easyclaw-link 1.6.0 → 1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +225 -104
  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 path8 = require("path");
935
- var fs11 = require("fs");
934
+ var path9 = require("path");
935
+ var fs12 = 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 = path8.resolve(baseDir, baseName);
1768
- if (fs11.existsSync(localBin))
1767
+ const localBin = path9.resolve(baseDir, baseName);
1768
+ if (fs12.existsSync(localBin))
1769
1769
  return localBin;
1770
- if (sourceExt.includes(path8.extname(baseName)))
1770
+ if (sourceExt.includes(path9.extname(baseName)))
1771
1771
  return void 0;
1772
- const foundExt = sourceExt.find((ext) => fs11.existsSync(`${localBin}${ext}`));
1772
+ const foundExt = sourceExt.find((ext) => fs12.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 = fs11.realpathSync(this._scriptPath);
1784
+ resolvedScriptPath = fs12.realpathSync(this._scriptPath);
1785
1785
  } catch (err) {
1786
1786
  resolvedScriptPath = this._scriptPath;
1787
1787
  }
1788
- executableDir = path8.resolve(path8.dirname(resolvedScriptPath), executableDir);
1788
+ executableDir = path9.resolve(path9.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 = path8.basename(this._scriptPath, path8.extname(this._scriptPath));
1793
+ const legacyName = path9.basename(this._scriptPath, path9.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(path8.extname(executableFile));
1800
+ launchWithNode = sourceExt.includes(path9.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 = path8.basename(filename, path8.extname(filename));
2602
+ this._name = path9.basename(filename, path9.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(path9) {
2617
- if (path9 === void 0)
2616
+ executableDir(path10) {
2617
+ if (path10 === void 0)
2618
2618
  return this._executableDir;
2619
- this._executableDir = path9;
2619
+ this._executableDir = path10;
2620
2620
  return this;
2621
2621
  }
2622
2622
  /**
@@ -2833,7 +2833,7 @@ var os = __toESM(require("os"));
2833
2833
  var CONFIG_DIR = path.join(os.homedir(), ".easyclaw-link");
2834
2834
  var CONFIG_FILE = path.join(CONFIG_DIR, "config.json");
2835
2835
  var BASE_URL = process.env.EASYCLAW_LINK_API || "https://easyclaw.link";
2836
- var EXIT = {
2836
+ var EXIT2 = {
2837
2837
  OK: 0,
2838
2838
  ERROR: 1,
2839
2839
  AUTH: 2,
@@ -2848,26 +2848,26 @@ function httpError(status, serverMessage) {
2848
2848
  case 401:
2849
2849
  console.error(`\u274C \u8BA4\u8BC1\u5931\u8D25${msg}
2850
2850
  \u2192 \u8BF7\u5148\u8FD0\u884C: ecl login`);
2851
- process.exit(EXIT.AUTH);
2851
+ process.exit(EXIT2.AUTH);
2852
2852
  case 403:
2853
2853
  console.error(`\u274C \u6743\u9650\u4E0D\u8DB3${msg}
2854
2854
  \u2192 \u5F53\u524D\u8D26\u53F7\u65E0\u6B64\u64CD\u4F5C\u6743\u9650\uFF0C\u68C0\u67E5\u8D26\u53F7\u89D2\u8272`);
2855
- process.exit(EXIT.PERMISSION);
2855
+ process.exit(EXIT2.PERMISSION);
2856
2856
  case 404:
2857
2857
  console.error(`\u274C \u8D44\u6E90\u4E0D\u5B58\u5728${msg}
2858
2858
  \u2192 \u68C0\u67E5 ID/slug \u662F\u5426\u6B63\u786E`);
2859
- process.exit(EXIT.NOT_FOUND);
2859
+ process.exit(EXIT2.NOT_FOUND);
2860
2860
  case 422:
2861
2861
  console.error(`\u274C \u8BF7\u6C42\u6821\u9A8C\u5931\u8D25${msg}
2862
2862
  \u2192 \u68C0\u67E5\u53C2\u6570\u683C\u5F0F`);
2863
- process.exit(EXIT.VALIDATION);
2863
+ process.exit(EXIT2.VALIDATION);
2864
2864
  case 429:
2865
2865
  console.error(`\u274C \u89E6\u53D1\u9891\u7387\u9650\u5236${msg}
2866
2866
  \u2192 \u8BF7\u7A0D\u540E\u91CD\u8BD5`);
2867
- process.exit(EXIT.RATE_LIMIT);
2867
+ process.exit(EXIT2.RATE_LIMIT);
2868
2868
  default:
2869
2869
  console.error(`\u274C \u8BF7\u6C42\u5931\u8D25 (HTTP ${status})${msg}`);
2870
- process.exit(EXIT.ERROR);
2870
+ process.exit(EXIT2.ERROR);
2871
2871
  }
2872
2872
  }
2873
2873
  async function assertOk(res) {
@@ -2901,7 +2901,7 @@ function requireApiKey() {
2901
2901
  const cfg = readConfig();
2902
2902
  if (!cfg.apiKey) {
2903
2903
  console.error("\u274C \u672A\u767B\u5F55\uFF0C\u8BF7\u5148\u8FD0\u884C: ecl login");
2904
- process.exit(EXIT.AUTH);
2904
+ process.exit(EXIT2.AUTH);
2905
2905
  }
2906
2906
  return cfg.apiKey;
2907
2907
  }
@@ -2926,10 +2926,10 @@ async function fetchWithRetry(url, options, maxRetries = 3) {
2926
2926
  // src/commands/login.ts
2927
2927
  function prompt(question) {
2928
2928
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
2929
- return new Promise((resolve4) => {
2929
+ return new Promise((resolve5) => {
2930
2930
  rl.question(question, (answer) => {
2931
2931
  rl.close();
2932
- resolve4(answer.trim());
2932
+ resolve5(answer.trim());
2933
2933
  });
2934
2934
  });
2935
2935
  }
@@ -3234,10 +3234,10 @@ function prompt2(question) {
3234
3234
  input: process.stdin,
3235
3235
  output: process.stdout
3236
3236
  });
3237
- return new Promise((resolve4) => {
3237
+ return new Promise((resolve5) => {
3238
3238
  rl.question(question, (answer) => {
3239
3239
  rl.close();
3240
- resolve4(answer.trim());
3240
+ resolve5(answer.trim());
3241
3241
  });
3242
3242
  });
3243
3243
  }
@@ -3417,13 +3417,15 @@ async function leaderboardAction(options) {
3417
3417
  async function profileUpdateAction(options) {
3418
3418
  const apiKey = requireApiKey();
3419
3419
  const body = {};
3420
+ if (options.displayName !== void 0)
3421
+ body.display_name = options.displayName || null;
3420
3422
  if (options.webhookUrl !== void 0)
3421
3423
  body.webhook_url = options.webhookUrl || null;
3422
3424
  if (options.ownerEmail !== void 0)
3423
3425
  body.owner_email = options.ownerEmail || null;
3424
3426
  if (!Object.keys(body).length) {
3425
- console.error("\u274C \u8BF7\u63D0\u4F9B\u81F3\u5C11\u4E00\u4E2A\u5B57\u6BB5\uFF1A--webhook-url \u6216 --owner-email");
3426
- process.exit(1);
3427
+ console.error("\u274C \u8BF7\u63D0\u4F9B\u81F3\u5C11\u4E00\u4E2A\u5B57\u6BB5\uFF1A--display-name\u3001--webhook-url \u6216 --owner-email");
3428
+ process.exit(EXIT.VALIDATION);
3427
3429
  }
3428
3430
  const res = await fetchWithRetry(`${BASE_URL}/api/auth/me`, {
3429
3431
  method: "PATCH",
@@ -3437,6 +3439,8 @@ async function profileUpdateAction(options) {
3437
3439
  return;
3438
3440
  }
3439
3441
  console.log("\u2705 \u4E2A\u4EBA\u8D44\u6599\u5DF2\u66F4\u65B0");
3442
+ if (body.display_name !== void 0)
3443
+ console.log(` \u663E\u793A\u540D\u79F0: ${body.display_name || "(\u5DF2\u6E05\u9664)"}`);
3440
3444
  if (body.webhook_url !== void 0)
3441
3445
  console.log(` Webhook URL: ${body.webhook_url || "(\u5DF2\u6E05\u9664)"}`);
3442
3446
  if (body.owner_email !== void 0)
@@ -3446,73 +3450,189 @@ async function profileUpdateAction(options) {
3446
3450
  // src/commands/validate.ts
3447
3451
  var fs5 = __toESM(require("fs"));
3448
3452
  var path5 = __toESM(require("path"));
3449
- var SKILL_MD_NAMES = ["SKILL.md", "skill.md", "Skill.md"];
3450
- function parseSkillMeta(content) {
3451
- const meta = {};
3452
- const nameMatch = content.match(/^name:\s*(.+)$/m);
3453
- const descMatch = content.match(/^description:\s*(.+)$/m);
3454
- if (nameMatch)
3455
- meta.name = nameMatch[1].trim().replace(/^["']|["']$/g, "");
3456
- if (descMatch)
3457
- meta.description = descMatch[1].trim().replace(/^["']|["']$/g, "");
3458
- return meta;
3459
- }
3460
- async function validateAction(dir) {
3461
- const target = path5.resolve(dir || ".");
3453
+ var VALID_CATEGORIES = ["system", "office", "creative", "data", "coding", "ai_agent", "tools", "other"];
3454
+ var SKILL_MD_MAX = 5e4;
3455
+ var SKILL_MD_WARN_MIN = 200;
3456
+ var SKILL_MD_WARN_MAX = 2e4;
3457
+ var DESC_MAX = 1e3;
3458
+ function validateSkillDir2(dir) {
3462
3459
  const errors = [];
3463
3460
  const warnings = [];
3461
+ const skillMdPath = path5.join(dir, "SKILL.md");
3462
+ const pkgPath = path5.join(dir, "package.json");
3463
+ if (!fs5.existsSync(skillMdPath)) {
3464
+ errors.push("SKILL.md \u4E0D\u5B58\u5728");
3465
+ } else {
3466
+ const content = fs5.readFileSync(skillMdPath, "utf-8");
3467
+ const trimmed = content.trim();
3468
+ if (!trimmed) {
3469
+ errors.push("SKILL.md \u4E3A\u7A7A");
3470
+ } else {
3471
+ if (!/^#\s+\S/m.test(content)) {
3472
+ errors.push("SKILL.md \u7F3A\u5C11 # \u6807\u9898\u884C\uFF08\u81F3\u5C11\u4E00\u884C\u4EE5 # \u5F00\u5934\uFF09");
3473
+ }
3474
+ if (content.length > SKILL_MD_MAX) {
3475
+ errors.push(`SKILL.md \u8D85\u8FC7 ${SKILL_MD_MAX} \u5B57\u7B26\uFF08\u5F53\u524D ${content.length}\uFF09\uFF0C\u540E\u7AEF\u4F1A\u62D2\u7EDD`);
3476
+ }
3477
+ if (trimmed.length < SKILL_MD_WARN_MIN) {
3478
+ warnings.push(`SKILL.md \u5185\u5BB9\u8F83\u77ED\uFF08${trimmed.length} \u5B57\u7B26\uFF0C\u5EFA\u8BAE \u2265${SKILL_MD_WARN_MIN}\uFF09`);
3479
+ }
3480
+ if (!/##?\s*(使用方法|用法|usage|how to use)/i.test(content)) {
3481
+ warnings.push('SKILL.md \u7F3A\u5C11"\u4F7F\u7528\u65B9\u6CD5"\u7AE0\u8282\uFF08Agent \u9700\u8981\u77E5\u9053\u5982\u4F55\u8C03\u7528\uFF09');
3482
+ }
3483
+ if (content.length > SKILL_MD_WARN_MAX) {
3484
+ warnings.push(`SKILL.md \u8D85\u8FC7 ${SKILL_MD_WARN_MAX} \u5B57\u7B26\uFF0C\u8D85\u957F\u6587\u6863\u5F71\u54CD Agent \u4E0A\u4E0B\u6587\u52A0\u8F7D`);
3485
+ }
3486
+ }
3487
+ }
3488
+ if (!fs5.existsSync(pkgPath)) {
3489
+ warnings.push("package.json \u4E0D\u5B58\u5728\uFF0C\u6280\u80FD\u6807\u9898\u5C06\u964D\u7EA7\u4E3A\u76EE\u5F55\u540D");
3490
+ } else {
3491
+ let pkg;
3492
+ try {
3493
+ pkg = JSON.parse(fs5.readFileSync(pkgPath, "utf-8"));
3494
+ } catch {
3495
+ errors.push("package.json JSON \u8BED\u6CD5\u9519\u8BEF");
3496
+ return { errors, warnings };
3497
+ }
3498
+ if (!pkg.name || typeof pkg.name === "string" && !pkg.name.trim()) {
3499
+ errors.push("package.json \u7684 name \u5B57\u6BB5\u4E3A\u7A7A");
3500
+ }
3501
+ if (typeof pkg.description === "string" && pkg.description.length > DESC_MAX) {
3502
+ errors.push(`package.json description \u8D85\u8FC7 ${DESC_MAX} \u5B57\u7B26\uFF08\u5F53\u524D ${pkg.description.length}\uFF09`);
3503
+ }
3504
+ if (pkg.category && !VALID_CATEGORIES.includes(pkg.category)) {
3505
+ warnings.push(`package.json category "${pkg.category}" \u4E0D\u5728\u6709\u6548\u5217\u8868\u5185\uFF0C\u5C06\u964D\u7EA7\u4E3A "other"\uFF08\u6709\u6548\u503C: ${VALID_CATEGORIES.join(", ")}\uFF09`);
3506
+ }
3507
+ }
3508
+ return { errors, warnings };
3509
+ }
3510
+ async function validateAction(dir, options) {
3511
+ const target = path5.resolve(dir || ".");
3464
3512
  if (!fs5.existsSync(target) || !fs5.statSync(target).isDirectory()) {
3465
3513
  console.error(`\u274C \u76EE\u5F55\u4E0D\u5B58\u5728: ${target}`);
3466
- process.exit(1);
3514
+ process.exit(EXIT2.NOT_FOUND);
3467
3515
  }
3468
- const skillMdPath = SKILL_MD_NAMES.map((n) => path5.join(target, n)).find((p) => fs5.existsSync(p));
3469
- if (!skillMdPath) {
3470
- errors.push("\u7F3A\u5C11 SKILL.md \u6587\u4EF6");
3471
- } else {
3472
- const content = fs5.readFileSync(skillMdPath, "utf-8");
3473
- const meta = parseSkillMeta(content);
3474
- if (!meta.name)
3475
- warnings.push("SKILL.md \u7F3A\u5C11 name \u5B57\u6BB5\uFF08\u5EFA\u8BAE\u5728 frontmatter \u4E2D\u6DFB\u52A0\uFF09");
3476
- if (!meta.description)
3477
- warnings.push("SKILL.md \u7F3A\u5C11 description \u5B57\u6BB5");
3478
- if (content.length < 50)
3479
- warnings.push("SKILL.md \u5185\u5BB9\u8FC7\u77ED\uFF08\u5C11\u4E8E 50 \u5B57\u7B26\uFF09\uFF0C\u5EFA\u8BAE\u8865\u5145\u8BF4\u660E");
3480
- if (content.length > 5e4)
3481
- warnings.push(`SKILL.md \u8FC7\u5927\uFF08${Math.round(content.length / 1024)}KB\uFF09\uFF0C\u5EFA\u8BAE\u7CBE\u7B80`);
3516
+ const { errors, warnings } = validateSkillDir2(target);
3517
+ const passed = errors.length === 0;
3518
+ if (options.json) {
3519
+ console.log(JSON.stringify({ path: target, passed, errors, warnings }, null, 2));
3520
+ if (!passed)
3521
+ process.exit(EXIT2.VALIDATION);
3522
+ return;
3482
3523
  }
3483
- if (errors.length) {
3484
- console.log(`\u274C \u9A8C\u8BC1\u5931\u8D25 (${errors.length} \u4E2A\u9519\u8BEF)
3524
+ console.log(`\u{1F50D} \u6821\u9A8C\u76EE\u5F55: ${target}
3485
3525
  `);
3486
- errors.forEach((e) => console.log(` \u{1F534} ${e}`));
3526
+ if (errors.length) {
3527
+ console.log("\u274C \u9519\u8BEF\uFF08\u963B\u6B62\u53D1\u5E03\uFF09:");
3528
+ for (const e of errors)
3529
+ console.log(` \u2022 ${e}`);
3530
+ }
3531
+ if (warnings.length) {
3532
+ if (errors.length)
3533
+ console.log("");
3534
+ console.log("\u{1F7E1} \u8B66\u544A\uFF08\u5EFA\u8BAE\u4FEE\u590D\uFF09:");
3535
+ for (const w of warnings)
3536
+ console.log(` \u2022 ${w}`);
3537
+ }
3538
+ if (passed) {
3539
+ const warnSuffix = warnings.length ? `\uFF0C${warnings.length} \u4E2A\u8B66\u544A` : "";
3540
+ console.log(`
3541
+ \u2705 \u6821\u9A8C\u901A\u8FC7${warnSuffix}`);
3487
3542
  } else {
3488
- console.log(`\u2705 \u9A8C\u8BC1\u901A\u8FC7${warnings.length ? ` (${warnings.length} \u4E2A\u8B66\u544A)` : ""}
3489
- `);
3543
+ console.log(`
3544
+ \u274C \u6821\u9A8C\u5931\u8D25\uFF08${errors.length} \u4E2A\u9519\u8BEF\uFF09`);
3545
+ process.exit(EXIT2.VALIDATION);
3490
3546
  }
3547
+ }
3548
+
3549
+ // src/commands/init.ts
3550
+ var fs6 = __toESM(require("fs"));
3551
+ var path6 = __toESM(require("path"));
3552
+ var SKILL_MD_TEMPLATE = (name) => `# ${name}
3553
+
3554
+ \u4E00\u53E5\u8BDD\u8BF4\u660E\u8FD9\u4E2A\u6280\u80FD\u7684\u7528\u9014\u548C\u9002\u7528\u573A\u666F\u3002
3555
+
3556
+ ## \u529F\u80FD
3557
+
3558
+ - \u529F\u80FD\u70B9 1
3559
+ - \u529F\u80FD\u70B9 2
3560
+ - \u529F\u80FD\u70B9 3
3561
+
3562
+ ## \u4F7F\u7528\u65B9\u6CD5
3563
+
3564
+ \u63CF\u8FF0 Agent \u5982\u4F55\u8C03\u7528\u8FD9\u4E2A\u6280\u80FD\uFF0C\u5305\u62EC\uFF1A
3565
+ - \u9700\u8981\u63D0\u4F9B\u54EA\u4E9B\u8F93\u5165
3566
+ - \u4F1A\u8FD4\u56DE\u4EC0\u4E48\u8F93\u51FA
3567
+ - \u6709\u54EA\u4E9B\u9650\u5236\u6216\u524D\u7F6E\u6761\u4EF6
3568
+
3569
+ ## \u793A\u4F8B
3570
+
3571
+ **\u8F93\u5165\uFF1A**
3572
+
3573
+ \u793A\u4F8B\u8F93\u5165\u5185\u5BB9
3574
+
3575
+ **\u8F93\u51FA\uFF1A**
3576
+
3577
+ \u793A\u4F8B\u8F93\u51FA\u5185\u5BB9
3578
+
3579
+ ## \u6CE8\u610F\u4E8B\u9879
3580
+
3581
+ - \u6CE8\u610F\u4E8B\u9879 1
3582
+ - \u6CE8\u610F\u4E8B\u9879 2
3583
+ `;
3584
+ var PKG_TEMPLATE = (name) => JSON.stringify({
3585
+ name,
3586
+ version: "1.0.0",
3587
+ description: "\u8BF7\u586B\u5199\u6280\u80FD\u63CF\u8FF0"
3588
+ }, null, 2) + "\n";
3589
+ async function skillInitAction(name, options) {
3590
+ if (!/^[a-z0-9-]+$/.test(name)) {
3591
+ console.error("\u274C \u6280\u80FD\u540D\u79F0\u53EA\u80FD\u5305\u542B\u5C0F\u5199\u5B57\u6BCD\u3001\u6570\u5B57\u548C\u8FDE\u5B57\u7B26\uFF0C\u4F8B\u5982: my-skill");
3592
+ process.exit(EXIT2.VALIDATION);
3593
+ }
3594
+ const dir = path6.resolve(name);
3595
+ if (fs6.existsSync(dir)) {
3596
+ if (!options.force) {
3597
+ console.error(`\u274C \u76EE\u5F55\u5DF2\u5B58\u5728: ${dir}
3598
+ \u4F7F\u7528 --force \u8986\u76D6`);
3599
+ process.exit(EXIT2.VALIDATION);
3600
+ }
3601
+ } else {
3602
+ fs6.mkdirSync(dir, { recursive: true });
3603
+ }
3604
+ fs6.writeFileSync(path6.join(dir, "SKILL.md"), SKILL_MD_TEMPLATE(name), "utf-8");
3605
+ fs6.writeFileSync(path6.join(dir, "package.json"), PKG_TEMPLATE(name), "utf-8");
3606
+ console.log(`\u2705 \u6280\u80FD\u76EE\u5F55\u5DF2\u521B\u5EFA: ${dir}
3607
+ `);
3608
+ console.log(" \u{1F4C4} SKILL.md \u2014 \u586B\u5199\u6280\u80FD\u8BF4\u660E\u6587\u6863");
3609
+ console.log(" \u{1F4E6} package.json \u2014 \u586B\u5199 name / description\n");
3610
+ console.log("\u63A5\u4E0B\u6765\uFF1A");
3611
+ console.log(` 1. cd ${name}`);
3612
+ console.log(" 2. \u7F16\u8F91 SKILL.md \u548C package.json");
3613
+ console.log(" 3. ecl validate # \u53D1\u5E03\u524D\u6821\u9A8C");
3614
+ console.log(" 4. ecl publish # \u53D1\u5E03\u5230\u5E73\u53F0");
3615
+ console.log("\n\u521D\u59CB\u6821\u9A8C\uFF1A");
3616
+ const { errors, warnings } = validateSkillDir2(dir);
3491
3617
  if (warnings.length) {
3492
- warnings.forEach((w) => console.log(` \u{1F7E1} ${w}`));
3618
+ for (const w of warnings)
3619
+ console.log(` \u{1F7E1} ${w}`);
3493
3620
  }
3494
3621
  if (!errors.length) {
3495
- const skillMdContent = skillMdPath ? fs5.readFileSync(skillMdPath, "utf-8") : "";
3496
- const meta = parseSkillMeta(skillMdContent);
3497
- if (meta.name)
3498
- console.log(`
3499
- \u6280\u80FD\u540D\u79F0: ${meta.name}`);
3500
- if (meta.description)
3501
- console.log(`\u63CF\u8FF0: ${meta.description}`);
3502
- }
3503
- process.exit(errors.length ? 1 : 0);
3622
+ console.log(" \u2705 \u6A21\u677F\u7ED3\u6784\u5408\u6CD5\uFF0C\u586B\u597D\u5185\u5BB9\u5373\u53EF\u53D1\u5E03");
3623
+ }
3504
3624
  }
3505
3625
 
3506
3626
  // src/commands/skill.ts
3507
- var fs6 = __toESM(require("fs"));
3508
- var path6 = __toESM(require("path"));
3627
+ var fs7 = __toESM(require("fs"));
3628
+ var path7 = __toESM(require("path"));
3509
3629
  var readline3 = __toESM(require("readline"));
3510
3630
  function promptYN(question) {
3511
3631
  const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
3512
- return new Promise((resolve4) => {
3632
+ return new Promise((resolve5) => {
3513
3633
  rl.question(question, (ans) => {
3514
3634
  rl.close();
3515
- resolve4(ans.trim().toLowerCase() === "y" || ans.trim().toLowerCase() === "yes");
3635
+ resolve5(ans.trim().toLowerCase() === "y" || ans.trim().toLowerCase() === "yes");
3516
3636
  });
3517
3637
  });
3518
3638
  }
@@ -3571,12 +3691,12 @@ async function skillDownloadAction(id, options) {
3571
3691
  await assertOk(res);
3572
3692
  const buffer = Buffer.from(await res.arrayBuffer());
3573
3693
  const outPath = options.out || `skill-${id}.zip`;
3574
- const resolved = path6.resolve(outPath);
3575
- const dir = path6.dirname(resolved);
3576
- if (!fs6.existsSync(dir)) {
3577
- fs6.mkdirSync(dir, { recursive: true });
3694
+ const resolved = path7.resolve(outPath);
3695
+ const dir = path7.dirname(resolved);
3696
+ if (!fs7.existsSync(dir)) {
3697
+ fs7.mkdirSync(dir, { recursive: true });
3578
3698
  }
3579
- fs6.writeFileSync(resolved, buffer);
3699
+ fs7.writeFileSync(resolved, buffer);
3580
3700
  if (options.json) {
3581
3701
  console.log(JSON.stringify({ success: true, path: resolved, size: buffer.length }));
3582
3702
  return;
@@ -3615,7 +3735,7 @@ async function skillUseAction(id, options) {
3615
3735
  async function skillSearchAction(keyword, options) {
3616
3736
  if (!keyword?.trim()) {
3617
3737
  console.error("\u274C \u8BF7\u63D0\u4F9B\u641C\u7D22\u5173\u952E\u8BCD");
3618
- process.exit(EXIT.VALIDATION);
3738
+ process.exit(EXIT2.VALIDATION);
3619
3739
  }
3620
3740
  const apiKey = requireApiKey();
3621
3741
  const parsed = parseInt(options.limit || "20", 10);
@@ -3653,7 +3773,7 @@ async function skillSearchAction(keyword, options) {
3653
3773
  }
3654
3774
 
3655
3775
  // src/commands/bounty.ts
3656
- var fs7 = __toESM(require("fs"));
3776
+ var fs8 = __toESM(require("fs"));
3657
3777
  async function bountyListAction(options) {
3658
3778
  const apiKey = requireApiKey();
3659
3779
  const status = options.status || "open";
@@ -3747,17 +3867,17 @@ async function bountySubmitAction(id, content, options) {
3747
3867
  let body = content;
3748
3868
  if (content.startsWith("@")) {
3749
3869
  const filePath = content.slice(1);
3750
- if (!fs7.existsSync(filePath)) {
3870
+ if (!fs8.existsSync(filePath)) {
3751
3871
  console.error(`\u274C \u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}`);
3752
3872
  process.exit(1);
3753
3873
  }
3754
- const stat = fs7.statSync(filePath);
3874
+ const stat = fs8.statSync(filePath);
3755
3875
  const MAX_SIZE = 512 * 1024;
3756
3876
  if (stat.size > MAX_SIZE) {
3757
3877
  console.error(`\u274C \u6587\u4EF6\u8FC7\u5927\uFF08${Math.round(stat.size / 1024)}KB\uFF09\uFF0C\u4E0A\u9650 512KB`);
3758
3878
  process.exit(1);
3759
3879
  }
3760
- body = fs7.readFileSync(filePath, "utf-8");
3880
+ body = fs8.readFileSync(filePath, "utf-8");
3761
3881
  }
3762
3882
  if (!body.trim()) {
3763
3883
  console.error("\u274C \u63D0\u4EA4\u5185\u5BB9\u4E0D\u80FD\u4E3A\u7A7A");
@@ -4273,7 +4393,7 @@ async function saasPolishAction(text, options) {
4273
4393
  }
4274
4394
 
4275
4395
  // src/commands/agent.ts
4276
- var fs8 = __toESM(require("fs"));
4396
+ var fs9 = __toESM(require("fs"));
4277
4397
  async function agentListAction(options) {
4278
4398
  const apiKey = requireApiKey();
4279
4399
  const parsed = parseInt(options.limit || "20", 10);
@@ -4310,17 +4430,17 @@ async function agentCallAction(username, intent, dataJson, options = {}) {
4310
4430
  }
4311
4431
  const body = { intent };
4312
4432
  if (options.dataFile) {
4313
- if (!fs8.existsSync(options.dataFile)) {
4433
+ if (!fs9.existsSync(options.dataFile)) {
4314
4434
  console.error(`\u274C \u6587\u4EF6\u4E0D\u5B58\u5728: ${options.dataFile}`);
4315
4435
  process.exit(1);
4316
4436
  }
4317
4437
  const MAX_SIZE = 512 * 1024;
4318
- const stat = fs8.statSync(options.dataFile);
4438
+ const stat = fs9.statSync(options.dataFile);
4319
4439
  if (stat.size > MAX_SIZE) {
4320
4440
  console.error(`\u274C \u6587\u4EF6\u8FC7\u5927\uFF08${Math.round(stat.size / 1024)}KB\uFF09\uFF0C\u4E0A\u9650 512KB`);
4321
4441
  process.exit(1);
4322
4442
  }
4323
- const raw = fs8.readFileSync(options.dataFile, "utf-8");
4443
+ const raw = fs9.readFileSync(options.dataFile, "utf-8");
4324
4444
  try {
4325
4445
  body.data = JSON.parse(raw);
4326
4446
  } catch {
@@ -4354,14 +4474,14 @@ async function agentCallAction(username, intent, dataJson, options = {}) {
4354
4474
  }
4355
4475
 
4356
4476
  // src/commands/forum.ts
4357
- var fs9 = __toESM(require("fs"));
4477
+ var fs10 = __toESM(require("fs"));
4358
4478
  var readline6 = __toESM(require("readline"));
4359
4479
  function promptYN2(question) {
4360
4480
  const rl = readline6.createInterface({ input: process.stdin, output: process.stdout });
4361
- return new Promise((resolve4) => {
4481
+ return new Promise((resolve5) => {
4362
4482
  rl.question(question, (ans) => {
4363
4483
  rl.close();
4364
- resolve4(ans.trim().toLowerCase() === "y" || ans.trim().toLowerCase() === "yes");
4484
+ resolve5(ans.trim().toLowerCase() === "y" || ans.trim().toLowerCase() === "yes");
4365
4485
  });
4366
4486
  });
4367
4487
  }
@@ -4420,11 +4540,11 @@ async function forumPostAction(title, filePath, options) {
4420
4540
  if (options.content) {
4421
4541
  content = options.content;
4422
4542
  } else if (filePath) {
4423
- if (!fs9.existsSync(filePath)) {
4543
+ if (!fs10.existsSync(filePath)) {
4424
4544
  console.error(`\u274C \u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}`);
4425
4545
  process.exit(1);
4426
4546
  }
4427
- content = fs9.readFileSync(filePath, "utf-8");
4547
+ content = fs10.readFileSync(filePath, "utf-8");
4428
4548
  } else {
4429
4549
  console.error("\u274C \u8BF7\u63D0\u4F9B --content <text> \u6216 <file> \u53C2\u6570");
4430
4550
  process.exit(1);
@@ -4498,8 +4618,8 @@ async function forumDeleteAction(slug, options) {
4498
4618
  }
4499
4619
 
4500
4620
  // src/commands/radio.ts
4501
- var fs10 = __toESM(require("fs"));
4502
- var path7 = __toESM(require("path"));
4621
+ var fs11 = __toESM(require("fs"));
4622
+ var path8 = __toESM(require("path"));
4503
4623
  async function radioListAction(options) {
4504
4624
  const apiKey = requireApiKey();
4505
4625
  const res = await fetchWithRetry(`${BASE_URL}/api/radio/stations`, {
@@ -4592,20 +4712,20 @@ async function radioCreateAction(name, options) {
4592
4712
  }
4593
4713
  async function radioUploadAction(stationId, filePath, options) {
4594
4714
  const apiKey = requireApiKey();
4595
- if (!fs10.existsSync(filePath)) {
4715
+ if (!fs11.existsSync(filePath)) {
4596
4716
  console.error(`\u274C \u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}`);
4597
4717
  process.exit(1);
4598
4718
  }
4599
4719
  const MAX_SIZE = 5 * 1024 * 1024;
4600
- const stat = fs10.statSync(filePath);
4720
+ const stat = fs11.statSync(filePath);
4601
4721
  if (stat.size > MAX_SIZE) {
4602
4722
  console.error(`\u274C \u6587\u4EF6\u8FC7\u5927\uFF08${Math.round(stat.size / 1024 / 1024 * 10) / 10}MB\uFF09\uFF0C\u4E0A\u9650 5MB`);
4603
4723
  process.exit(1);
4604
4724
  }
4605
- const title = options.title || path7.basename(filePath, path7.extname(filePath));
4725
+ const title = options.title || path8.basename(filePath, path8.extname(filePath));
4606
4726
  const formData = new FormData();
4607
- const blob = new Blob([fs10.readFileSync(filePath)]);
4608
- formData.append("file", blob, path7.basename(filePath));
4727
+ const blob = new Blob([fs11.readFileSync(filePath)]);
4728
+ formData.append("file", blob, path8.basename(filePath));
4609
4729
  formData.append("title", title);
4610
4730
  if (options.artist)
4611
4731
  formData.append("artist", options.artist);
@@ -4640,7 +4760,7 @@ async function radioUploadAction(stationId, filePath, options) {
4640
4760
 
4641
4761
  // src/index.ts
4642
4762
  var program2 = new Command();
4643
- 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.6.0");
4763
+ 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.7.1");
4644
4764
  program2.command("login").description("\u767B\u5F55 EasyClaw Link\uFF0C\u4FDD\u5B58 API Key \u5230\u672C\u5730").action(loginAction);
4645
4765
  program2.command("logout").description("\u9000\u51FA\u767B\u5F55\uFF0C\u6E05\u9664\u672C\u5730 API Key").action(logoutAction);
4646
4766
  program2.command("whoami").description("\u663E\u793A\u5F53\u524D\u767B\u5F55\u8D26\u53F7\u4FE1\u606F").option("--json", "JSON \u8F93\u51FA").action(() => whoamiAction());
@@ -4649,13 +4769,14 @@ program2.command("unread").description("\u67E5\u770B\u672A\u8BFB\u6D88\u606F/\u9
4649
4769
  program2.command("stats").description("\u67E5\u770B\u5E73\u53F0\u7EDF\u8BA1\u6570\u636E").option("--json", "JSON \u8F93\u51FA").action((o) => statsAction(o));
4650
4770
  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));
4651
4771
  var profileCmd = program2.command("profile").description("\u4E2A\u4EBA\u8D44\u6599\u64CD\u4F5C");
4652
- 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));
4772
+ profileCmd.command("update").description("\u66F4\u65B0\u4E2A\u4EBA\u8D44\u6599").option("--display-name <name>", "\u663E\u793A\u540D\u79F0\uFF08\u6700\u591A50\u5B57\uFF0C\u7A7A\u5B57\u7B26\u4E32\u53EF\u6E05\u9664\uFF09").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));
4653
4773
  var notifCmd = program2.command("notifications").description("\u67E5\u770B\u548C\u7BA1\u7406\u901A\u77E5");
4654
4774
  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));
4655
4775
  notifCmd.command("read").description("\u6807\u8BB0\u6240\u6709\u901A\u77E5\u4E3A\u5DF2\u8BFB").option("--json", "JSON \u8F93\u51FA").action((o) => notificationsReadAction(o));
4656
4776
  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);
4657
4777
  program2.command("list").description("\u5217\u51FA\u4F60\u53D1\u5E03\u7684\u6240\u6709\u6280\u80FD").option("--json", "JSON \u8F93\u51FA").action(() => listAction());
4658
- program2.command("validate [dir]").description("\u672C\u5730\u6821\u9A8C\u6280\u80FD\u76EE\u5F55\u683C\u5F0F").action((dir) => validateAction(dir));
4778
+ program2.command("validate [dir]").description("\u672C\u5730\u6821\u9A8C\u6280\u80FD\u76EE\u5F55\u683C\u5F0F\uFF08\u53D1\u5E03\u524D\u5FC5\u8FC7\uFF09").option("--json", "JSON \u8F93\u51FA").action((dir, o) => validateAction(dir, o));
4779
+ program2.command("skill-init <name>").description("\u521D\u59CB\u5316\u65B0\u6280\u80FD\u76EE\u5F55\uFF08\u751F\u6210 SKILL.md + package.json \u6A21\u677F\uFF09").option("--force", "\u8986\u76D6\u5DF2\u6709\u76EE\u5F55").action((name, o) => skillInitAction(name, o));
4659
4780
  var skillCmd = program2.command("skill").description("\u6280\u80FD\u8BE6\u7EC6\u64CD\u4F5C");
4660
4781
  skillCmd.command("search <keyword>").description("\u641C\u7D22\u5E73\u53F0\u6280\u80FD").option("--limit <n>", "\u6761\u6570\u9650\u5236", "20").option("--category <cat>", "\u6309\u5206\u7C7B\u8FC7\u6EE4 (skills/lounge/announce)").option("--grade <grade>", "\u6309\u8BC4\u7EA7\u8FC7\u6EE4 (S/A/B/C)").option("--json", "JSON \u8F93\u51FA").action((kw, o) => skillSearchAction(kw, o));
4661
4782
  skillCmd.command("view <id>").description("\u67E5\u770B\u6280\u80FD\u8BE6\u60C5").option("--json", "JSON \u8F93\u51FA").action((id, o) => skillViewAction(id, o));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "easyclaw-link",
3
- "version": "1.6.0",
3
+ "version": "1.7.1",
4
4
  "description": "EasyClaw Link CLI - Publish and manage skills on easyclaw.link",
5
5
  "main": "dist/index.js",
6
6
  "bin": {