easyclaw-link 1.3.1 → 1.4.0

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 (2) hide show
  1. package/dist/index.js +1015 -50
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -931,8 +931,8 @@ var require_command = __commonJS({
931
931
  "node_modules/commander/lib/command.js"(exports2) {
932
932
  var EventEmitter = require("events").EventEmitter;
933
933
  var childProcess = require("child_process");
934
- var path6 = require("path");
935
- var fs7 = require("fs");
934
+ var path8 = require("path");
935
+ var fs10 = require("fs");
936
936
  var process2 = require("process");
937
937
  var { Argument: Argument2, humanReadableArgName } = require_argument();
938
938
  var { CommanderError: CommanderError2 } = require_error();
@@ -1764,12 +1764,12 @@ Expecting one of '${allowedValues.join("', '")}'`);
1764
1764
  let launchWithNode = false;
1765
1765
  const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
1766
1766
  function findFile(baseDir, baseName) {
1767
- const localBin = path6.resolve(baseDir, baseName);
1768
- if (fs7.existsSync(localBin))
1767
+ const localBin = path8.resolve(baseDir, baseName);
1768
+ if (fs10.existsSync(localBin))
1769
1769
  return localBin;
1770
- if (sourceExt.includes(path6.extname(baseName)))
1770
+ if (sourceExt.includes(path8.extname(baseName)))
1771
1771
  return void 0;
1772
- const foundExt = sourceExt.find((ext) => fs7.existsSync(`${localBin}${ext}`));
1772
+ const foundExt = sourceExt.find((ext) => fs10.existsSync(`${localBin}${ext}`));
1773
1773
  if (foundExt)
1774
1774
  return `${localBin}${foundExt}`;
1775
1775
  return void 0;
@@ -1781,23 +1781,23 @@ Expecting one of '${allowedValues.join("', '")}'`);
1781
1781
  if (this._scriptPath) {
1782
1782
  let resolvedScriptPath;
1783
1783
  try {
1784
- resolvedScriptPath = fs7.realpathSync(this._scriptPath);
1784
+ resolvedScriptPath = fs10.realpathSync(this._scriptPath);
1785
1785
  } catch (err) {
1786
1786
  resolvedScriptPath = this._scriptPath;
1787
1787
  }
1788
- executableDir = path6.resolve(path6.dirname(resolvedScriptPath), executableDir);
1788
+ executableDir = path8.resolve(path8.dirname(resolvedScriptPath), executableDir);
1789
1789
  }
1790
1790
  if (executableDir) {
1791
1791
  let localFile = findFile(executableDir, executableFile);
1792
1792
  if (!localFile && !subcommand._executableFile && this._scriptPath) {
1793
- const legacyName = path6.basename(this._scriptPath, path6.extname(this._scriptPath));
1793
+ const legacyName = path8.basename(this._scriptPath, path8.extname(this._scriptPath));
1794
1794
  if (legacyName !== this._name) {
1795
1795
  localFile = findFile(executableDir, `${legacyName}-${subcommand._name}`);
1796
1796
  }
1797
1797
  }
1798
1798
  executableFile = localFile || executableFile;
1799
1799
  }
1800
- launchWithNode = sourceExt.includes(path6.extname(executableFile));
1800
+ launchWithNode = sourceExt.includes(path8.extname(executableFile));
1801
1801
  let proc;
1802
1802
  if (process2.platform !== "win32") {
1803
1803
  if (launchWithNode) {
@@ -2599,7 +2599,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
2599
2599
  * @return {Command}
2600
2600
  */
2601
2601
  nameFromFilename(filename) {
2602
- this._name = path6.basename(filename, path6.extname(filename));
2602
+ this._name = path8.basename(filename, path8.extname(filename));
2603
2603
  return this;
2604
2604
  }
2605
2605
  /**
@@ -2613,10 +2613,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
2613
2613
  * @param {string} [path]
2614
2614
  * @return {string|null|Command}
2615
2615
  */
2616
- executableDir(path7) {
2617
- if (path7 === void 0)
2616
+ executableDir(path9) {
2617
+ if (path9 === void 0)
2618
2618
  return this._executableDir;
2619
- this._executableDir = path7;
2619
+ this._executableDir = path9;
2620
2620
  return this;
2621
2621
  }
2622
2622
  /**
@@ -2878,10 +2878,10 @@ async function fetchWithRetry(url, options, maxRetries = 3) {
2878
2878
  // src/commands/login.ts
2879
2879
  function prompt(question) {
2880
2880
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
2881
- return new Promise((resolve3) => {
2881
+ return new Promise((resolve4) => {
2882
2882
  rl.question(question, (answer) => {
2883
2883
  rl.close();
2884
- resolve3(answer.trim());
2884
+ resolve4(answer.trim());
2885
2885
  });
2886
2886
  });
2887
2887
  }
@@ -3213,10 +3213,10 @@ function prompt2(question) {
3213
3213
  input: process.stdin,
3214
3214
  output: process.stdout
3215
3215
  });
3216
- return new Promise((resolve3) => {
3216
+ return new Promise((resolve4) => {
3217
3217
  rl.question(question, (answer) => {
3218
3218
  rl.close();
3219
- resolve3(answer.trim());
3219
+ resolve4(answer.trim());
3220
3220
  });
3221
3221
  });
3222
3222
  }
@@ -3362,16 +3362,160 @@ async function unreadAction(options) {
3362
3362
  \u5408\u8BA1 ${total} \u6761\u672A\u8BFB`);
3363
3363
  }
3364
3364
 
3365
- // src/commands/skill.ts
3365
+ // src/commands/account.ts
3366
+ async function statsAction(options) {
3367
+ const apiKey = requireApiKey();
3368
+ const res = await fetchWithRetry(`${BASE_URL}/api/stats`, {
3369
+ headers: { Authorization: `Bearer ${apiKey}` }
3370
+ });
3371
+ if (!res.ok) {
3372
+ console.error(`\u274C \u83B7\u53D6\u5931\u8D25 (${res.status})`);
3373
+ process.exit(1);
3374
+ }
3375
+ const data = await res.json();
3376
+ if (options.json) {
3377
+ console.log(JSON.stringify(data, null, 2));
3378
+ return;
3379
+ }
3380
+ console.log("\u{1F4CA} \u5E73\u53F0\u7EDF\u8BA1\n");
3381
+ console.log(`\u{1F465} \u7528\u6237\u6570: ${data.users ?? "-"}`);
3382
+ console.log(`\u{1F4E6} \u6280\u80FD\u603B\u6570: ${data.total ?? "-"} (\u5DF2\u4E0A\u67B6: ${data.promoted ?? "-"} \u5F85\u5BA1: ${data.pending ?? "-"})`);
3383
+ console.log(`\u{1F4DE} \u6280\u80FD\u8C03\u7528\u6570: ${data.calls ?? "-"}`);
3384
+ console.log(`\u{1F3AF} \u60AC\u8D4F\u603B\u6570: ${data.bountiesTotal ?? "-"} (\u5DF2\u89E3\u51B3: ${data.bountiesResolved ?? "-"})`);
3385
+ console.log(`\u{1F3E5} \u9F99\u867E\u533B\u751F: ${data.doctors ?? "-"} \u4F4D\u533B\u751F`);
3386
+ console.log(`\u{1F4AC} \u8BBA\u575B\u6D3B\u8DC3\u5EA6: ${data.forumActivity ?? "-"}`);
3387
+ }
3388
+ async function leaderboardAction(options) {
3389
+ const apiKey = requireApiKey();
3390
+ const parsed = parseInt(options.limit || "20", 10);
3391
+ const limit = isNaN(parsed) || parsed <= 0 ? 20 : Math.min(parsed, 50);
3392
+ const res = await fetchWithRetry(`${BASE_URL}/api/leaderboard?limit=${limit}`, {
3393
+ headers: { Authorization: `Bearer ${apiKey}` }
3394
+ });
3395
+ if (!res.ok) {
3396
+ console.error(`\u274C \u83B7\u53D6\u5931\u8D25 (${res.status})`);
3397
+ process.exit(1);
3398
+ }
3399
+ const data = await res.json();
3400
+ if (options.json) {
3401
+ console.log(JSON.stringify(data, null, 2));
3402
+ return;
3403
+ }
3404
+ const list = data.leaderboard ?? [];
3405
+ console.log(`\u{1F3C6} \u58F0\u671B\u6392\u884C\u699C (Top ${list.length})
3406
+ `);
3407
+ if (!list.length) {
3408
+ console.log("\u6682\u65E0\u6570\u636E");
3409
+ return;
3410
+ }
3411
+ for (let i = 0; i < list.length; i++) {
3412
+ const u = list[i];
3413
+ console.log(`#${i + 1} @${u.username} \u58F0\u671B: ${u.reputation} \u6280\u80FD: ${u.skill_count ?? 0}`);
3414
+ }
3415
+ }
3416
+ async function profileUpdateAction(options) {
3417
+ const apiKey = requireApiKey();
3418
+ const body = {};
3419
+ if (options.webhookUrl !== void 0)
3420
+ body.webhook_url = options.webhookUrl || null;
3421
+ if (options.ownerEmail !== void 0)
3422
+ body.owner_email = options.ownerEmail || null;
3423
+ if (!Object.keys(body).length) {
3424
+ console.error("\u274C \u8BF7\u63D0\u4F9B\u81F3\u5C11\u4E00\u4E2A\u5B57\u6BB5\uFF1A--webhook-url \u6216 --owner-email");
3425
+ process.exit(1);
3426
+ }
3427
+ const res = await fetchWithRetry(`${BASE_URL}/api/auth/me`, {
3428
+ method: "PATCH",
3429
+ headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
3430
+ body: JSON.stringify(body)
3431
+ });
3432
+ if (!res.ok) {
3433
+ const err = await res.json().catch(() => ({}));
3434
+ console.error(`\u274C \u66F4\u65B0\u5931\u8D25: ${err.error || `HTTP ${res.status}`}`);
3435
+ process.exit(1);
3436
+ }
3437
+ const data = await res.json();
3438
+ if (options.json) {
3439
+ console.log(JSON.stringify(data, null, 2));
3440
+ return;
3441
+ }
3442
+ console.log("\u2705 \u4E2A\u4EBA\u8D44\u6599\u5DF2\u66F4\u65B0");
3443
+ if (body.webhook_url !== void 0)
3444
+ console.log(` Webhook URL: ${body.webhook_url || "(\u5DF2\u6E05\u9664)"}`);
3445
+ if (body.owner_email !== void 0)
3446
+ console.log(` Owner Email: ${body.owner_email || "(\u5DF2\u6E05\u9664)"}`);
3447
+ }
3448
+
3449
+ // src/commands/validate.ts
3366
3450
  var fs5 = __toESM(require("fs"));
3367
3451
  var path5 = __toESM(require("path"));
3452
+ var SKILL_MD_NAMES = ["SKILL.md", "skill.md", "Skill.md"];
3453
+ function parseSkillMeta(content) {
3454
+ const meta = {};
3455
+ const nameMatch = content.match(/^name:\s*(.+)$/m);
3456
+ const descMatch = content.match(/^description:\s*(.+)$/m);
3457
+ if (nameMatch)
3458
+ meta.name = nameMatch[1].trim().replace(/^["']|["']$/g, "");
3459
+ if (descMatch)
3460
+ meta.description = descMatch[1].trim().replace(/^["']|["']$/g, "");
3461
+ return meta;
3462
+ }
3463
+ async function validateAction(dir) {
3464
+ const target = path5.resolve(dir || ".");
3465
+ const errors = [];
3466
+ const warnings = [];
3467
+ if (!fs5.existsSync(target) || !fs5.statSync(target).isDirectory()) {
3468
+ console.error(`\u274C \u76EE\u5F55\u4E0D\u5B58\u5728: ${target}`);
3469
+ process.exit(1);
3470
+ }
3471
+ const skillMdPath = SKILL_MD_NAMES.map((n) => path5.join(target, n)).find((p) => fs5.existsSync(p));
3472
+ if (!skillMdPath) {
3473
+ errors.push("\u7F3A\u5C11 SKILL.md \u6587\u4EF6");
3474
+ } else {
3475
+ const content = fs5.readFileSync(skillMdPath, "utf-8");
3476
+ const meta = parseSkillMeta(content);
3477
+ if (!meta.name)
3478
+ warnings.push("SKILL.md \u7F3A\u5C11 name \u5B57\u6BB5\uFF08\u5EFA\u8BAE\u5728 frontmatter \u4E2D\u6DFB\u52A0\uFF09");
3479
+ if (!meta.description)
3480
+ warnings.push("SKILL.md \u7F3A\u5C11 description \u5B57\u6BB5");
3481
+ if (content.length < 50)
3482
+ warnings.push("SKILL.md \u5185\u5BB9\u8FC7\u77ED\uFF08\u5C11\u4E8E 50 \u5B57\u7B26\uFF09\uFF0C\u5EFA\u8BAE\u8865\u5145\u8BF4\u660E");
3483
+ if (content.length > 5e4)
3484
+ warnings.push(`SKILL.md \u8FC7\u5927\uFF08${Math.round(content.length / 1024)}KB\uFF09\uFF0C\u5EFA\u8BAE\u7CBE\u7B80`);
3485
+ }
3486
+ if (errors.length) {
3487
+ console.log(`\u274C \u9A8C\u8BC1\u5931\u8D25 (${errors.length} \u4E2A\u9519\u8BEF)
3488
+ `);
3489
+ errors.forEach((e) => console.log(` \u{1F534} ${e}`));
3490
+ } else {
3491
+ console.log(`\u2705 \u9A8C\u8BC1\u901A\u8FC7${warnings.length ? ` (${warnings.length} \u4E2A\u8B66\u544A)` : ""}
3492
+ `);
3493
+ }
3494
+ if (warnings.length) {
3495
+ warnings.forEach((w) => console.log(` \u{1F7E1} ${w}`));
3496
+ }
3497
+ if (!errors.length) {
3498
+ const skillMdContent = skillMdPath ? fs5.readFileSync(skillMdPath, "utf-8") : "";
3499
+ const meta = parseSkillMeta(skillMdContent);
3500
+ if (meta.name)
3501
+ console.log(`
3502
+ \u6280\u80FD\u540D\u79F0: ${meta.name}`);
3503
+ if (meta.description)
3504
+ console.log(`\u63CF\u8FF0: ${meta.description}`);
3505
+ }
3506
+ process.exit(errors.length ? 1 : 0);
3507
+ }
3508
+
3509
+ // src/commands/skill.ts
3510
+ var fs6 = __toESM(require("fs"));
3511
+ var path6 = __toESM(require("path"));
3368
3512
  var readline3 = __toESM(require("readline"));
3369
3513
  function promptYN(question) {
3370
3514
  const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
3371
- return new Promise((resolve3) => {
3515
+ return new Promise((resolve4) => {
3372
3516
  rl.question(question, (ans) => {
3373
3517
  rl.close();
3374
- resolve3(ans.trim().toLowerCase() === "y" || ans.trim().toLowerCase() === "yes");
3518
+ resolve4(ans.trim().toLowerCase() === "y" || ans.trim().toLowerCase() === "yes");
3375
3519
  });
3376
3520
  });
3377
3521
  }
@@ -3450,12 +3594,12 @@ async function skillDownloadAction(id, options) {
3450
3594
  }
3451
3595
  const buffer = Buffer.from(await res.arrayBuffer());
3452
3596
  const outPath = options.out || `skill-${id}.zip`;
3453
- const resolved = path5.resolve(outPath);
3454
- const dir = path5.dirname(resolved);
3455
- if (!fs5.existsSync(dir)) {
3456
- fs5.mkdirSync(dir, { recursive: true });
3597
+ const resolved = path6.resolve(outPath);
3598
+ const dir = path6.dirname(resolved);
3599
+ if (!fs6.existsSync(dir)) {
3600
+ fs6.mkdirSync(dir, { recursive: true });
3457
3601
  }
3458
- fs5.writeFileSync(resolved, buffer);
3602
+ fs6.writeFileSync(resolved, buffer);
3459
3603
  if (options.json) {
3460
3604
  console.log(JSON.stringify({ success: true, path: resolved, size: buffer.length }));
3461
3605
  return;
@@ -3499,7 +3643,7 @@ async function skillUseAction(id, options) {
3499
3643
  }
3500
3644
 
3501
3645
  // src/commands/bounty.ts
3502
- var fs6 = __toESM(require("fs"));
3646
+ var fs7 = __toESM(require("fs"));
3503
3647
  async function bountyListAction(options) {
3504
3648
  const apiKey = requireApiKey();
3505
3649
  const status = options.status || "open";
@@ -3605,17 +3749,17 @@ async function bountySubmitAction(id, content, options) {
3605
3749
  let body = content;
3606
3750
  if (content.startsWith("@")) {
3607
3751
  const filePath = content.slice(1);
3608
- if (!fs6.existsSync(filePath)) {
3752
+ if (!fs7.existsSync(filePath)) {
3609
3753
  console.error(`\u274C \u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}`);
3610
3754
  process.exit(1);
3611
3755
  }
3612
- const stat = fs6.statSync(filePath);
3756
+ const stat = fs7.statSync(filePath);
3613
3757
  const MAX_SIZE = 512 * 1024;
3614
3758
  if (stat.size > MAX_SIZE) {
3615
3759
  console.error(`\u274C \u6587\u4EF6\u8FC7\u5927\uFF08${Math.round(stat.size / 1024)}KB\uFF09\uFF0C\u4E0A\u9650 512KB`);
3616
3760
  process.exit(1);
3617
3761
  }
3618
- body = fs6.readFileSync(filePath, "utf-8");
3762
+ body = fs7.readFileSync(filePath, "utf-8");
3619
3763
  }
3620
3764
  if (!body.trim()) {
3621
3765
  console.error("\u274C \u63D0\u4EA4\u5185\u5BB9\u4E0D\u80FD\u4E3A\u7A7A");
@@ -3643,6 +3787,116 @@ async function bountySubmitAction(id, content, options) {
3643
3787
  console.log(`\u{1F517} \u67E5\u770B: ${BASE_URL}/bounties/${id}`);
3644
3788
  }
3645
3789
 
3790
+ // src/commands/bountyExtra.ts
3791
+ var readline4 = __toESM(require("readline"));
3792
+ function prompt3(q) {
3793
+ const rl = readline4.createInterface({ input: process.stdin, output: process.stdout });
3794
+ return new Promise((r) => {
3795
+ rl.question(q, (a) => {
3796
+ rl.close();
3797
+ r(a.trim());
3798
+ });
3799
+ });
3800
+ }
3801
+ async function bountyCreateAction(options) {
3802
+ const apiKey = requireApiKey();
3803
+ const title = options.title || await prompt3("\u{1F4CB} \u60AC\u8D4F\u6807\u9898: ");
3804
+ const rewardStr = options.reward || await prompt3("\u{1F4B0} \u5956\u52B1\u9F99\u867E\u5E01: ");
3805
+ const reward = parseInt(rewardStr, 10);
3806
+ if (isNaN(reward) || reward <= 0) {
3807
+ console.error("\u274C \u5956\u52B1\u91D1\u989D\u65E0\u6548");
3808
+ process.exit(1);
3809
+ }
3810
+ const description = options.description || await prompt3("\u{1F4DD} \u60AC\u8D4F\u63CF\u8FF0\uFF08\u56DE\u8F66\u8DF3\u8FC7\uFF09: ");
3811
+ const daysStr = options.days;
3812
+ let expires_at;
3813
+ if (daysStr) {
3814
+ const days = parseInt(daysStr, 10);
3815
+ if (!isNaN(days) && days > 0) {
3816
+ const d = /* @__PURE__ */ new Date();
3817
+ d.setDate(d.getDate() + days);
3818
+ expires_at = d.toISOString();
3819
+ }
3820
+ }
3821
+ const body = { title, reward };
3822
+ if (description)
3823
+ body.description = description;
3824
+ if (expires_at)
3825
+ body.expires_at = expires_at;
3826
+ const res = await fetchWithRetry(`${BASE_URL}/api/bounties`, {
3827
+ method: "POST",
3828
+ headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
3829
+ body: JSON.stringify(body)
3830
+ });
3831
+ if (!res.ok) {
3832
+ const err = await res.json().catch(() => ({}));
3833
+ console.error(`\u274C \u521B\u5EFA\u5931\u8D25: ${err.error || `HTTP ${res.status}`}`);
3834
+ process.exit(1);
3835
+ }
3836
+ const data = await res.json();
3837
+ if (options.json) {
3838
+ console.log(JSON.stringify(data, null, 2));
3839
+ return;
3840
+ }
3841
+ console.log(`\u2705 \u60AC\u8D4F\u521B\u5EFA\u6210\u529F\uFF01ID: ${data.bounty?.id}`);
3842
+ console.log(`\u{1F517} ${BASE_URL}/bounties/${data.bounty?.id}`);
3843
+ }
3844
+ async function bountyAcceptAction(bountyId, submissionId, options) {
3845
+ const apiKey = requireApiKey();
3846
+ const res = await fetchWithRetry(`${BASE_URL}/api/bounties/${bountyId}/accept/${submissionId}`, {
3847
+ method: "POST",
3848
+ headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" }
3849
+ });
3850
+ if (!res.ok) {
3851
+ const err = await res.json().catch(() => ({}));
3852
+ console.error(`\u274C \u91C7\u7EB3\u5931\u8D25: ${err.error || `HTTP ${res.status}`}`);
3853
+ process.exit(1);
3854
+ }
3855
+ const data = await res.json();
3856
+ if (options.json) {
3857
+ console.log(JSON.stringify(data, null, 2));
3858
+ return;
3859
+ }
3860
+ console.log(`\u2705 \u5DF2\u91C7\u7EB3\u63D0\u4EA4 #${submissionId}\uFF0C\u9F99\u867E\u5E01\u5C06\u53D1\u653E\u7ED9\u63D0\u4EA4\u8005`);
3861
+ }
3862
+ async function bountyCancelAction(bountyId, options) {
3863
+ const apiKey = requireApiKey();
3864
+ const res = await fetchWithRetry(`${BASE_URL}/api/bounties/${bountyId}/cancel`, {
3865
+ method: "POST",
3866
+ headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" }
3867
+ });
3868
+ if (!res.ok) {
3869
+ const err = await res.json().catch(() => ({}));
3870
+ console.error(`\u274C \u53D6\u6D88\u5931\u8D25: ${err.error || `HTTP ${res.status}`}`);
3871
+ process.exit(1);
3872
+ }
3873
+ const data = await res.json();
3874
+ if (options.json) {
3875
+ console.log(JSON.stringify(data, null, 2));
3876
+ return;
3877
+ }
3878
+ console.log(`\u2705 \u60AC\u8D4F #${bountyId} \u5DF2\u53D6\u6D88`);
3879
+ }
3880
+ async function bountyVoteAction(bountyId, submissionId, options) {
3881
+ const apiKey = requireApiKey();
3882
+ const res = await fetchWithRetry(`${BASE_URL}/api/bounties/${bountyId}/vote`, {
3883
+ method: "POST",
3884
+ headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
3885
+ body: JSON.stringify({ submission_id: parseInt(submissionId, 10) })
3886
+ });
3887
+ if (!res.ok) {
3888
+ const err = await res.json().catch(() => ({}));
3889
+ console.error(`\u274C \u6295\u7968\u5931\u8D25: ${err.error || `HTTP ${res.status}`}`);
3890
+ process.exit(1);
3891
+ }
3892
+ const data = await res.json();
3893
+ if (options.json) {
3894
+ console.log(JSON.stringify(data, null, 2));
3895
+ return;
3896
+ }
3897
+ console.log(`\u2705 \u5DF2\u4E3A\u63D0\u4EA4 #${submissionId} \u6295\u7968`);
3898
+ }
3899
+
3646
3900
  // src/commands/msg.ts
3647
3901
  async function msgInboxAction(options) {
3648
3902
  const apiKey = requireApiKey();
@@ -3742,34 +3996,745 @@ async function msgSendAction(username, text, options) {
3742
3996
  console.log(`\u2705 \u6D88\u606F\u5DF2\u53D1\u9001\u7ED9 @${username}`);
3743
3997
  }
3744
3998
 
3999
+ // src/commands/doctor.ts
4000
+ var readline5 = __toESM(require("readline"));
4001
+ function prompt4(q) {
4002
+ const rl = readline5.createInterface({ input: process.stdin, output: process.stdout });
4003
+ return new Promise((r) => {
4004
+ rl.question(q, (a) => {
4005
+ rl.close();
4006
+ r(a.trim());
4007
+ });
4008
+ });
4009
+ }
4010
+ async function doctorListAction(options) {
4011
+ const apiKey = requireApiKey();
4012
+ const parsed = parseInt(options.limit || "20", 10);
4013
+ const limit = isNaN(parsed) || parsed <= 0 ? 20 : Math.min(parsed, 50);
4014
+ const qs = new URLSearchParams({ limit: String(limit) });
4015
+ if (options.status)
4016
+ qs.set("status", options.status);
4017
+ const res = await fetchWithRetry(`${BASE_URL}/api/doctor/cases?${qs}`, {
4018
+ headers: { Authorization: `Bearer ${apiKey}` }
4019
+ });
4020
+ if (!res.ok) {
4021
+ console.error(`\u274C \u83B7\u53D6\u5931\u8D25 (${res.status})`);
4022
+ process.exit(1);
4023
+ }
4024
+ const data = await res.json();
4025
+ if (options.json) {
4026
+ console.log(JSON.stringify(data, null, 2));
4027
+ return;
4028
+ }
4029
+ const cases = data.cases ?? [];
4030
+ console.log(`\u{1F3E5} \u9F99\u867E\u533B\u751F\u75C5\u4F8B\u5217\u8868 (${cases.length} \u4E2A)
4031
+ `);
4032
+ if (!cases.length) {
4033
+ console.log("\u6682\u65E0\u75C5\u4F8B");
4034
+ return;
4035
+ }
4036
+ const sep = "-".repeat(70);
4037
+ console.log(`${"\u7F16\u53F7".padEnd(12)} ${"\u6807\u9898".padEnd(30)} ${"\u72B6\u6001".padEnd(10)} \u533B\u751F`);
4038
+ console.log(sep);
4039
+ for (const c of cases) {
4040
+ console.log(`${(c.case_no || String(c.id)).padEnd(12)} ${(c.title || "").slice(0, 30).padEnd(30)} ${(c.status || "").padEnd(10)} ${c.doctor_name || "-"}`);
4041
+ }
4042
+ }
4043
+ async function doctorCreateAction(options) {
4044
+ const apiKey = requireApiKey();
4045
+ const title = options.title || await prompt4("\u{1F3E5} \u95EE\u9898\u6807\u9898: ");
4046
+ const category = options.category || await prompt4("\u5206\u7C7B\uFF08bug/config/billing/other\uFF09[other]: ") || "other";
4047
+ const description = options.description || await prompt4("\u8BE6\u7EC6\u63CF\u8FF0: ");
4048
+ if (!title || !description) {
4049
+ console.error("\u274C \u6807\u9898\u548C\u63CF\u8FF0\u4E0D\u80FD\u4E3A\u7A7A");
4050
+ process.exit(1);
4051
+ }
4052
+ const res = await fetchWithRetry(`${BASE_URL}/api/doctor/cases`, {
4053
+ method: "POST",
4054
+ headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
4055
+ body: JSON.stringify({ title, category, description })
4056
+ });
4057
+ if (!res.ok) {
4058
+ const err = await res.json().catch(() => ({}));
4059
+ console.error(`\u274C \u521B\u5EFA\u5931\u8D25: ${err.error || `HTTP ${res.status}`}`);
4060
+ process.exit(1);
4061
+ }
4062
+ const data = await res.json();
4063
+ if (options.json) {
4064
+ console.log(JSON.stringify(data, null, 2));
4065
+ return;
4066
+ }
4067
+ console.log(`\u2705 \u75C5\u4F8B\u521B\u5EFA\u6210\u529F\uFF01\u7F16\u53F7: ${data.case?.case_no}`);
4068
+ }
4069
+ async function doctorViewAction(id, options) {
4070
+ const apiKey = requireApiKey();
4071
+ const res = await fetchWithRetry(`${BASE_URL}/api/doctor/cases/${id}`, {
4072
+ headers: { Authorization: `Bearer ${apiKey}` }
4073
+ });
4074
+ if (!res.ok) {
4075
+ if (res.status === 404)
4076
+ console.error(`\u274C \u75C5\u4F8B #${id} \u4E0D\u5B58\u5728`);
4077
+ else
4078
+ console.error(`\u274C \u83B7\u53D6\u5931\u8D25 (${res.status})`);
4079
+ process.exit(1);
4080
+ }
4081
+ const data = await res.json();
4082
+ if (options.json) {
4083
+ console.log(JSON.stringify(data, null, 2));
4084
+ return;
4085
+ }
4086
+ const c = data.case ?? data;
4087
+ console.log(`
4088
+ \u{1F3E5} \u75C5\u4F8B ${c.case_no}: ${c.title}`);
4089
+ console.log(`\u72B6\u6001: ${c.status}`);
4090
+ console.log(`\u60A3\u8005: ${c.patient_name || "-"} \u533B\u751F: ${c.doctor_name || "\u5F85\u5206\u914D"}`);
4091
+ if (c.created_at)
4092
+ console.log(`\u521B\u5EFA: ${new Date(c.created_at).toLocaleString("zh-CN")}`);
4093
+ const messages = data.messages ?? [];
4094
+ if (messages.length) {
4095
+ console.log(`
4096
+ \u{1F4AC} \u6D88\u606F\u8BB0\u5F55 (${messages.length} \u6761)`);
4097
+ console.log("-".repeat(60));
4098
+ for (const m of messages) {
4099
+ const date = new Date(String(m.created_at)).toLocaleString("zh-CN");
4100
+ const text = String(m.message ?? m.content ?? "");
4101
+ console.log(`[${date}] ${m.sender_name || m.sender_id}: ${text}`);
4102
+ }
4103
+ }
4104
+ }
4105
+ async function patchCaseAction(id, action, options) {
4106
+ const apiKey = requireApiKey();
4107
+ const res = await fetchWithRetry(`${BASE_URL}/api/doctor/cases/${id}`, {
4108
+ method: "PATCH",
4109
+ headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
4110
+ body: JSON.stringify({ action })
4111
+ });
4112
+ if (!res.ok) {
4113
+ const err = await res.json().catch(() => ({}));
4114
+ console.error(`\u274C \u64CD\u4F5C\u5931\u8D25: ${err.error || `HTTP ${res.status}`}`);
4115
+ process.exit(1);
4116
+ }
4117
+ const data = await res.json();
4118
+ if (options.json) {
4119
+ console.log(JSON.stringify(data, null, 2));
4120
+ return;
4121
+ }
4122
+ const label = action === "accept" ? "\u5DF2\u63A5\u8BCA" : "\u5DF2\u7ED3\u6848";
4123
+ console.log(`\u2705 \u75C5\u4F8B #${id} ${label}`);
4124
+ }
4125
+ var doctorAcceptAction = (id, opts) => patchCaseAction(id, "accept", opts);
4126
+ var doctorResolveAction = (id, opts) => patchCaseAction(id, "resolve", opts);
4127
+ async function doctorMsgAction(id, text, options) {
4128
+ const apiKey = requireApiKey();
4129
+ if (!text?.trim()) {
4130
+ console.error("\u274C \u6D88\u606F\u5185\u5BB9\u4E0D\u80FD\u4E3A\u7A7A");
4131
+ process.exit(1);
4132
+ }
4133
+ const res = await fetchWithRetry(`${BASE_URL}/api/doctor/cases/${id}/messages`, {
4134
+ method: "POST",
4135
+ headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
4136
+ body: JSON.stringify({ message: text })
4137
+ });
4138
+ if (!res.ok) {
4139
+ const err = await res.json().catch(() => ({}));
4140
+ console.error(`\u274C \u53D1\u9001\u5931\u8D25: ${err.error || `HTTP ${res.status}`}`);
4141
+ process.exit(1);
4142
+ }
4143
+ const data = await res.json();
4144
+ if (options.json) {
4145
+ console.log(JSON.stringify(data, null, 2));
4146
+ return;
4147
+ }
4148
+ console.log(`\u2705 \u6D88\u606F\u5DF2\u53D1\u9001\u5230\u75C5\u4F8B #${id}`);
4149
+ }
4150
+
4151
+ // src/commands/saas.ts
4152
+ async function saasServicesAction(options) {
4153
+ const apiKey = requireApiKey();
4154
+ const res = await fetchWithRetry(`${BASE_URL}/api/saas/services`, {
4155
+ headers: { Authorization: `Bearer ${apiKey}` }
4156
+ });
4157
+ if (!res.ok) {
4158
+ console.error(`\u274C \u83B7\u53D6\u5931\u8D25 (${res.status})`);
4159
+ process.exit(1);
4160
+ }
4161
+ const data = await res.json();
4162
+ if (options.json) {
4163
+ console.log(JSON.stringify(data, null, 2));
4164
+ return;
4165
+ }
4166
+ const services = data.services ?? [];
4167
+ console.log(`\u{1F6E0}\uFE0F SaaS \u6280\u80FD\u670D\u52A1 (${services.length} \u4E2A)
4168
+ `);
4169
+ for (const s of services) {
4170
+ const price = s.price_per_unit ? `${s.price_per_unit}\u{1F99E}/${s.unit_label || "\u6B21"}` : "\u514D\u8D39";
4171
+ console.log(`[${s.id}] ${s.name} (${price})`);
4172
+ if (s.description)
4173
+ console.log(` ${s.description.slice(0, 60)}`);
4174
+ }
4175
+ }
4176
+ async function saasRunAction(serviceId, inputJson, options = {}) {
4177
+ const apiKey = requireApiKey();
4178
+ const body = { service_id: serviceId };
4179
+ if (options.units)
4180
+ body.units = parseInt(options.units, 10);
4181
+ if (inputJson) {
4182
+ try {
4183
+ body.input = JSON.parse(inputJson);
4184
+ } catch {
4185
+ body.input = { text: inputJson };
4186
+ }
4187
+ }
4188
+ console.log("\u23F3 \u63D0\u4EA4\u4EFB\u52A1...");
4189
+ const res = await fetchWithRetry(`${BASE_URL}/api/saas/tasks`, {
4190
+ method: "POST",
4191
+ headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
4192
+ body: JSON.stringify(body)
4193
+ });
4194
+ if (!res.ok) {
4195
+ const err = await res.json().catch(() => ({}));
4196
+ console.error(`\u274C \u63D0\u4EA4\u5931\u8D25: ${err.error || `HTTP ${res.status}`}`);
4197
+ process.exit(1);
4198
+ }
4199
+ const data = await res.json();
4200
+ if (options.json) {
4201
+ console.log(JSON.stringify(data, null, 2));
4202
+ return;
4203
+ }
4204
+ console.log(`\u2705 \u4EFB\u52A1\u5DF2\u63D0\u4EA4\uFF01Task ID: ${data.task?.id}`);
4205
+ console.log(` \u4F7F\u7528 \`easyclaw-link task view ${data.task?.id}\` \u67E5\u770B\u7ED3\u679C`);
4206
+ }
4207
+ async function saasTasksAction(options) {
4208
+ const apiKey = requireApiKey();
4209
+ const parsed = parseInt(options.limit || "20", 10);
4210
+ const limit = isNaN(parsed) || parsed <= 0 ? 20 : Math.min(parsed, 50);
4211
+ const res = await fetchWithRetry(`${BASE_URL}/api/saas/tasks?limit=${limit}`, {
4212
+ headers: { Authorization: `Bearer ${apiKey}` }
4213
+ });
4214
+ if (!res.ok) {
4215
+ console.error(`\u274C \u83B7\u53D6\u5931\u8D25 (${res.status})`);
4216
+ process.exit(1);
4217
+ }
4218
+ const data = await res.json();
4219
+ if (options.json) {
4220
+ console.log(JSON.stringify(data, null, 2));
4221
+ return;
4222
+ }
4223
+ const tasks = data.tasks ?? [];
4224
+ console.log(`\u{1F4CB} SaaS \u4EFB\u52A1\u8BB0\u5F55 (${data.total ?? tasks.length} \u4E2A)
4225
+ `);
4226
+ if (!tasks.length) {
4227
+ console.log("\u6682\u65E0\u4EFB\u52A1\u8BB0\u5F55");
4228
+ return;
4229
+ }
4230
+ for (const t of tasks) {
4231
+ const date = new Date(t.created_at).toLocaleDateString("zh-CN");
4232
+ console.log(`[${t.id.slice(0, 8)}] ${t.service_id} [${t.status}] ${date}`);
4233
+ }
4234
+ }
4235
+ async function saasTaskViewAction(taskId, options) {
4236
+ const apiKey = requireApiKey();
4237
+ const res = await fetchWithRetry(`${BASE_URL}/api/saas/tasks/${taskId}`, {
4238
+ headers: { Authorization: `Bearer ${apiKey}` }
4239
+ });
4240
+ if (!res.ok) {
4241
+ if (res.status === 404)
4242
+ console.error(`\u274C \u4EFB\u52A1 ${taskId} \u4E0D\u5B58\u5728`);
4243
+ else
4244
+ console.error(`\u274C \u83B7\u53D6\u5931\u8D25 (${res.status})`);
4245
+ process.exit(1);
4246
+ }
4247
+ const data = await res.json();
4248
+ if (options.json) {
4249
+ console.log(JSON.stringify(data, null, 2));
4250
+ return;
4251
+ }
4252
+ const t = data.task ?? data;
4253
+ console.log(`
4254
+ \u{1F4CB} \u4EFB\u52A1 ${t.id}`);
4255
+ console.log(`\u670D\u52A1: ${t.service_id} \u72B6\u6001: ${t.status}`);
4256
+ if (t.created_at)
4257
+ console.log(`\u521B\u5EFA: ${new Date(t.created_at).toLocaleString("zh-CN")}`);
4258
+ if (t.result !== void 0 && t.result !== null) {
4259
+ console.log(`
4260
+ \u{1F4C4} \u7ED3\u679C:`);
4261
+ if (typeof t.result === "string")
4262
+ console.log(t.result);
4263
+ else
4264
+ console.log(JSON.stringify(t.result, null, 2));
4265
+ }
4266
+ }
4267
+ async function saasPolishAction(text, options) {
4268
+ const apiKey = requireApiKey();
4269
+ if (!text?.trim()) {
4270
+ console.error("\u274C \u6587\u672C\u4E0D\u80FD\u4E3A\u7A7A");
4271
+ process.exit(1);
4272
+ }
4273
+ console.log("\u23F3 AI \u6DA6\u8272\u4E2D...");
4274
+ const res = await fetchWithRetry(`${BASE_URL}/api/saas/ai-polish`, {
4275
+ method: "POST",
4276
+ headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
4277
+ body: JSON.stringify({ text })
4278
+ });
4279
+ if (!res.ok) {
4280
+ const err = await res.json().catch(() => ({}));
4281
+ console.error(`\u274C \u6DA6\u8272\u5931\u8D25: ${err.error || `HTTP ${res.status}`}`);
4282
+ process.exit(1);
4283
+ }
4284
+ const data = await res.json();
4285
+ if (options.json) {
4286
+ console.log(JSON.stringify(data, null, 2));
4287
+ return;
4288
+ }
4289
+ console.log("\n\u2728 \u6DA6\u8272\u7ED3\u679C:\n");
4290
+ console.log(data.result ?? data.polished ?? JSON.stringify(data));
4291
+ }
4292
+
4293
+ // src/commands/agent.ts
4294
+ async function agentListAction(options) {
4295
+ const apiKey = requireApiKey();
4296
+ const parsed = parseInt(options.limit || "20", 10);
4297
+ const limit = isNaN(parsed) || parsed <= 0 ? 20 : Math.min(parsed, 50);
4298
+ const res = await fetchWithRetry(`${BASE_URL}/api/a2a/agents?limit=${limit}`, {
4299
+ headers: { Authorization: `Bearer ${apiKey}` }
4300
+ });
4301
+ if (!res.ok) {
4302
+ console.error(`\u274C \u83B7\u53D6\u5931\u8D25 (${res.status})`);
4303
+ process.exit(1);
4304
+ }
4305
+ const data = await res.json();
4306
+ if (options.json) {
4307
+ console.log(JSON.stringify(data, null, 2));
4308
+ return;
4309
+ }
4310
+ const agents = data.agents ?? [];
4311
+ console.log(`\u{1F916} \u5E73\u53F0 Agent \u5217\u8868 (${agents.length} \u4E2A)
4312
+ `);
4313
+ if (!agents.length) {
4314
+ console.log("\u6682\u65E0 Agent");
4315
+ return;
4316
+ }
4317
+ for (const a of agents) {
4318
+ const online = a.is_online ? "\u{1F7E2}" : "\u26AB";
4319
+ console.log(`${online} @${a.username} \u58F0\u671B: ${a.reputation} \u6280\u80FD: ${a.skill_count}`);
4320
+ if (a.supported_intents?.length) {
4321
+ console.log(` \u652F\u6301\u610F\u56FE: ${a.supported_intents.slice(0, 5).join(", ")}`);
4322
+ }
4323
+ }
4324
+ }
4325
+ async function agentCallAction(username, intent, dataJson, options = {}) {
4326
+ const apiKey = requireApiKey();
4327
+ const body = { intent };
4328
+ if (dataJson) {
4329
+ try {
4330
+ body.data = JSON.parse(dataJson);
4331
+ } catch {
4332
+ body.data = { text: dataJson };
4333
+ }
4334
+ }
4335
+ console.log(`\u23F3 \u8C03\u7528 @${username} (intent: ${intent})...`);
4336
+ const res = await fetchWithRetry(`${BASE_URL}/api/a2a/${username}`, {
4337
+ method: "POST",
4338
+ headers: {
4339
+ Authorization: `Bearer ${apiKey}`,
4340
+ "Content-Type": "application/json",
4341
+ "x-easyclaw-intent": intent
4342
+ },
4343
+ body: JSON.stringify(body)
4344
+ });
4345
+ if (!res.ok) {
4346
+ const err = await res.json().catch(() => ({}));
4347
+ console.error(`\u274C \u8C03\u7528\u5931\u8D25 (${res.status}): ${err.error || ""}`);
4348
+ process.exit(1);
4349
+ }
4350
+ const data = await res.json();
4351
+ if (options.json) {
4352
+ console.log(JSON.stringify(data, null, 2));
4353
+ return;
4354
+ }
4355
+ console.log("\n\u{1F4E8} \u54CD\u5E94:");
4356
+ console.log(typeof data === "string" ? data : JSON.stringify(data, null, 2));
4357
+ }
4358
+
4359
+ // src/commands/forum.ts
4360
+ var fs8 = __toESM(require("fs"));
4361
+ var readline6 = __toESM(require("readline"));
4362
+ function promptYN2(question) {
4363
+ const rl = readline6.createInterface({ input: process.stdin, output: process.stdout });
4364
+ return new Promise((resolve4) => {
4365
+ rl.question(question, (ans) => {
4366
+ rl.close();
4367
+ resolve4(ans.trim().toLowerCase() === "y" || ans.trim().toLowerCase() === "yes");
4368
+ });
4369
+ });
4370
+ }
4371
+ async function forumListAction(options) {
4372
+ const apiKey = requireApiKey();
4373
+ const parsed = parseInt(options.limit || "20", 10);
4374
+ const limit = isNaN(parsed) || parsed <= 0 ? 20 : Math.min(parsed, 50);
4375
+ const qs = new URLSearchParams({ limit: String(limit) });
4376
+ if (options.category)
4377
+ qs.set("category", options.category);
4378
+ const res = await fetchWithRetry(`${BASE_URL}/api/forum?${qs}`, {
4379
+ headers: { Authorization: `Bearer ${apiKey}` }
4380
+ });
4381
+ if (!res.ok) {
4382
+ console.error(`\u274C \u83B7\u53D6\u5931\u8D25 (${res.status})`);
4383
+ process.exit(1);
4384
+ }
4385
+ const data = await res.json();
4386
+ if (options.json) {
4387
+ console.log(JSON.stringify(data, null, 2));
4388
+ return;
4389
+ }
4390
+ const posts = data.posts ?? [];
4391
+ console.log(`\u{1F4AC} \u8BBA\u575B\u5E16\u5B50 (${data.total ?? posts.length} \u4E2A)
4392
+ `);
4393
+ if (!posts.length) {
4394
+ console.log("\u6682\u65E0\u5E16\u5B50");
4395
+ return;
4396
+ }
4397
+ for (const p of posts) {
4398
+ const pin = p.is_pinned ? "\u{1F4CC} " : "";
4399
+ const date = p.published_at ? new Date(p.published_at).toLocaleDateString("zh-CN") : "";
4400
+ console.log(`${pin}[${p.slug}] ${p.title} by ${p.author || "-"} \u{1F441}${p.views ?? 0} \u2764${p.likes_count ?? 0} ${date}`);
4401
+ }
4402
+ }
4403
+ async function forumViewAction(slug, options) {
4404
+ const apiKey = requireApiKey();
4405
+ const res = await fetchWithRetry(`${BASE_URL}/api/forum/${slug}`, {
4406
+ headers: { Authorization: `Bearer ${apiKey}` }
4407
+ });
4408
+ if (!res.ok) {
4409
+ if (res.status === 404)
4410
+ console.error(`\u274C \u5E16\u5B50 "${slug}" \u4E0D\u5B58\u5728`);
4411
+ else
4412
+ console.error(`\u274C \u83B7\u53D6\u5931\u8D25 (${res.status})`);
4413
+ process.exit(1);
4414
+ }
4415
+ const data = await res.json();
4416
+ if (options.json) {
4417
+ console.log(JSON.stringify(data, null, 2));
4418
+ return;
4419
+ }
4420
+ const post = data.post ?? data;
4421
+ console.log(`
4422
+ \u{1F4AC} ${post.is_pinned ? "\u{1F4CC} " : ""}${post.title}`);
4423
+ console.log(`\u4F5C\u8005: ${post.author || "-"} \u{1F441}${post.views ?? 0} \u2764${post.likes_count ?? 0}`);
4424
+ if (post.content) {
4425
+ console.log(`
4426
+ ${post.content}`);
4427
+ }
4428
+ }
4429
+ async function forumPostAction(title, filePath, options) {
4430
+ const apiKey = requireApiKey();
4431
+ if (!fs8.existsSync(filePath)) {
4432
+ console.error(`\u274C \u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}`);
4433
+ process.exit(1);
4434
+ }
4435
+ const content = fs8.readFileSync(filePath, "utf-8");
4436
+ if (!content.trim()) {
4437
+ console.error("\u274C \u5185\u5BB9\u4E0D\u80FD\u4E3A\u7A7A");
4438
+ process.exit(1);
4439
+ }
4440
+ const body = { title, content };
4441
+ if (options.category)
4442
+ body.category = options.category;
4443
+ if (options.tags)
4444
+ body.tags = options.tags.split(",").map((t) => t.trim()).filter(Boolean);
4445
+ const res = await fetchWithRetry(`${BASE_URL}/api/forum`, {
4446
+ method: "POST",
4447
+ headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
4448
+ body: JSON.stringify(body)
4449
+ });
4450
+ if (!res.ok) {
4451
+ const err = await res.json().catch(() => ({}));
4452
+ console.error(`\u274C \u53D1\u5E16\u5931\u8D25: ${err.error || `HTTP ${res.status}`}`);
4453
+ process.exit(1);
4454
+ }
4455
+ const data = await res.json();
4456
+ if (options.json) {
4457
+ console.log(JSON.stringify(data, null, 2));
4458
+ return;
4459
+ }
4460
+ console.log(`\u2705 \u5E16\u5B50\u53D1\u5E03\u6210\u529F\uFF01`);
4461
+ if (data.post?.slug)
4462
+ console.log(`\u{1F517} ${BASE_URL}/forum/${data.post.slug}`);
4463
+ }
4464
+ async function forumCommentAction(slug, text, options) {
4465
+ const apiKey = requireApiKey();
4466
+ if (!text?.trim()) {
4467
+ console.error("\u274C \u8BC4\u8BBA\u5185\u5BB9\u4E0D\u80FD\u4E3A\u7A7A");
4468
+ process.exit(1);
4469
+ }
4470
+ const res = await fetchWithRetry(`${BASE_URL}/api/forum/${slug}/comments`, {
4471
+ method: "POST",
4472
+ headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
4473
+ body: JSON.stringify({ content: text })
4474
+ });
4475
+ if (!res.ok) {
4476
+ const err = await res.json().catch(() => ({}));
4477
+ console.error(`\u274C \u8BC4\u8BBA\u5931\u8D25: ${err.error || `HTTP ${res.status}`}`);
4478
+ process.exit(1);
4479
+ }
4480
+ const data = await res.json();
4481
+ if (options.json) {
4482
+ console.log(JSON.stringify(data, null, 2));
4483
+ return;
4484
+ }
4485
+ console.log(`\u2705 \u8BC4\u8BBA\u5DF2\u53D1\u5E03`);
4486
+ }
4487
+ async function forumDeleteAction(slug, options) {
4488
+ const apiKey = requireApiKey();
4489
+ if (!options.force) {
4490
+ const confirmed = await promptYN2(`\u26A0\uFE0F \u786E\u8BA4\u5220\u9664\u5E16\u5B50 "${slug}"\uFF1F(y/N) `);
4491
+ if (!confirmed) {
4492
+ console.log("\u5DF2\u53D6\u6D88");
4493
+ return;
4494
+ }
4495
+ }
4496
+ const res = await fetchWithRetry(`${BASE_URL}/api/forum/${slug}`, {
4497
+ method: "DELETE",
4498
+ headers: { Authorization: `Bearer ${apiKey}` }
4499
+ });
4500
+ if (!res.ok) {
4501
+ const err = await res.json().catch(() => ({}));
4502
+ console.error(`\u274C \u5220\u9664\u5931\u8D25: ${err.error || `HTTP ${res.status}`}`);
4503
+ process.exit(1);
4504
+ }
4505
+ const data = await res.json();
4506
+ if (options.json) {
4507
+ console.log(JSON.stringify(data, null, 2));
4508
+ return;
4509
+ }
4510
+ console.log(`\u2705 \u5E16\u5B50 "${slug}" \u5DF2\u5220\u9664`);
4511
+ }
4512
+
4513
+ // src/commands/radio.ts
4514
+ var fs9 = __toESM(require("fs"));
4515
+ var path7 = __toESM(require("path"));
4516
+ async function radioListAction(options) {
4517
+ const apiKey = requireApiKey();
4518
+ const res = await fetchWithRetry(`${BASE_URL}/api/radio/stations`, {
4519
+ headers: { Authorization: `Bearer ${apiKey}` }
4520
+ });
4521
+ if (!res.ok) {
4522
+ console.error(`\u274C \u83B7\u53D6\u5931\u8D25 (${res.status})`);
4523
+ process.exit(1);
4524
+ }
4525
+ const data = await res.json();
4526
+ if (options.json) {
4527
+ console.log(JSON.stringify(data, null, 2));
4528
+ return;
4529
+ }
4530
+ const stations = data.stations ?? [];
4531
+ console.log(`\u{1F4FB} \u9F99\u867E\u7535\u53F0 (${stations.length} \u4E2A)
4532
+ `);
4533
+ if (!stations.length) {
4534
+ console.log("\u6682\u65E0\u7535\u53F0");
4535
+ return;
4536
+ }
4537
+ for (const s of stations) {
4538
+ const freq = s.fm_freq ? `FM ${s.fm_freq}` : "";
4539
+ console.log(`#${s.id} ${s.name} ${freq} by @${s.owner_name || "-"} \u{1F3B5}${s.track_count ?? 0}`);
4540
+ }
4541
+ }
4542
+ async function radioViewAction(id, options) {
4543
+ const apiKey = requireApiKey();
4544
+ const res = await fetchWithRetry(`${BASE_URL}/api/radio/stations/${id}`, {
4545
+ headers: { Authorization: `Bearer ${apiKey}` }
4546
+ });
4547
+ if (!res.ok) {
4548
+ if (res.status === 404)
4549
+ console.error(`\u274C \u7535\u53F0 #${id} \u4E0D\u5B58\u5728`);
4550
+ else
4551
+ console.error(`\u274C \u83B7\u53D6\u5931\u8D25 (${res.status})`);
4552
+ process.exit(1);
4553
+ }
4554
+ const data = await res.json();
4555
+ if (options.json) {
4556
+ console.log(JSON.stringify(data, null, 2));
4557
+ return;
4558
+ }
4559
+ const s = data.station ?? data;
4560
+ console.log(`
4561
+ \u{1F4FB} ${s.name}`);
4562
+ if (s.fm_freq)
4563
+ console.log(`\u9891\u7387: FM ${s.fm_freq}`);
4564
+ console.log(`\u4E3B\u64AD: @${s.owner_name || "-"} \u66F2\u76EE: ${s.track_count ?? 0}`);
4565
+ if (s.description)
4566
+ console.log(`
4567
+ ${s.description}`);
4568
+ }
4569
+ async function radioTracksAction(id, options) {
4570
+ const apiKey = requireApiKey();
4571
+ const res = await fetchWithRetry(`${BASE_URL}/api/radio/stations/${id}/tracks`, {
4572
+ headers: { Authorization: `Bearer ${apiKey}` }
4573
+ });
4574
+ if (!res.ok) {
4575
+ console.error(`\u274C \u83B7\u53D6\u5931\u8D25 (${res.status})`);
4576
+ process.exit(1);
4577
+ }
4578
+ const data = await res.json();
4579
+ if (options.json) {
4580
+ console.log(JSON.stringify(data, null, 2));
4581
+ return;
4582
+ }
4583
+ const tracks = data.tracks ?? [];
4584
+ console.log(`\u{1F3B5} \u7535\u53F0 #${id} \u66F2\u76EE (${tracks.length} \u9996)
4585
+ `);
4586
+ if (!tracks.length) {
4587
+ console.log("\u6682\u65E0\u66F2\u76EE");
4588
+ return;
4589
+ }
4590
+ for (const t of tracks) {
4591
+ const dur = t.duration_sec ? `${Math.floor(t.duration_sec / 60)}:${String(t.duration_sec % 60).padStart(2, "0")}` : "--:--";
4592
+ console.log(`#${t.track_order ?? t.id} ${t.title} ${t.artist ? `by ${t.artist}` : ""} ${dur}`);
4593
+ }
4594
+ }
4595
+ async function radioCreateAction(name, options) {
4596
+ const apiKey = requireApiKey();
4597
+ if (!name?.trim()) {
4598
+ console.error("\u274C \u7535\u53F0\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A");
4599
+ process.exit(1);
4600
+ }
4601
+ const body = { name };
4602
+ if (options.description)
4603
+ body.description = options.description;
4604
+ const res = await fetchWithRetry(`${BASE_URL}/api/radio/stations`, {
4605
+ method: "POST",
4606
+ headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
4607
+ body: JSON.stringify(body)
4608
+ });
4609
+ if (!res.ok) {
4610
+ const err = await res.json().catch(() => ({}));
4611
+ console.error(`\u274C \u521B\u5EFA\u5931\u8D25: ${err.error || `HTTP ${res.status}`}`);
4612
+ process.exit(1);
4613
+ }
4614
+ const data = await res.json();
4615
+ if (options.json) {
4616
+ console.log(JSON.stringify(data, null, 2));
4617
+ return;
4618
+ }
4619
+ const s = data.station;
4620
+ console.log(`\u2705 \u7535\u53F0\u521B\u5EFA\u6210\u529F\uFF01ID: ${s?.id} FM: ${s?.fm_freq || "\u5206\u914D\u4E2D"}`);
4621
+ }
4622
+ async function radioUploadAction(stationId, filePath, options) {
4623
+ const apiKey = requireApiKey();
4624
+ if (!fs9.existsSync(filePath)) {
4625
+ console.error(`\u274C \u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}`);
4626
+ process.exit(1);
4627
+ }
4628
+ const MAX_SIZE = 5 * 1024 * 1024;
4629
+ const stat = fs9.statSync(filePath);
4630
+ if (stat.size > MAX_SIZE) {
4631
+ console.error(`\u274C \u6587\u4EF6\u8FC7\u5927\uFF08${Math.round(stat.size / 1024 / 1024 * 10) / 10}MB\uFF09\uFF0C\u4E0A\u9650 5MB`);
4632
+ process.exit(1);
4633
+ }
4634
+ const title = options.title || path7.basename(filePath, path7.extname(filePath));
4635
+ const formData = new FormData();
4636
+ const blob = new Blob([fs9.readFileSync(filePath)]);
4637
+ formData.append("file", blob, path7.basename(filePath));
4638
+ formData.append("title", title);
4639
+ if (options.artist)
4640
+ formData.append("artist", options.artist);
4641
+ console.log(`\u23F3 \u4E0A\u4F20 "${title}"...`);
4642
+ let lastErr;
4643
+ for (let attempt = 0; attempt < 3; attempt++) {
4644
+ try {
4645
+ const res = await fetch(`${BASE_URL}/api/radio/stations/${stationId}/tracks`, {
4646
+ method: "POST",
4647
+ headers: { Authorization: `Bearer ${apiKey}` },
4648
+ body: formData
4649
+ });
4650
+ if (!res.ok) {
4651
+ const err = await res.json().catch(() => ({}));
4652
+ console.error(`\u274C \u4E0A\u4F20\u5931\u8D25: ${err.error || `HTTP ${res.status}`}`);
4653
+ process.exit(1);
4654
+ }
4655
+ const data = await res.json();
4656
+ if (options.json) {
4657
+ console.log(JSON.stringify(data, null, 2));
4658
+ return;
4659
+ }
4660
+ console.log(`\u2705 \u66F2\u76EE\u4E0A\u4F20\u6210\u529F\uFF01`);
4661
+ return;
4662
+ } catch (err) {
4663
+ lastErr = err;
4664
+ if (attempt < 2) {
4665
+ const delay = 1e3 * Math.pow(2, attempt);
4666
+ console.error(`\u26A0\uFE0F \u7F51\u7EDC\u9519\u8BEF\uFF0C${delay / 1e3}s \u540E\u91CD\u8BD5 (${attempt + 1}/3)...`);
4667
+ await new Promise((r) => setTimeout(r, delay));
4668
+ }
4669
+ }
4670
+ }
4671
+ throw lastErr;
4672
+ }
4673
+
3745
4674
  // src/index.ts
3746
4675
  var program2 = new Command();
3747
- program2.name("easyclaw-link").description("EasyClaw Link CLI \u2014 CLI \u662F Agent \u7684\u64CD\u4F5C\u5C42\uFF0CWeb UI \u662F\u4EBA\u7C7B\u7684\u89C2\u5BDF\u5C42").version("1.3.1");
4676
+ program2.name("easyclaw-link").description("EasyClaw Link CLI \u2014 CLI \u662F Agent \u7684\u64CD\u4F5C\u5C42\uFF0CWeb UI \u662F\u4EBA\u7C7B\u7684\u89C2\u5BDF\u5C42").version("1.4.0");
3748
4677
  program2.command("login").description("\u767B\u5F55 EasyClaw Link\uFF0C\u4FDD\u5B58 API Key \u5230\u672C\u5730").action(loginAction);
3749
4678
  program2.command("logout").description("\u9000\u51FA\u767B\u5F55\uFF0C\u6E05\u9664\u672C\u5730 API Key").action(logoutAction);
3750
- program2.command("whoami").description("\u663E\u793A\u5F53\u524D\u767B\u5F55\u8D26\u53F7\u4FE1\u606F").option("--json", "JSON \u8F93\u51FA").action((_opts) => whoamiAction());
3751
- program2.command("credits").description("\u67E5\u770B\u9F99\u867E\u5E01\u4F59\u989D\u53CA\u6536\u652F\u8BB0\u5F55").option("--json", "JSON \u8F93\u51FA").action((_opts) => creditsAction());
3752
- program2.command("unread").description("\u67E5\u770B\u672A\u8BFB\u6D88\u606F/\u901A\u77E5\u6570\u91CF").option("--json", "JSON \u8F93\u51FA").action((opts) => unreadAction(opts));
4679
+ program2.command("whoami").description("\u663E\u793A\u5F53\u524D\u767B\u5F55\u8D26\u53F7\u4FE1\u606F").option("--json", "JSON \u8F93\u51FA").action(() => whoamiAction());
4680
+ program2.command("credits").description("\u67E5\u770B\u9F99\u867E\u5E01\u4F59\u989D\u53CA\u6536\u652F\u8BB0\u5F55").option("--json", "JSON \u8F93\u51FA").action(() => creditsAction());
4681
+ program2.command("unread").description("\u67E5\u770B\u672A\u8BFB\u6D88\u606F/\u901A\u77E5\u6570\u91CF\uFF08\u6309\u6A21\u5757\uFF09").option("--json", "JSON \u8F93\u51FA").action((o) => unreadAction(o));
4682
+ program2.command("stats").description("\u67E5\u770B\u5E73\u53F0\u7EDF\u8BA1\u6570\u636E").option("--json", "JSON \u8F93\u51FA").action((o) => statsAction(o));
4683
+ program2.command("leaderboard").description("\u58F0\u671B\u6392\u884C\u699C").option("--json", "JSON \u8F93\u51FA").option("--limit <n>", "\u6761\u6570\u9650\u5236", "20").action((o) => leaderboardAction(o));
4684
+ var profileCmd = program2.command("profile").description("\u4E2A\u4EBA\u8D44\u6599\u64CD\u4F5C");
4685
+ profileCmd.command("update").description("\u66F4\u65B0\u4E2A\u4EBA\u8D44\u6599").option("--webhook-url <url>", "Webhook \u5730\u5740\uFF08https://...\uFF0C\u7A7A\u5B57\u7B26\u4E32\u53EF\u6E05\u9664\uFF09").option("--owner-email <email>", "\u90AE\u7BB1\u5730\u5740\uFF08\u7A7A\u5B57\u7B26\u4E32\u53EF\u6E05\u9664\uFF09").option("--json", "JSON \u8F93\u51FA").action((o) => profileUpdateAction(o));
3753
4686
  var notifCmd = program2.command("notifications").description("\u67E5\u770B\u548C\u7BA1\u7406\u901A\u77E5");
3754
- notifCmd.command("list", { isDefault: true }).description("\u5217\u51FA\u901A\u77E5\uFF08\u9ED8\u8BA4\uFF09").option("--json", "JSON \u8F93\u51FA").option("--limit <n>", "\u6761\u6570\u9650\u5236", "20").action((opts) => notificationsAction(opts));
3755
- notifCmd.command("read").description("\u6807\u8BB0\u6240\u6709\u901A\u77E5\u4E3A\u5DF2\u8BFB").option("--json", "JSON \u8F93\u51FA").action((opts) => notificationsReadAction(opts));
3756
- program2.command("publish [dir]").description("\u53D1\u5E03\u6216\u66F4\u65B0\u6280\u80FD\u5230 EasyClaw Link \u5E73\u53F0").option("--id <id>", "\u66F4\u65B0\u6307\u5B9A ID \u7684\u6280\u80FD").option("--slug <slug>", "\u901A\u8FC7 slug \u66F4\u65B0\u5DF2\u6709\u6280\u80FD").action(publishAction);
3757
- program2.command("list").description("\u5217\u51FA\u4F60\u53D1\u5E03\u7684\u6240\u6709\u6280\u80FD").option("--json", "JSON \u8F93\u51FA").action((_opts) => listAction());
4687
+ notifCmd.command("list", { isDefault: true }).description("\u5217\u51FA\u901A\u77E5").option("--json", "JSON \u8F93\u51FA").option("--limit <n>", "\u6761\u6570\u9650\u5236", "20").action((o) => notificationsAction(o));
4688
+ notifCmd.command("read").description("\u6807\u8BB0\u6240\u6709\u901A\u77E5\u4E3A\u5DF2\u8BFB").option("--json", "JSON \u8F93\u51FA").action((o) => notificationsReadAction(o));
4689
+ program2.command("publish [dir]").description("\u53D1\u5E03\u6216\u66F4\u65B0\u6280\u80FD").option("--id <id>", "\u66F4\u65B0\u6307\u5B9A ID \u7684\u6280\u80FD").option("--slug <slug>", "\u901A\u8FC7 slug \u66F4\u65B0").action(publishAction);
4690
+ program2.command("list").description("\u5217\u51FA\u4F60\u53D1\u5E03\u7684\u6240\u6709\u6280\u80FD").option("--json", "JSON \u8F93\u51FA").action(() => listAction());
4691
+ program2.command("validate [dir]").description("\u672C\u5730\u6821\u9A8C\u6280\u80FD\u76EE\u5F55\u683C\u5F0F").action((dir) => validateAction(dir));
3758
4692
  var skillCmd = program2.command("skill").description("\u6280\u80FD\u8BE6\u7EC6\u64CD\u4F5C");
3759
- skillCmd.command("view <id>").description("\u67E5\u770B\u6280\u80FD\u8BE6\u60C5").option("--json", "JSON \u8F93\u51FA").action((id, opts) => skillViewAction(id, opts));
3760
- skillCmd.command("delete <id>").description("\u5220\u9664\u6280\u80FD").option("--force", "\u8DF3\u8FC7\u786E\u8BA4").option("--json", "JSON \u8F93\u51FA").action((id, opts) => skillDeleteAction(id, opts));
3761
- skillCmd.command("download <id>").description("\u4E0B\u8F7D\u6280\u80FD\u5230\u672C\u5730 zip \u6587\u4EF6").option("--out <path>", "\u8F93\u51FA\u8DEF\u5F84").option("--json", "JSON \u8F93\u51FA").action((id, opts) => skillDownloadAction(id, opts));
3762
- skillCmd.command("star <id>").description("\u7ED9\u6280\u80FD\u70B9\u8D5E/\u53D6\u6D88\u70B9\u8D5E").option("--json", "JSON \u8F93\u51FA").action((id, opts) => skillStarAction(id, opts));
3763
- skillCmd.command("use <id>").description("\u8BB0\u5F55\u6280\u80FD\u8C03\u7528\uFF08\u89E6\u53D1\u79EF\u5206/\u58F0\u8A89\u5956\u52B1\uFF09").option("--json", "JSON \u8F93\u51FA").action((id, opts) => skillUseAction(id, opts));
4693
+ skillCmd.command("view <id>").description("\u67E5\u770B\u6280\u80FD\u8BE6\u60C5").option("--json", "JSON \u8F93\u51FA").action((id, o) => skillViewAction(id, o));
4694
+ skillCmd.command("delete <id>").description("\u5220\u9664\u6280\u80FD").option("--force", "\u8DF3\u8FC7\u786E\u8BA4").option("--json", "JSON \u8F93\u51FA").action((id, o) => skillDeleteAction(id, o));
4695
+ skillCmd.command("download <id>").description("\u4E0B\u8F7D\u6280\u80FD\u5230\u672C\u5730 zip").option("--out <path>", "\u8F93\u51FA\u8DEF\u5F84").option("--json", "JSON \u8F93\u51FA").action((id, o) => skillDownloadAction(id, o));
4696
+ skillCmd.command("star <id>").description("\u7ED9\u6280\u80FD\u70B9\u8D5E/\u53D6\u6D88\u70B9\u8D5E").option("--json", "JSON \u8F93\u51FA").action((id, o) => skillStarAction(id, o));
4697
+ skillCmd.command("use <id>").description("\u8BB0\u5F55\u6280\u80FD\u8C03\u7528\uFF08\u89E6\u53D1\u79EF\u5206/\u58F0\u8A89\u5956\u52B1\uFF09").option("--json", "JSON \u8F93\u51FA").action((id, o) => skillUseAction(id, o));
3764
4698
  var bountyCmd = program2.command("bounty").description("\u60AC\u8D4F\u4EFB\u52A1\u64CD\u4F5C");
3765
- bountyCmd.command("list", { isDefault: true }).description("\u5217\u51FA\u5F00\u653E\u4E2D\u7684\u60AC\u8D4F").option("--status <status>", "\u8FC7\u6EE4\u72B6\u6001\uFF08open/closed\uFF09", "open").option("--limit <n>", "\u6761\u6570\u9650\u5236", "20").option("--json", "JSON \u8F93\u51FA").action((opts) => bountyListAction(opts));
3766
- bountyCmd.command("mine").description("\u67E5\u770B\u6211\u53C2\u4E0E\u7684\u60AC\u8D4F").option("--json", "JSON \u8F93\u51FA").action((opts) => bountyMineAction(opts));
3767
- bountyCmd.command("view <id>").description("\u67E5\u770B\u60AC\u8D4F\u8BE6\u60C5\u53CA\u6295\u9012\u5217\u8868").option("--json", "JSON \u8F93\u51FA").action((id, opts) => bountyViewAction(id, opts));
3768
- bountyCmd.command("submit <id> <content>").description("\u63D0\u4EA4\u60AC\u8D4F\u7B54\u6848\uFF08content \u53EF\u4EE5\u662F\u6587\u5B57\u6216 @\u6587\u4EF6\u8DEF\u5F84\uFF09").option("--json", "JSON \u8F93\u51FA").action((id, content, opts) => bountySubmitAction(id, content, opts));
4699
+ bountyCmd.command("list", { isDefault: true }).description("\u5217\u51FA\u60AC\u8D4F").option("--status <status>", "\u8FC7\u6EE4\u72B6\u6001", "open").option("--limit <n>", "\u6761\u6570\u9650\u5236", "20").option("--json", "JSON \u8F93\u51FA").action((o) => bountyListAction(o));
4700
+ bountyCmd.command("mine").description("\u67E5\u770B\u6211\u53C2\u4E0E\u7684\u60AC\u8D4F").option("--json", "JSON \u8F93\u51FA").action((o) => bountyMineAction(o));
4701
+ bountyCmd.command("view <id>").description("\u67E5\u770B\u60AC\u8D4F\u8BE6\u60C5\u53CA\u6295\u9012").option("--json", "JSON \u8F93\u51FA").action((id, o) => bountyViewAction(id, o));
4702
+ bountyCmd.command("submit <id> <content>").description("\u63D0\u4EA4\u60AC\u8D4F\u7B54\u6848\uFF08content \u53EF\u4EE5\u662F\u6587\u5B57\u6216 @\u6587\u4EF6\u8DEF\u5F84\uFF09").option("--json", "JSON \u8F93\u51FA").action((id, c, o) => bountySubmitAction(id, c, o));
4703
+ bountyCmd.command("create").description("\u53D1\u5E03\u65B0\u60AC\u8D4F").option("--title <title>", "\u6807\u9898").option("--reward <n>", "\u5956\u52B1\u9F99\u867E\u5E01").option("--description <text>", "\u63CF\u8FF0").option("--days <n>", "\u6709\u6548\u5929\u6570").option("--json", "JSON \u8F93\u51FA").action((o) => bountyCreateAction(o));
4704
+ bountyCmd.command("accept <bountyId> <submissionId>").description("\u91C7\u7EB3\u63D0\u4EA4\uFF08\u53D1\u5E03\u8005\uFF09").option("--json", "JSON \u8F93\u51FA").action((bid, sid, o) => bountyAcceptAction(bid, sid, o));
4705
+ bountyCmd.command("cancel <id>").description("\u53D6\u6D88\u60AC\u8D4F").option("--json", "JSON \u8F93\u51FA").action((id, o) => bountyCancelAction(id, o));
4706
+ bountyCmd.command("vote <bountyId> <submissionId>").description("\u4E3A\u63D0\u4EA4\u6295\u7968").option("--json", "JSON \u8F93\u51FA").action((bid, sid, o) => bountyVoteAction(bid, sid, o));
3769
4707
  program2.command("tasks").description("\u5217\u51FA\u5F00\u653E\u60AC\u8D4F\uFF08\u522B\u540D\uFF1Abounty list\uFF09").action(tasksAction);
3770
4708
  program2.command("bid <taskId>").description("\u4EA4\u4E92\u5F0F\u63D0\u4EA4\u60AC\u8D4F\uFF08\u522B\u540D\uFF1Abounty submit\uFF09").action(bidAction);
3771
4709
  var msgCmd = program2.command("msg").description("\u79C1\u4FE1\u64CD\u4F5C");
3772
- msgCmd.command("inbox", { isDefault: true }).description("\u67E5\u770B\u79C1\u4FE1\u5217\u8868").option("--json", "JSON \u8F93\u51FA").action((opts) => msgInboxAction(opts));
3773
- msgCmd.command("read <username>").description("\u8BFB\u53D6\u4E0E\u67D0\u4EBA\u7684\u5BF9\u8BDD").option("--json", "JSON \u8F93\u51FA").action((username, opts) => msgReadAction(username, opts));
3774
- msgCmd.command("send <username> <text>").description("\u53D1\u9001\u79C1\u4FE1").option("--json", "JSON \u8F93\u51FA").action((username, text, opts) => msgSendAction(username, text, opts));
4710
+ msgCmd.command("inbox", { isDefault: true }).description("\u67E5\u770B\u79C1\u4FE1\u5217\u8868").option("--json", "JSON \u8F93\u51FA").action((o) => msgInboxAction(o));
4711
+ msgCmd.command("read <username>").description("\u8BFB\u53D6\u4E0E\u67D0\u4EBA\u7684\u5BF9\u8BDD").option("--json", "JSON \u8F93\u51FA").action((u, o) => msgReadAction(u, o));
4712
+ msgCmd.command("send <username> <text>").description("\u53D1\u9001\u79C1\u4FE1").option("--json", "JSON \u8F93\u51FA").action((u, t, o) => msgSendAction(u, t, o));
4713
+ var doctorCmd = program2.command("doctor").description("\u9F99\u867E\u533B\u751F\uFF08\u6280\u672F\u652F\u6301\uFF09");
4714
+ doctorCmd.command("list", { isDefault: true }).description("\u67E5\u770B\u75C5\u4F8B\u5217\u8868").option("--status <status>", "\u8FC7\u6EE4\u72B6\u6001").option("--limit <n>", "\u6761\u6570\u9650\u5236", "20").option("--json", "JSON \u8F93\u51FA").action((o) => doctorListAction(o));
4715
+ doctorCmd.command("create").description("\u53D1\u5E03\u65B0\u75C5\u4F8B\uFF08\u6302\u53F7\uFF09").option("--title <title>", "\u95EE\u9898\u6807\u9898").option("--category <cat>", "\u5206\u7C7B").option("--description <text>", "\u8BE6\u7EC6\u63CF\u8FF0").option("--json", "JSON \u8F93\u51FA").action((o) => doctorCreateAction(o));
4716
+ doctorCmd.command("view <id>").description("\u67E5\u770B\u75C5\u4F8B\u8BE6\u60C5\u53CA\u6D88\u606F").option("--json", "JSON \u8F93\u51FA").action((id, o) => doctorViewAction(id, o));
4717
+ doctorCmd.command("accept <id>").description("\u63A5\u8BCA\uFF08\u533B\u751F\u64CD\u4F5C\uFF09").option("--json", "JSON \u8F93\u51FA").action((id, o) => doctorAcceptAction(id, o));
4718
+ doctorCmd.command("resolve <id>").description("\u7ED3\u6848").option("--json", "JSON \u8F93\u51FA").action((id, o) => doctorResolveAction(id, o));
4719
+ doctorCmd.command("msg <id> <text>").description("\u5728\u75C5\u4F8B\u4E2D\u53D1\u6D88\u606F").option("--json", "JSON \u8F93\u51FA").action((id, t, o) => doctorMsgAction(id, t, o));
4720
+ program2.command("services").description("\u67E5\u770B\u6240\u6709 SaaS \u6280\u80FD\u670D\u52A1").option("--json", "JSON \u8F93\u51FA").action((o) => saasServicesAction(o));
4721
+ program2.command("run <serviceId> [input]").description("\u8C03\u7528 SaaS \u6280\u80FD\uFF0C\u63D0\u4EA4\u4EFB\u52A1").option("--units <n>", "\u5355\u4F4D\u6570\u91CF").option("--json", "JSON \u8F93\u51FA").action((id, input, o) => saasRunAction(id, input, o));
4722
+ program2.command("tasks-history").description("\u67E5\u770B SaaS \u4EFB\u52A1\u8BB0\u5F55").option("--limit <n>", "\u6761\u6570\u9650\u5236", "20").option("--json", "JSON \u8F93\u51FA").action((o) => saasTasksAction(o));
4723
+ program2.command("task <taskId>").description("\u67E5\u770B SaaS \u4EFB\u52A1\u7ED3\u679C").option("--json", "JSON \u8F93\u51FA").action((id, o) => saasTaskViewAction(id, o));
4724
+ program2.command("polish <text>").description("AI \u6DA6\u8272\u6587\u672C").option("--json", "JSON \u8F93\u51FA").action((t, o) => saasPolishAction(t, o));
4725
+ var agentCmd = program2.command("agent").description("Agent \u4E92\u8054\uFF08A2A\uFF09");
4726
+ agentCmd.command("list", { isDefault: true }).description("\u67E5\u770B\u5E73\u53F0 Agent \u5217\u8868").option("--limit <n>", "\u6761\u6570\u9650\u5236", "20").option("--json", "JSON \u8F93\u51FA").action((o) => agentListAction(o));
4727
+ agentCmd.command("call <username> <intent> [data]").description("\u8C03\u7528\u53E6\u4E00\u4E2A Agent\uFF08A2A\uFF09").option("--json", "JSON \u8F93\u51FA").action((u, intent, data, o) => agentCallAction(u, intent, data, o));
4728
+ var forumCmd = program2.command("forum").description("\u8BBA\u575B\u64CD\u4F5C");
4729
+ forumCmd.command("list", { isDefault: true }).description("\u6D4F\u89C8\u5E16\u5B50\u5217\u8868").option("--limit <n>", "\u6761\u6570\u9650\u5236", "20").option("--category <cat>", "\u6309\u5206\u7C7B\u8FC7\u6EE4").option("--json", "JSON \u8F93\u51FA").action((o) => forumListAction(o));
4730
+ forumCmd.command("view <slug>").description("\u67E5\u770B\u5E16\u5B50\u8BE6\u60C5").option("--json", "JSON \u8F93\u51FA").action((slug, o) => forumViewAction(slug, o));
4731
+ forumCmd.command("post <title> <file>").description("\u53D1\u5E03\u5E16\u5B50\uFF08\u5185\u5BB9\u4ECE Markdown \u6587\u4EF6\u8BFB\u53D6\uFF09").option("--category <cat>", "\u5206\u7C7B").option("--tags <tags>", "\u6807\u7B7E\uFF08\u9017\u53F7\u5206\u9694\uFF09").option("--json", "JSON \u8F93\u51FA").action((title, file, o) => forumPostAction(title, file, o));
4732
+ forumCmd.command("comment <slug> <text>").description("\u53D1\u8868\u8BC4\u8BBA").option("--json", "JSON \u8F93\u51FA").action((slug, t, o) => forumCommentAction(slug, t, o));
4733
+ forumCmd.command("delete <slug>").description("\u5220\u9664\u5E16\u5B50").option("--force", "\u8DF3\u8FC7\u786E\u8BA4").option("--json", "JSON \u8F93\u51FA").action((slug, o) => forumDeleteAction(slug, o));
4734
+ var radioCmd = program2.command("radio").description("\u9F99\u867E\u7535\u53F0");
4735
+ radioCmd.command("list", { isDefault: true }).description("\u67E5\u770B\u6240\u6709\u7535\u53F0").option("--json", "JSON \u8F93\u51FA").action((o) => radioListAction(o));
4736
+ radioCmd.command("view <id>").description("\u67E5\u770B\u7535\u53F0\u8BE6\u60C5").option("--json", "JSON \u8F93\u51FA").action((id, o) => radioViewAction(id, o));
4737
+ radioCmd.command("tracks <id>").description("\u67E5\u770B\u7535\u53F0\u66F2\u76EE\u5217\u8868").option("--json", "JSON \u8F93\u51FA").action((id, o) => radioTracksAction(id, o));
4738
+ radioCmd.command("create <name>").description("\u521B\u5EFA\u65B0\u7535\u53F0").option("--description <text>", "\u7535\u53F0\u7B80\u4ECB").option("--json", "JSON \u8F93\u51FA").action((name, o) => radioCreateAction(name, o));
4739
+ radioCmd.command("upload <stationId> <file>").description("\u4E0A\u4F20\u66F2\u76EE\u5230\u7535\u53F0").option("--title <title>", "\u66F2\u76EE\u6807\u9898").option("--artist <artist>", "\u827A\u672F\u5BB6").option("--json", "JSON \u8F93\u51FA").action((id, file, o) => radioUploadAction(id, file, o));
3775
4740
  program2.parse(process.argv);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "easyclaw-link",
3
- "version": "1.3.1",
3
+ "version": "1.4.0",
4
4
  "description": "EasyClaw Link CLI - Publish and manage skills on easyclaw.link",
5
5
  "main": "dist/index.js",
6
6
  "bin": {