easyclaw-link 1.8.0 → 1.9.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 +267 -164
  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 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");
3007
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`);
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,108 @@ 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
+ console.log(`\u2705 \u5DF2\u5C06 @${options.allow} \u52A0\u5165\u767D\u540D\u5355`);
3533
+ }
3534
+ if (options.deny) {
3535
+ const removeRes = await fetchWithRetry(`${BASE_URL}/api/auth/me`, {
3536
+ method: "PATCH",
3537
+ headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
3538
+ body: JSON.stringify({ a2a_allowlist_remove_usernames: [options.deny] })
3539
+ });
3540
+ await assertOk(removeRes);
3541
+ console.log(`\u2705 \u5DF2\u5C06 @${options.deny} \u4ECE\u767D\u540D\u5355\u79FB\u9664`);
3542
+ }
3543
+ }
3544
+
3346
3545
  // src/commands/unread.ts
3347
3546
  async function unreadAction(options) {
3348
3547
  const apiKey = requireApiKey();
@@ -3447,108 +3646,9 @@ async function profileUpdateAction(options) {
3447
3646
  console.log(` Owner Email: ${body.owner_email || "(\u5DF2\u6E05\u9664)"}`);
3448
3647
  }
3449
3648
 
3450
- // src/commands/validate.ts
3649
+ // src/commands/init.ts
3451
3650
  var fs5 = __toESM(require("fs"));
3452
3651
  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
3652
  var SKILL_MD_TEMPLATE = (name) => `# ${name}
3553
3653
 
3554
3654
  \u4E00\u53E5\u8BDD\u8BF4\u660E\u8FD9\u4E2A\u6280\u80FD\u7684\u7528\u9014\u548C\u9002\u7528\u573A\u666F\u3002
@@ -3591,18 +3691,18 @@ async function skillInitAction(name, options) {
3591
3691
  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
3692
  process.exit(EXIT2.VALIDATION);
3593
3693
  }
3594
- const dir = path6.resolve(name);
3595
- if (fs6.existsSync(dir)) {
3694
+ const dir = path5.resolve(name);
3695
+ if (fs5.existsSync(dir)) {
3596
3696
  if (!options.force) {
3597
3697
  console.error(`\u274C \u76EE\u5F55\u5DF2\u5B58\u5728: ${dir}
3598
3698
  \u4F7F\u7528 --force \u8986\u76D6`);
3599
3699
  process.exit(EXIT2.VALIDATION);
3600
3700
  }
3601
3701
  } else {
3602
- fs6.mkdirSync(dir, { recursive: true });
3702
+ fs5.mkdirSync(dir, { recursive: true });
3603
3703
  }
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");
3704
+ fs5.writeFileSync(path5.join(dir, "SKILL.md"), SKILL_MD_TEMPLATE(name), "utf-8");
3705
+ fs5.writeFileSync(path5.join(dir, "package.json"), PKG_TEMPLATE(name), "utf-8");
3606
3706
  console.log(`\u2705 \u6280\u80FD\u76EE\u5F55\u5DF2\u521B\u5EFA: ${dir}
3607
3707
  `);
3608
3708
  console.log(" \u{1F4C4} SKILL.md \u2014 \u586B\u5199\u6280\u80FD\u8BF4\u660E\u6587\u6863");
@@ -3613,7 +3713,7 @@ async function skillInitAction(name, options) {
3613
3713
  console.log(" 3. ecl validate # \u53D1\u5E03\u524D\u6821\u9A8C");
3614
3714
  console.log(" 4. ecl publish # \u53D1\u5E03\u5230\u5E73\u53F0");
3615
3715
  console.log("\n\u521D\u59CB\u6821\u9A8C\uFF1A");
3616
- const { errors, warnings } = validateSkillDir2(dir);
3716
+ const { errors, warnings } = validateSkillDir(dir);
3617
3717
  if (warnings.length) {
3618
3718
  for (const w of warnings)
3619
3719
  console.log(` \u{1F7E1} ${w}`);
@@ -3624,8 +3724,8 @@ async function skillInitAction(name, options) {
3624
3724
  }
3625
3725
 
3626
3726
  // src/commands/skill.ts
3627
- var fs7 = __toESM(require("fs"));
3628
- var path7 = __toESM(require("path"));
3727
+ var fs6 = __toESM(require("fs"));
3728
+ var path6 = __toESM(require("path"));
3629
3729
  var readline3 = __toESM(require("readline"));
3630
3730
  function promptYN(question) {
3631
3731
  const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
@@ -3691,12 +3791,12 @@ async function skillDownloadAction(id, options) {
3691
3791
  await assertOk(res);
3692
3792
  const buffer = Buffer.from(await res.arrayBuffer());
3693
3793
  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 });
3794
+ const resolved = path6.resolve(outPath);
3795
+ const dir = path6.dirname(resolved);
3796
+ if (!fs6.existsSync(dir)) {
3797
+ fs6.mkdirSync(dir, { recursive: true });
3698
3798
  }
3699
- fs7.writeFileSync(resolved, buffer);
3799
+ fs6.writeFileSync(resolved, buffer);
3700
3800
  if (options.json) {
3701
3801
  console.log(JSON.stringify({ success: true, path: resolved, size: buffer.length }));
3702
3802
  return;
@@ -3773,7 +3873,7 @@ async function skillSearchAction(keyword, options) {
3773
3873
  }
3774
3874
 
3775
3875
  // src/commands/bounty.ts
3776
- var fs8 = __toESM(require("fs"));
3876
+ var fs7 = __toESM(require("fs"));
3777
3877
  async function bountyListAction(options) {
3778
3878
  const apiKey = requireApiKey();
3779
3879
  const status = options.status || "open";
@@ -3867,17 +3967,17 @@ async function bountySubmitAction(id, content, options) {
3867
3967
  let body = content;
3868
3968
  if (content.startsWith("@")) {
3869
3969
  const filePath = content.slice(1);
3870
- if (!fs8.existsSync(filePath)) {
3970
+ if (!fs7.existsSync(filePath)) {
3871
3971
  console.error(`\u274C \u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}`);
3872
3972
  process.exit(1);
3873
3973
  }
3874
- const stat = fs8.statSync(filePath);
3974
+ const stat = fs7.statSync(filePath);
3875
3975
  const MAX_SIZE = 512 * 1024;
3876
3976
  if (stat.size > MAX_SIZE) {
3877
3977
  console.error(`\u274C \u6587\u4EF6\u8FC7\u5927\uFF08${Math.round(stat.size / 1024)}KB\uFF09\uFF0C\u4E0A\u9650 512KB`);
3878
3978
  process.exit(1);
3879
3979
  }
3880
- body = fs8.readFileSync(filePath, "utf-8");
3980
+ body = fs7.readFileSync(filePath, "utf-8");
3881
3981
  }
3882
3982
  if (!body.trim()) {
3883
3983
  console.error("\u274C \u63D0\u4EA4\u5185\u5BB9\u4E0D\u80FD\u4E3A\u7A7A");
@@ -4393,7 +4493,7 @@ async function saasPolishAction(text, options) {
4393
4493
  }
4394
4494
 
4395
4495
  // src/commands/agent.ts
4396
- var fs9 = __toESM(require("fs"));
4496
+ var fs8 = __toESM(require("fs"));
4397
4497
  async function agentListAction(options) {
4398
4498
  const apiKey = requireApiKey();
4399
4499
  const parsed = parseInt(options.limit || "20", 10);
@@ -4430,17 +4530,17 @@ async function agentCallAction(username, intent, dataJson, options = {}) {
4430
4530
  }
4431
4531
  const body = { intent };
4432
4532
  if (options.dataFile) {
4433
- if (!fs9.existsSync(options.dataFile)) {
4533
+ if (!fs8.existsSync(options.dataFile)) {
4434
4534
  console.error(`\u274C \u6587\u4EF6\u4E0D\u5B58\u5728: ${options.dataFile}`);
4435
4535
  process.exit(1);
4436
4536
  }
4437
4537
  const MAX_SIZE = 512 * 1024;
4438
- const stat = fs9.statSync(options.dataFile);
4538
+ const stat = fs8.statSync(options.dataFile);
4439
4539
  if (stat.size > MAX_SIZE) {
4440
4540
  console.error(`\u274C \u6587\u4EF6\u8FC7\u5927\uFF08${Math.round(stat.size / 1024)}KB\uFF09\uFF0C\u4E0A\u9650 512KB`);
4441
4541
  process.exit(1);
4442
4542
  }
4443
- const raw = fs9.readFileSync(options.dataFile, "utf-8");
4543
+ const raw = fs8.readFileSync(options.dataFile, "utf-8");
4444
4544
  try {
4445
4545
  body.data = JSON.parse(raw);
4446
4546
  } catch {
@@ -4474,7 +4574,7 @@ async function agentCallAction(username, intent, dataJson, options = {}) {
4474
4574
  }
4475
4575
 
4476
4576
  // src/commands/forum.ts
4477
- var fs10 = __toESM(require("fs"));
4577
+ var fs9 = __toESM(require("fs"));
4478
4578
  var readline6 = __toESM(require("readline"));
4479
4579
  function promptYN2(question) {
4480
4580
  const rl = readline6.createInterface({ input: process.stdin, output: process.stdout });
@@ -4540,11 +4640,11 @@ async function forumPostAction(title, filePath, options) {
4540
4640
  if (options.content) {
4541
4641
  content = options.content;
4542
4642
  } else if (filePath) {
4543
- if (!fs10.existsSync(filePath)) {
4643
+ if (!fs9.existsSync(filePath)) {
4544
4644
  console.error(`\u274C \u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}`);
4545
4645
  process.exit(1);
4546
4646
  }
4547
- content = fs10.readFileSync(filePath, "utf-8");
4647
+ content = fs9.readFileSync(filePath, "utf-8");
4548
4648
  } else {
4549
4649
  console.error("\u274C \u8BF7\u63D0\u4F9B --content <text> \u6216 <file> \u53C2\u6570");
4550
4650
  process.exit(1);
@@ -4618,8 +4718,8 @@ async function forumDeleteAction(slug, options) {
4618
4718
  }
4619
4719
 
4620
4720
  // src/commands/radio.ts
4621
- var fs11 = __toESM(require("fs"));
4622
- var path8 = __toESM(require("path"));
4721
+ var fs10 = __toESM(require("fs"));
4722
+ var path7 = __toESM(require("path"));
4623
4723
  async function radioListAction(options) {
4624
4724
  const apiKey = requireApiKey();
4625
4725
  const res = await fetchWithRetry(`${BASE_URL}/api/radio/stations`, {
@@ -4712,20 +4812,20 @@ async function radioCreateAction(name, options) {
4712
4812
  }
4713
4813
  async function radioUploadAction(stationId, filePath, options) {
4714
4814
  const apiKey = requireApiKey();
4715
- if (!fs11.existsSync(filePath)) {
4815
+ if (!fs10.existsSync(filePath)) {
4716
4816
  console.error(`\u274C \u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}`);
4717
4817
  process.exit(1);
4718
4818
  }
4719
4819
  const MAX_SIZE = 5 * 1024 * 1024;
4720
- const stat = fs11.statSync(filePath);
4820
+ const stat = fs10.statSync(filePath);
4721
4821
  if (stat.size > MAX_SIZE) {
4722
4822
  console.error(`\u274C \u6587\u4EF6\u8FC7\u5927\uFF08${Math.round(stat.size / 1024 / 1024 * 10) / 10}MB\uFF09\uFF0C\u4E0A\u9650 5MB`);
4723
4823
  process.exit(1);
4724
4824
  }
4725
- const title = options.title || path8.basename(filePath, path8.extname(filePath));
4825
+ const title = options.title || path7.basename(filePath, path7.extname(filePath));
4726
4826
  const formData = new FormData();
4727
- const blob = new Blob([fs11.readFileSync(filePath)]);
4728
- formData.append("file", blob, path8.basename(filePath));
4827
+ const blob = new Blob([fs10.readFileSync(filePath)]);
4828
+ formData.append("file", blob, path7.basename(filePath));
4729
4829
  formData.append("title", title);
4730
4830
  if (options.artist)
4731
4831
  formData.append("artist", options.artist);
@@ -4760,7 +4860,7 @@ async function radioUploadAction(stationId, filePath, options) {
4760
4860
 
4761
4861
  // src/index.ts
4762
4862
  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");
4863
+ 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
4864
  program2.command("login").description("\u767B\u5F55 EasyClaw Link\uFF0C\u4FDD\u5B58 API Key \u5230\u672C\u5730").action(loginAction);
4765
4865
  program2.command("logout").description("\u9000\u51FA\u767B\u5F55\uFF0C\u6E05\u9664\u672C\u5730 API Key").action(logoutAction);
4766
4866
  program2.command("whoami").description("\u663E\u793A\u5F53\u524D\u767B\u5F55\u8D26\u53F7\u4FE1\u606F").option("--json", "JSON \u8F93\u51FA").action(() => whoamiAction());
@@ -4773,7 +4873,7 @@ profileCmd.command("update").description("\u66F4\u65B0\u4E2A\u4EBA\u8D44\u6599")
4773
4873
  var notifCmd = program2.command("notifications").description("\u67E5\u770B\u548C\u7BA1\u7406\u901A\u77E5");
4774
4874
  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
4875
  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);
4876
+ 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
4877
  program2.command("list").description("\u5217\u51FA\u4F60\u53D1\u5E03\u7684\u6240\u6709\u6280\u80FD").option("--json", "JSON \u8F93\u51FA").action(() => listAction());
4778
4878
  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
4879
  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 +4914,9 @@ program2.command("polish <text>").description("AI \u6DA6\u8272\u6587\u672C").opt
4814
4914
  var agentCmd = program2.command("agent").description("Agent \u4E92\u8054\uFF08A2A\uFF09");
4815
4915
  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
4916
  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));
4917
+ var a2aCmd = program2.command("a2a").description("A2A \u8C03\u7528\u65E5\u5FD7\u4E0E\u7B56\u7565\u7BA1\u7406");
4918
+ 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));
4919
+ 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
4920
  var forumCmd = program2.command("forum").description("\u8BBA\u575B\u64CD\u4F5C");
4818
4921
  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
4922
  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.0",
4
4
  "description": "EasyClaw Link CLI - Publish and manage skills on easyclaw.link",
5
5
  "main": "dist/index.js",
6
6
  "bin": {