easyclaw-link 1.8.0 → 1.9.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 +277 -164
  2. package/package.json +2 -2
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 path9 = require("path");
935
- var fs12 = require("fs");
934
+ var path8 = require("path");
935
+ var fs11 = 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 = path9.resolve(baseDir, baseName);
1768
- if (fs12.existsSync(localBin))
1767
+ const localBin = path8.resolve(baseDir, baseName);
1768
+ if (fs11.existsSync(localBin))
1769
1769
  return localBin;
1770
- if (sourceExt.includes(path9.extname(baseName)))
1770
+ if (sourceExt.includes(path8.extname(baseName)))
1771
1771
  return void 0;
1772
- const foundExt = sourceExt.find((ext) => fs12.existsSync(`${localBin}${ext}`));
1772
+ const foundExt = sourceExt.find((ext) => fs11.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 = fs12.realpathSync(this._scriptPath);
1784
+ resolvedScriptPath = fs11.realpathSync(this._scriptPath);
1785
1785
  } catch (err) {
1786
1786
  resolvedScriptPath = this._scriptPath;
1787
1787
  }
1788
- executableDir = path9.resolve(path9.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 = path9.basename(this._scriptPath, path9.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(path9.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 = path9.basename(filename, path9.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(path10) {
2617
- if (path10 === void 0)
2616
+ executableDir(path9) {
2617
+ if (path9 === void 0)
2618
2618
  return this._executableDir;
2619
- this._executableDir = path10;
2619
+ this._executableDir = path9;
2620
2620
  return this;
2621
2621
  }
2622
2622
  /**
@@ -2982,31 +2982,103 @@ async function logoutAction() {
2982
2982
  var fs4 = __toESM(require("fs"));
2983
2983
  var path4 = __toESM(require("path"));
2984
2984
 
2985
- // src/validate.ts
2985
+ // src/commands/validate.ts
2986
2986
  var fs3 = __toESM(require("fs"));
2987
2987
  var path3 = __toESM(require("path"));
2988
+ var VALID_CATEGORIES = ["system", "office", "creative", "data", "coding", "ai_agent", "tools", "other"];
2989
+ var SKILL_MD_MAX = 5e4;
2990
+ var SKILL_MD_WARN_MIN = 200;
2991
+ var SKILL_MD_WARN_MAX = 2e4;
2992
+ var DESC_MAX = 1e3;
2988
2993
  function validateSkillDir(dir) {
2989
2994
  const errors = [];
2990
- const skillPath = path3.join(dir, "SKILL.md");
2991
- if (!fs3.existsSync(skillPath)) {
2992
- errors.push("\u7F3A\u5C11 SKILL.md \u6587\u4EF6");
2995
+ const warnings = [];
2996
+ const skillMdPath = path3.join(dir, "SKILL.md");
2997
+ const pkgPath = path3.join(dir, "package.json");
2998
+ if (!fs3.existsSync(skillMdPath)) {
2999
+ errors.push("SKILL.md \u4E0D\u5B58\u5728");
2993
3000
  } else {
2994
- const content = fs3.readFileSync(skillPath, "utf-8");
3001
+ const content = fs3.readFileSync(skillMdPath, "utf-8");
2995
3002
  const trimmed = content.trim();
2996
3003
  if (!trimmed) {
2997
- errors.push("SKILL.md \u6587\u4EF6\u4E3A\u7A7A");
3004
+ errors.push("SKILL.md \u4E3A\u7A7A");
2998
3005
  } else {
2999
- const lines = content.split("\n");
3000
- const hasHeading = lines.some((line) => /^#{1,6}\s/.test(line));
3001
- if (!hasHeading) {
3002
- errors.push("SKILL.md \u7F3A\u5C11\u6807\u9898\u884C\uFF08\u9700\u8981\u4EE5 # \u5F00\u5934\u7684\u884C\uFF0C\u5982 # \u6280\u80FD\u540D\u79F0\uFF09");
3006
+ if (!/^#\s+\S/m.test(content)) {
3007
+ errors.push("SKILL.md \u7F3A\u5C11 # \u6807\u9898\u884C\uFF08\u81F3\u5C11\u4E00\u884C\u4EE5 # \u5F00\u5934\uFF09");
3008
+ }
3009
+ if (content.length > SKILL_MD_MAX) {
3010
+ errors.push(`SKILL.md \u8D85\u8FC7 ${SKILL_MD_MAX} \u5B57\u7B26\uFF08\u5F53\u524D ${content.length}\uFF09\uFF0C\u540E\u7AEF\u4F1A\u62D2\u7EDD`);
3011
+ }
3012
+ if (trimmed.length < SKILL_MD_WARN_MIN) {
3013
+ warnings.push(`SKILL.md \u5185\u5BB9\u8F83\u77ED\uFF08${trimmed.length} \u5B57\u7B26\uFF0C\u5EFA\u8BAE \u2265${SKILL_MD_WARN_MIN}\uFF09`);
3014
+ }
3015
+ if (!/##?\s*(使用方法|用法|usage|how to use)/i.test(content)) {
3016
+ warnings.push('SKILL.md \u7F3A\u5C11"\u4F7F\u7528\u65B9\u6CD5"\u7AE0\u8282\uFF08Agent \u9700\u8981\u77E5\u9053\u5982\u4F55\u8C03\u7528\uFF09');
3017
+ }
3018
+ if (content.length > SKILL_MD_WARN_MAX) {
3019
+ 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`);
3003
3020
  }
3004
3021
  }
3005
- if (content.length > 5e4) {
3006
- errors.push("SKILL.md \u8D85\u8FC7 50000 \u5B57\u7B26\u9650\u5236");
3022
+ }
3023
+ if (!fs3.existsSync(pkgPath)) {
3024
+ warnings.push("package.json \u4E0D\u5B58\u5728\uFF0C\u6280\u80FD\u6807\u9898\u5C06\u964D\u7EA7\u4E3A\u76EE\u5F55\u540D");
3025
+ } else {
3026
+ let pkg;
3027
+ try {
3028
+ pkg = JSON.parse(fs3.readFileSync(pkgPath, "utf-8"));
3029
+ } catch {
3030
+ errors.push("package.json JSON \u8BED\u6CD5\u9519\u8BEF");
3031
+ return { errors, warnings };
3032
+ }
3033
+ if (!pkg.name || typeof pkg.name === "string" && !pkg.name.trim()) {
3034
+ errors.push("package.json \u7684 name \u5B57\u6BB5\u4E3A\u7A7A");
3035
+ }
3036
+ if (typeof pkg.description === "string" && pkg.description.length > DESC_MAX) {
3037
+ errors.push(`package.json description \u8D85\u8FC7 ${DESC_MAX} \u5B57\u7B26\uFF08\u5F53\u524D ${pkg.description.length}\uFF09`);
3007
3038
  }
3039
+ if (pkg.category && !VALID_CATEGORIES.includes(pkg.category)) {
3040
+ 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`);
3041
+ }
3042
+ }
3043
+ return { errors, warnings };
3044
+ }
3045
+ async function validateAction(dir, options) {
3046
+ const target = path3.resolve(dir || ".");
3047
+ if (!fs3.existsSync(target) || !fs3.statSync(target).isDirectory()) {
3048
+ console.error(`\u274C \u76EE\u5F55\u4E0D\u5B58\u5728: ${target}`);
3049
+ process.exit(EXIT2.NOT_FOUND);
3050
+ }
3051
+ const { errors, warnings } = validateSkillDir(target);
3052
+ const passed = errors.length === 0;
3053
+ if (options.json) {
3054
+ console.log(JSON.stringify({ path: target, passed, errors, warnings }, null, 2));
3055
+ if (!passed)
3056
+ process.exit(EXIT2.VALIDATION);
3057
+ return;
3058
+ }
3059
+ console.log(`\u{1F50D} \u6821\u9A8C\u76EE\u5F55: ${target}
3060
+ `);
3061
+ if (errors.length) {
3062
+ console.log("\u274C \u9519\u8BEF\uFF08\u963B\u6B62\u53D1\u5E03\uFF09:");
3063
+ for (const e of errors)
3064
+ console.log(` \u2022 ${e}`);
3065
+ }
3066
+ if (warnings.length) {
3067
+ if (errors.length)
3068
+ console.log("");
3069
+ console.log("\u{1F7E1} \u8B66\u544A\uFF08\u5EFA\u8BAE\u4FEE\u590D\uFF09:");
3070
+ for (const w of warnings)
3071
+ console.log(` \u2022 ${w}`);
3072
+ }
3073
+ if (passed) {
3074
+ const warnSuffix = warnings.length ? `\uFF0C${warnings.length} \u4E2A\u8B66\u544A` : "";
3075
+ console.log(`
3076
+ \u2705 \u6821\u9A8C\u901A\u8FC7${warnSuffix}`);
3077
+ } else {
3078
+ console.log(`
3079
+ \u274C \u6821\u9A8C\u5931\u8D25\uFF08${errors.length} \u4E2A\u9519\u8BEF\uFF09`);
3080
+ process.exit(EXIT2.VALIDATION);
3008
3081
  }
3009
- return { valid: errors.length === 0, errors };
3010
3082
  }
3011
3083
 
3012
3084
  // src/commands/publish.ts
@@ -3035,11 +3107,15 @@ async function resolveId(apiKey, slug) {
3035
3107
  async function publishAction(dir, options) {
3036
3108
  const apiKey = requireApiKey();
3037
3109
  const targetDir = path4.resolve(dir || ".");
3038
- const { valid, errors } = validateSkillDir(targetDir);
3039
- if (!valid) {
3040
- console.error("\u274C \u6821\u9A8C\u5931\u8D25\uFF1A");
3110
+ const { errors, warnings } = validateSkillDir(targetDir);
3111
+ if (errors.length) {
3112
+ console.error("\u274C \u672C\u5730\u6821\u9A8C\u5931\u8D25\uFF1A");
3041
3113
  errors.forEach((e) => console.error(` \u2022 ${e}`));
3042
- process.exit(1);
3114
+ process.exit(EXIT2.VALIDATION);
3115
+ }
3116
+ if (warnings.length) {
3117
+ console.log("\u{1F7E1} \u6821\u9A8C\u8B66\u544A\uFF08\u4E0D\u963B\u6B62\u53D1\u5E03\uFF09:");
3118
+ warnings.forEach((w) => console.log(` \u2022 ${w}`));
3043
3119
  }
3044
3120
  const content = fs4.readFileSync(path4.join(targetDir, "SKILL.md"), "utf-8");
3045
3121
  let pkgName;
@@ -3057,6 +3133,27 @@ async function publishAction(dir, options) {
3057
3133
  }
3058
3134
  const title = pkgName || path4.basename(targetDir);
3059
3135
  const description = pkgDescription || title;
3136
+ if (options.dryRun) {
3137
+ console.log("\u23F3 \u540E\u7AEF\u6821\u9A8C\uFF08dry run\uFF0C\u4E0D\u5199\u5E93\uFF09...");
3138
+ const res = await fetchWithRetry(
3139
+ `${BASE_URL}/api/assets?dry_run=true`,
3140
+ {
3141
+ method: "POST",
3142
+ headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
3143
+ body: JSON.stringify({ title, content, description, category: "other" })
3144
+ }
3145
+ );
3146
+ await assertOk(res);
3147
+ const data = await res.json();
3148
+ if (data.valid) {
3149
+ console.log("\u2705 \u540E\u7AEF\u6821\u9A8C\u901A\u8FC7\uFF0C\u53EF\u4EE5\u53D1\u5E03");
3150
+ if (data.preview) {
3151
+ console.log(` \u6807\u9898: ${data.preview.title}`);
3152
+ console.log(` \u5206\u7C7B: ${data.preview.category}`);
3153
+ }
3154
+ }
3155
+ return;
3156
+ }
3060
3157
  let resolvedId = options.id;
3061
3158
  if (!resolvedId && options.slug) {
3062
3159
  const numId = await resolveId(apiKey, options.slug);
@@ -3343,6 +3440,118 @@ async function notificationsReadAction(options) {
3343
3440
  console.log("\u2705 \u6240\u6709\u901A\u77E5\u5DF2\u6807\u8BB0\u4E3A\u5DF2\u8BFB");
3344
3441
  }
3345
3442
 
3443
+ // src/commands/a2a.ts
3444
+ async function a2aLogsAction(options) {
3445
+ const apiKey = requireApiKey();
3446
+ const params = new URLSearchParams();
3447
+ if (options.asCaller)
3448
+ params.set("role", "caller");
3449
+ if (options.intent)
3450
+ params.set("intent", options.intent);
3451
+ if (options.status)
3452
+ params.set("status", options.status);
3453
+ if (options.from)
3454
+ params.set("from", options.from);
3455
+ if (options.to)
3456
+ params.set("to", options.to);
3457
+ if (options.limit)
3458
+ params.set("limit", options.limit);
3459
+ const res = await fetchWithRetry(`${BASE_URL}/api/a2a/logs?${params}`, {
3460
+ headers: { Authorization: `Bearer ${apiKey}` }
3461
+ });
3462
+ await assertOk(res);
3463
+ const data = await res.json();
3464
+ if (options.json) {
3465
+ console.log(JSON.stringify(data, null, 2));
3466
+ return;
3467
+ }
3468
+ const logs = data.logs || [];
3469
+ if (!logs.length) {
3470
+ console.log("\u{1F4ED} \u6682\u65E0\u8C03\u7528\u8BB0\u5F55");
3471
+ return;
3472
+ }
3473
+ const role = data.role;
3474
+ console.log(`\u{1F4CB} A2A \u8C03\u7528\u8BB0\u5F55\uFF08${role === "caller" ? "\u6211\u53D1\u8D77\u7684" : "\u88AB\u8C03\u7528"}\uFF0C\u5171 ${logs.length} \u6761\uFF09
3475
+ `);
3476
+ console.log("\u65F6\u95F4 \u8C03\u7528\u65B9 \u88AB\u8C03\u65B9 \u610F\u56FE \u7ED3\u679C \u8017\u65F6");
3477
+ console.log("\u2500".repeat(110));
3478
+ for (const l of logs) {
3479
+ const time = String(l.created_at).replace("T", " ").slice(0, 16);
3480
+ const caller = String(l.caller_username || l.caller_ip || "anonymous").slice(0, 18).padEnd(18);
3481
+ const callee = String(l.callee_username || "-").slice(0, 18).padEnd(18);
3482
+ const intent = String(l.intent || "-").slice(0, 22).padEnd(22);
3483
+ const status = String(l.status || "-").padEnd(10);
3484
+ const latency = l.latency_ms != null ? `${l.latency_ms}ms` : "-";
3485
+ console.log(`${time} ${caller} ${callee} ${intent} ${status} ${latency}`);
3486
+ if (l.error_message)
3487
+ console.log(` \u26A0\uFE0F ${l.error_message}`);
3488
+ }
3489
+ }
3490
+ async function a2aPolicyAction(options) {
3491
+ const apiKey = requireApiKey();
3492
+ if (!options.set && !options.allow && !options.deny) {
3493
+ const res = await fetchWithRetry(`${BASE_URL}/api/auth/me`, {
3494
+ headers: { Authorization: `Bearer ${apiKey}` }
3495
+ });
3496
+ await assertOk(res);
3497
+ const { user } = await res.json();
3498
+ if (options.json) {
3499
+ console.log(JSON.stringify({ a2a_policy: user.a2a_policy, a2a_allowlist: user.a2a_allowlist }, null, 2));
3500
+ return;
3501
+ }
3502
+ const policy = String(user.a2a_policy || "open");
3503
+ const allowlist = user.a2a_allowlist || [];
3504
+ console.log(`\u{1F510} A2A \u8C03\u7528\u7B56\u7565: ${policy}`);
3505
+ if (policy === "allowlist") {
3506
+ if (options.list || allowlist.length) {
3507
+ console.log(` \u767D\u540D\u5355\uFF08${allowlist.length} \u4E2A\u7528\u6237 ID\uFF09: ${allowlist.join(", ") || "\uFF08\u7A7A\uFF09"}`);
3508
+ }
3509
+ }
3510
+ return;
3511
+ }
3512
+ if (options.set) {
3513
+ if (!["open", "allowlist", "closed"].includes(options.set)) {
3514
+ console.error("\u274C \u7B56\u7565\u503C\u5FC5\u987B\u662F open / allowlist / closed");
3515
+ process.exit(1);
3516
+ }
3517
+ const res = await fetchWithRetry(`${BASE_URL}/api/auth/me`, {
3518
+ method: "PATCH",
3519
+ headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
3520
+ body: JSON.stringify({ a2a_policy: options.set })
3521
+ });
3522
+ await assertOk(res);
3523
+ console.log(`\u2705 A2A \u7B56\u7565\u5DF2\u8BBE\u4E3A: ${options.set}`);
3524
+ }
3525
+ if (options.allow) {
3526
+ const addRes = await fetchWithRetry(`${BASE_URL}/api/auth/me`, {
3527
+ method: "PATCH",
3528
+ headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
3529
+ body: JSON.stringify({ a2a_allowlist_add_usernames: [options.allow] })
3530
+ });
3531
+ await assertOk(addRes);
3532
+ const addData = await addRes.json();
3533
+ if (addData.a2a_not_found?.length) {
3534
+ console.error(`\u26A0\uFE0F \u7528\u6237\u4E0D\u5B58\u5728\u6216\u5DF2\u88AB\u5C01\u7981\uFF1A${addData.a2a_not_found.map((u) => `@${u}`).join(", ")}`);
3535
+ } else {
3536
+ console.log(`\u2705 \u5DF2\u5C06 @${options.allow} \u52A0\u5165\u767D\u540D\u5355`);
3537
+ }
3538
+ }
3539
+ if (options.deny) {
3540
+ const removeRes = await fetchWithRetry(`${BASE_URL}/api/auth/me`, {
3541
+ method: "PATCH",
3542
+ headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
3543
+ body: JSON.stringify({ a2a_allowlist_remove_usernames: [options.deny] })
3544
+ });
3545
+ await assertOk(removeRes);
3546
+ const removeData = await removeRes.json();
3547
+ if ((removeData.a2a_allowlist_removed ?? 0) === 0) {
3548
+ console.log(`\u2139\uFE0F @${options.deny} \u4E0D\u5728\u767D\u540D\u5355\u4E2D\uFF0C\u65E0\u9700\u79FB\u9664`);
3549
+ } else {
3550
+ console.log(`\u2705 \u5DF2\u5C06 @${options.deny} \u4ECE\u767D\u540D\u5355\u79FB\u9664`);
3551
+ }
3552
+ }
3553
+ }
3554
+
3346
3555
  // src/commands/unread.ts
3347
3556
  async function unreadAction(options) {
3348
3557
  const apiKey = requireApiKey();
@@ -3447,108 +3656,9 @@ async function profileUpdateAction(options) {
3447
3656
  console.log(` Owner Email: ${body.owner_email || "(\u5DF2\u6E05\u9664)"}`);
3448
3657
  }
3449
3658
 
3450
- // src/commands/validate.ts
3659
+ // src/commands/init.ts
3451
3660
  var fs5 = __toESM(require("fs"));
3452
3661
  var path5 = __toESM(require("path"));
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) {
3459
- const errors = [];
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 || ".");
3512
- if (!fs5.existsSync(target) || !fs5.statSync(target).isDirectory()) {
3513
- console.error(`\u274C \u76EE\u5F55\u4E0D\u5B58\u5728: ${target}`);
3514
- process.exit(EXIT2.NOT_FOUND);
3515
- }
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;
3523
- }
3524
- console.log(`\u{1F50D} \u6821\u9A8C\u76EE\u5F55: ${target}
3525
- `);
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}`);
3542
- } else {
3543
- console.log(`
3544
- \u274C \u6821\u9A8C\u5931\u8D25\uFF08${errors.length} \u4E2A\u9519\u8BEF\uFF09`);
3545
- process.exit(EXIT2.VALIDATION);
3546
- }
3547
- }
3548
-
3549
- // src/commands/init.ts
3550
- var fs6 = __toESM(require("fs"));
3551
- var path6 = __toESM(require("path"));
3552
3662
  var SKILL_MD_TEMPLATE = (name) => `# ${name}
3553
3663
 
3554
3664
  \u4E00\u53E5\u8BDD\u8BF4\u660E\u8FD9\u4E2A\u6280\u80FD\u7684\u7528\u9014\u548C\u9002\u7528\u573A\u666F\u3002
@@ -3591,18 +3701,18 @@ async function skillInitAction(name, options) {
3591
3701
  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
3702
  process.exit(EXIT2.VALIDATION);
3593
3703
  }
3594
- const dir = path6.resolve(name);
3595
- if (fs6.existsSync(dir)) {
3704
+ const dir = path5.resolve(name);
3705
+ if (fs5.existsSync(dir)) {
3596
3706
  if (!options.force) {
3597
3707
  console.error(`\u274C \u76EE\u5F55\u5DF2\u5B58\u5728: ${dir}
3598
3708
  \u4F7F\u7528 --force \u8986\u76D6`);
3599
3709
  process.exit(EXIT2.VALIDATION);
3600
3710
  }
3601
3711
  } else {
3602
- fs6.mkdirSync(dir, { recursive: true });
3712
+ fs5.mkdirSync(dir, { recursive: true });
3603
3713
  }
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");
3714
+ fs5.writeFileSync(path5.join(dir, "SKILL.md"), SKILL_MD_TEMPLATE(name), "utf-8");
3715
+ fs5.writeFileSync(path5.join(dir, "package.json"), PKG_TEMPLATE(name), "utf-8");
3606
3716
  console.log(`\u2705 \u6280\u80FD\u76EE\u5F55\u5DF2\u521B\u5EFA: ${dir}
3607
3717
  `);
3608
3718
  console.log(" \u{1F4C4} SKILL.md \u2014 \u586B\u5199\u6280\u80FD\u8BF4\u660E\u6587\u6863");
@@ -3613,7 +3723,7 @@ async function skillInitAction(name, options) {
3613
3723
  console.log(" 3. ecl validate # \u53D1\u5E03\u524D\u6821\u9A8C");
3614
3724
  console.log(" 4. ecl publish # \u53D1\u5E03\u5230\u5E73\u53F0");
3615
3725
  console.log("\n\u521D\u59CB\u6821\u9A8C\uFF1A");
3616
- const { errors, warnings } = validateSkillDir2(dir);
3726
+ const { errors, warnings } = validateSkillDir(dir);
3617
3727
  if (warnings.length) {
3618
3728
  for (const w of warnings)
3619
3729
  console.log(` \u{1F7E1} ${w}`);
@@ -3624,8 +3734,8 @@ async function skillInitAction(name, options) {
3624
3734
  }
3625
3735
 
3626
3736
  // src/commands/skill.ts
3627
- var fs7 = __toESM(require("fs"));
3628
- var path7 = __toESM(require("path"));
3737
+ var fs6 = __toESM(require("fs"));
3738
+ var path6 = __toESM(require("path"));
3629
3739
  var readline3 = __toESM(require("readline"));
3630
3740
  function promptYN(question) {
3631
3741
  const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
@@ -3691,12 +3801,12 @@ async function skillDownloadAction(id, options) {
3691
3801
  await assertOk(res);
3692
3802
  const buffer = Buffer.from(await res.arrayBuffer());
3693
3803
  const outPath = options.out || `skill-${id}.zip`;
3694
- const resolved = path7.resolve(outPath);
3695
- const dir = path7.dirname(resolved);
3696
- if (!fs7.existsSync(dir)) {
3697
- fs7.mkdirSync(dir, { recursive: true });
3804
+ const resolved = path6.resolve(outPath);
3805
+ const dir = path6.dirname(resolved);
3806
+ if (!fs6.existsSync(dir)) {
3807
+ fs6.mkdirSync(dir, { recursive: true });
3698
3808
  }
3699
- fs7.writeFileSync(resolved, buffer);
3809
+ fs6.writeFileSync(resolved, buffer);
3700
3810
  if (options.json) {
3701
3811
  console.log(JSON.stringify({ success: true, path: resolved, size: buffer.length }));
3702
3812
  return;
@@ -3773,7 +3883,7 @@ async function skillSearchAction(keyword, options) {
3773
3883
  }
3774
3884
 
3775
3885
  // src/commands/bounty.ts
3776
- var fs8 = __toESM(require("fs"));
3886
+ var fs7 = __toESM(require("fs"));
3777
3887
  async function bountyListAction(options) {
3778
3888
  const apiKey = requireApiKey();
3779
3889
  const status = options.status || "open";
@@ -3867,17 +3977,17 @@ async function bountySubmitAction(id, content, options) {
3867
3977
  let body = content;
3868
3978
  if (content.startsWith("@")) {
3869
3979
  const filePath = content.slice(1);
3870
- if (!fs8.existsSync(filePath)) {
3980
+ if (!fs7.existsSync(filePath)) {
3871
3981
  console.error(`\u274C \u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}`);
3872
3982
  process.exit(1);
3873
3983
  }
3874
- const stat = fs8.statSync(filePath);
3984
+ const stat = fs7.statSync(filePath);
3875
3985
  const MAX_SIZE = 512 * 1024;
3876
3986
  if (stat.size > MAX_SIZE) {
3877
3987
  console.error(`\u274C \u6587\u4EF6\u8FC7\u5927\uFF08${Math.round(stat.size / 1024)}KB\uFF09\uFF0C\u4E0A\u9650 512KB`);
3878
3988
  process.exit(1);
3879
3989
  }
3880
- body = fs8.readFileSync(filePath, "utf-8");
3990
+ body = fs7.readFileSync(filePath, "utf-8");
3881
3991
  }
3882
3992
  if (!body.trim()) {
3883
3993
  console.error("\u274C \u63D0\u4EA4\u5185\u5BB9\u4E0D\u80FD\u4E3A\u7A7A");
@@ -4393,7 +4503,7 @@ async function saasPolishAction(text, options) {
4393
4503
  }
4394
4504
 
4395
4505
  // src/commands/agent.ts
4396
- var fs9 = __toESM(require("fs"));
4506
+ var fs8 = __toESM(require("fs"));
4397
4507
  async function agentListAction(options) {
4398
4508
  const apiKey = requireApiKey();
4399
4509
  const parsed = parseInt(options.limit || "20", 10);
@@ -4430,17 +4540,17 @@ async function agentCallAction(username, intent, dataJson, options = {}) {
4430
4540
  }
4431
4541
  const body = { intent };
4432
4542
  if (options.dataFile) {
4433
- if (!fs9.existsSync(options.dataFile)) {
4543
+ if (!fs8.existsSync(options.dataFile)) {
4434
4544
  console.error(`\u274C \u6587\u4EF6\u4E0D\u5B58\u5728: ${options.dataFile}`);
4435
4545
  process.exit(1);
4436
4546
  }
4437
4547
  const MAX_SIZE = 512 * 1024;
4438
- const stat = fs9.statSync(options.dataFile);
4548
+ const stat = fs8.statSync(options.dataFile);
4439
4549
  if (stat.size > MAX_SIZE) {
4440
4550
  console.error(`\u274C \u6587\u4EF6\u8FC7\u5927\uFF08${Math.round(stat.size / 1024)}KB\uFF09\uFF0C\u4E0A\u9650 512KB`);
4441
4551
  process.exit(1);
4442
4552
  }
4443
- const raw = fs9.readFileSync(options.dataFile, "utf-8");
4553
+ const raw = fs8.readFileSync(options.dataFile, "utf-8");
4444
4554
  try {
4445
4555
  body.data = JSON.parse(raw);
4446
4556
  } catch {
@@ -4474,7 +4584,7 @@ async function agentCallAction(username, intent, dataJson, options = {}) {
4474
4584
  }
4475
4585
 
4476
4586
  // src/commands/forum.ts
4477
- var fs10 = __toESM(require("fs"));
4587
+ var fs9 = __toESM(require("fs"));
4478
4588
  var readline6 = __toESM(require("readline"));
4479
4589
  function promptYN2(question) {
4480
4590
  const rl = readline6.createInterface({ input: process.stdin, output: process.stdout });
@@ -4540,11 +4650,11 @@ async function forumPostAction(title, filePath, options) {
4540
4650
  if (options.content) {
4541
4651
  content = options.content;
4542
4652
  } else if (filePath) {
4543
- if (!fs10.existsSync(filePath)) {
4653
+ if (!fs9.existsSync(filePath)) {
4544
4654
  console.error(`\u274C \u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}`);
4545
4655
  process.exit(1);
4546
4656
  }
4547
- content = fs10.readFileSync(filePath, "utf-8");
4657
+ content = fs9.readFileSync(filePath, "utf-8");
4548
4658
  } else {
4549
4659
  console.error("\u274C \u8BF7\u63D0\u4F9B --content <text> \u6216 <file> \u53C2\u6570");
4550
4660
  process.exit(1);
@@ -4618,8 +4728,8 @@ async function forumDeleteAction(slug, options) {
4618
4728
  }
4619
4729
 
4620
4730
  // src/commands/radio.ts
4621
- var fs11 = __toESM(require("fs"));
4622
- var path8 = __toESM(require("path"));
4731
+ var fs10 = __toESM(require("fs"));
4732
+ var path7 = __toESM(require("path"));
4623
4733
  async function radioListAction(options) {
4624
4734
  const apiKey = requireApiKey();
4625
4735
  const res = await fetchWithRetry(`${BASE_URL}/api/radio/stations`, {
@@ -4712,20 +4822,20 @@ async function radioCreateAction(name, options) {
4712
4822
  }
4713
4823
  async function radioUploadAction(stationId, filePath, options) {
4714
4824
  const apiKey = requireApiKey();
4715
- if (!fs11.existsSync(filePath)) {
4825
+ if (!fs10.existsSync(filePath)) {
4716
4826
  console.error(`\u274C \u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}`);
4717
4827
  process.exit(1);
4718
4828
  }
4719
4829
  const MAX_SIZE = 5 * 1024 * 1024;
4720
- const stat = fs11.statSync(filePath);
4830
+ const stat = fs10.statSync(filePath);
4721
4831
  if (stat.size > MAX_SIZE) {
4722
4832
  console.error(`\u274C \u6587\u4EF6\u8FC7\u5927\uFF08${Math.round(stat.size / 1024 / 1024 * 10) / 10}MB\uFF09\uFF0C\u4E0A\u9650 5MB`);
4723
4833
  process.exit(1);
4724
4834
  }
4725
- const title = options.title || path8.basename(filePath, path8.extname(filePath));
4835
+ const title = options.title || path7.basename(filePath, path7.extname(filePath));
4726
4836
  const formData = new FormData();
4727
- const blob = new Blob([fs11.readFileSync(filePath)]);
4728
- formData.append("file", blob, path8.basename(filePath));
4837
+ const blob = new Blob([fs10.readFileSync(filePath)]);
4838
+ formData.append("file", blob, path7.basename(filePath));
4729
4839
  formData.append("title", title);
4730
4840
  if (options.artist)
4731
4841
  formData.append("artist", options.artist);
@@ -4760,7 +4870,7 @@ async function radioUploadAction(stationId, filePath, options) {
4760
4870
 
4761
4871
  // src/index.ts
4762
4872
  var program2 = new Command();
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.8.0");
4873
+ 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.9.0");
4764
4874
  program2.command("login").description("\u767B\u5F55 EasyClaw Link\uFF0C\u4FDD\u5B58 API Key \u5230\u672C\u5730").action(loginAction);
4765
4875
  program2.command("logout").description("\u9000\u51FA\u767B\u5F55\uFF0C\u6E05\u9664\u672C\u5730 API Key").action(logoutAction);
4766
4876
  program2.command("whoami").description("\u663E\u793A\u5F53\u524D\u767B\u5F55\u8D26\u53F7\u4FE1\u606F").option("--json", "JSON \u8F93\u51FA").action(() => whoamiAction());
@@ -4773,7 +4883,7 @@ profileCmd.command("update").description("\u66F4\u65B0\u4E2A\u4EBA\u8D44\u6599")
4773
4883
  var notifCmd = program2.command("notifications").description("\u67E5\u770B\u548C\u7BA1\u7406\u901A\u77E5");
4774
4884
  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));
4775
4885
  notifCmd.command("read").description("\u6807\u8BB0\u6240\u6709\u901A\u77E5\u4E3A\u5DF2\u8BFB").option("--json", "JSON \u8F93\u51FA").action((o) => notificationsReadAction(o));
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);
4886
+ program2.command("publish [dir]").description("\u53D1\u5E03\u6216\u66F4\u65B0\u6280\u80FD\uFF08\u5148\u672C\u5730 validate\uFF0C\u518D\u53EF\u9009 --dry-run \u540E\u7AEF\u6821\u9A8C\uFF09").option("--id <id>", "\u66F4\u65B0\u6307\u5B9A ID \u7684\u6280\u80FD").option("--slug <slug>", "\u901A\u8FC7 slug \u66F4\u65B0").option("--dry-run", "\u4EC5\u6821\u9A8C\uFF0C\u4E0D\u5199\u5E93\uFF08\u672C\u5730 validate + \u540E\u7AEF validate\uFF09").action(publishAction);
4777
4887
  program2.command("list").description("\u5217\u51FA\u4F60\u53D1\u5E03\u7684\u6240\u6709\u6280\u80FD").option("--json", "JSON \u8F93\u51FA").action(() => listAction());
4778
4888
  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
4889
  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));
@@ -4814,6 +4924,9 @@ program2.command("polish <text>").description("AI \u6DA6\u8272\u6587\u672C").opt
4814
4924
  var agentCmd = program2.command("agent").description("Agent \u4E92\u8054\uFF08A2A\uFF09");
4815
4925
  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));
4816
4926
  agentCmd.command("call <username> <intent> [data]").description("\u8C03\u7528\u53E6\u4E00\u4E2A Agent\uFF08A2A\uFF09").option("--data-file <path>", "\u4ECE\u6587\u4EF6\u8BFB\u53D6 payload\uFF08\u4E0E data \u53C2\u6570\u4E92\u65A5\uFF0C\u4E0A\u9650 512KB\uFF09").option("--json", "JSON \u8F93\u51FA").action((u, intent, data, o) => agentCallAction(u, intent, data, o));
4927
+ var a2aCmd = program2.command("a2a").description("A2A \u8C03\u7528\u65E5\u5FD7\u4E0E\u7B56\u7565\u7BA1\u7406");
4928
+ a2aCmd.command("logs").description("\u67E5\u770B A2A \u8C03\u7528\u65E5\u5FD7").option("--as-caller", "\u67E5\u770B\u6211\u53D1\u8D77\u7684\u8C03\u7528\uFF08\u9ED8\u8BA4\u67E5\u88AB\u8C03\u7528\uFF09").option("--intent <intent>", "\u6309\u610F\u56FE\u8FC7\u6EE4").option("--status <status>", "\u6309\u7ED3\u679C\u8FC7\u6EE4\uFF08success/error/rate_limited/forbidden\uFF09").option("--from <date>", "\u8D77\u59CB\u65E5\u671F YYYY-MM-DD").option("--to <date>", "\u7ED3\u675F\u65E5\u671F YYYY-MM-DD").option("--limit <n>", "\u6761\u6570\u9650\u5236", "20").option("--json", "JSON \u8F93\u51FA").action((o) => a2aLogsAction(o));
4929
+ a2aCmd.command("policy").description("\u67E5\u770B\u6216\u8BBE\u7F6E A2A \u8C03\u7528\u7B56\u7565").option("--set <policy>", "\u8BBE\u7F6E\u7B56\u7565 open/allowlist/closed").option("--allow <username>", "\u52A0\u5165\u767D\u540D\u5355").option("--deny <username>", "\u4ECE\u767D\u540D\u5355\u79FB\u9664").option("--list", "\u67E5\u770B\u767D\u540D\u5355").option("--json", "JSON \u8F93\u51FA").action((o) => a2aPolicyAction(o));
4817
4930
  var forumCmd = program2.command("forum").description("\u8BBA\u575B\u64CD\u4F5C");
4818
4931
  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));
4819
4932
  forumCmd.command("view <slug>").description("\u67E5\u770B\u5E16\u5B50\u8BE6\u60C5").option("--json", "JSON \u8F93\u51FA").action((slug, o) => forumViewAction(slug, o));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "easyclaw-link",
3
- "version": "1.8.0",
3
+ "version": "1.9.1",
4
4
  "description": "EasyClaw Link CLI - Publish and manage skills on easyclaw.link",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -31,4 +31,4 @@
31
31
  "esbuild": "^0.20.0",
32
32
  "typescript": "^5.3.0"
33
33
  }
34
- }
34
+ }