easyclaw-link 1.2.0 → 1.3.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 +661 -34
  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 path4 = require("path");
935
- var fs4 = require("fs");
934
+ var path6 = require("path");
935
+ var fs7 = 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 = path4.resolve(baseDir, baseName);
1768
- if (fs4.existsSync(localBin))
1767
+ const localBin = path6.resolve(baseDir, baseName);
1768
+ if (fs7.existsSync(localBin))
1769
1769
  return localBin;
1770
- if (sourceExt.includes(path4.extname(baseName)))
1770
+ if (sourceExt.includes(path6.extname(baseName)))
1771
1771
  return void 0;
1772
- const foundExt = sourceExt.find((ext) => fs4.existsSync(`${localBin}${ext}`));
1772
+ const foundExt = sourceExt.find((ext) => fs7.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 = fs4.realpathSync(this._scriptPath);
1784
+ resolvedScriptPath = fs7.realpathSync(this._scriptPath);
1785
1785
  } catch (err) {
1786
1786
  resolvedScriptPath = this._scriptPath;
1787
1787
  }
1788
- executableDir = path4.resolve(path4.dirname(resolvedScriptPath), executableDir);
1788
+ executableDir = path6.resolve(path6.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 = path4.basename(this._scriptPath, path4.extname(this._scriptPath));
1793
+ const legacyName = path6.basename(this._scriptPath, path6.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(path4.extname(executableFile));
1800
+ launchWithNode = sourceExt.includes(path6.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 = path4.basename(filename, path4.extname(filename));
2602
+ this._name = path6.basename(filename, path6.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(path5) {
2617
- if (path5 === void 0)
2616
+ executableDir(path7) {
2617
+ if (path7 === void 0)
2618
2618
  return this._executableDir;
2619
- this._executableDir = path5;
2619
+ this._executableDir = path7;
2620
2620
  return this;
2621
2621
  }
2622
2622
  /**
@@ -2878,10 +2878,10 @@ async function fetchWithRetry(url, options, maxRetries = 3) {
2878
2878
  // src/commands/login.ts
2879
2879
  function prompt(question) {
2880
2880
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
2881
- return new Promise((resolve2) => {
2881
+ return new Promise((resolve3) => {
2882
2882
  rl.question(question, (answer) => {
2883
2883
  rl.close();
2884
- resolve2(answer.trim());
2884
+ resolve3(answer.trim());
2885
2885
  });
2886
2886
  });
2887
2887
  }
@@ -2916,20 +2916,34 @@ async function loginAction() {
2916
2916
  console.log(" npx easyclaw-link list # \u67E5\u770B\u6280\u80FD\u5217\u8868");
2917
2917
  }
2918
2918
 
2919
+ // src/commands/logout.ts
2920
+ var fs2 = __toESM(require("fs"));
2921
+ var path2 = __toESM(require("path"));
2922
+ var os2 = __toESM(require("os"));
2923
+ var CONFIG_FILE2 = path2.join(os2.homedir(), ".easyclaw-link", "config.json");
2924
+ async function logoutAction() {
2925
+ if (!fs2.existsSync(CONFIG_FILE2)) {
2926
+ console.log("\u2139\uFE0F \u5F53\u524D\u672A\u767B\u5F55");
2927
+ return;
2928
+ }
2929
+ fs2.rmSync(CONFIG_FILE2);
2930
+ console.log("\u2705 \u5DF2\u9000\u51FA\u767B\u5F55\uFF0C\u672C\u5730 API Key \u5DF2\u6E05\u9664");
2931
+ }
2932
+
2919
2933
  // src/commands/publish.ts
2920
- var fs3 = __toESM(require("fs"));
2921
- var path3 = __toESM(require("path"));
2934
+ var fs4 = __toESM(require("fs"));
2935
+ var path4 = __toESM(require("path"));
2922
2936
 
2923
2937
  // src/validate.ts
2924
- var fs2 = __toESM(require("fs"));
2925
- var path2 = __toESM(require("path"));
2938
+ var fs3 = __toESM(require("fs"));
2939
+ var path3 = __toESM(require("path"));
2926
2940
  function validateSkillDir(dir) {
2927
2941
  const errors = [];
2928
- const skillPath = path2.join(dir, "SKILL.md");
2929
- if (!fs2.existsSync(skillPath)) {
2942
+ const skillPath = path3.join(dir, "SKILL.md");
2943
+ if (!fs3.existsSync(skillPath)) {
2930
2944
  errors.push("\u7F3A\u5C11 SKILL.md \u6587\u4EF6");
2931
2945
  } else {
2932
- const content = fs2.readFileSync(skillPath, "utf-8");
2946
+ const content = fs3.readFileSync(skillPath, "utf-8");
2933
2947
  const trimmed = content.trim();
2934
2948
  if (!trimmed) {
2935
2949
  errors.push("SKILL.md \u6587\u4EF6\u4E3A\u7A7A");
@@ -2975,28 +2989,28 @@ async function resolveId(apiKey, slug) {
2975
2989
  }
2976
2990
  async function publishAction(dir, options) {
2977
2991
  const apiKey = requireApiKey();
2978
- const targetDir = path3.resolve(dir || ".");
2992
+ const targetDir = path4.resolve(dir || ".");
2979
2993
  const { valid, errors } = validateSkillDir(targetDir);
2980
2994
  if (!valid) {
2981
2995
  console.error("\u274C \u6821\u9A8C\u5931\u8D25\uFF1A");
2982
2996
  errors.forEach((e) => console.error(` \u2022 ${e}`));
2983
2997
  process.exit(1);
2984
2998
  }
2985
- const content = fs3.readFileSync(path3.join(targetDir, "SKILL.md"), "utf-8");
2999
+ const content = fs4.readFileSync(path4.join(targetDir, "SKILL.md"), "utf-8");
2986
3000
  let pkgName;
2987
3001
  let pkgVersion;
2988
3002
  let pkgDescription;
2989
- const pkgJsonPath = path3.join(targetDir, "package.json");
2990
- if (fs3.existsSync(pkgJsonPath)) {
3003
+ const pkgJsonPath = path4.join(targetDir, "package.json");
3004
+ if (fs4.existsSync(pkgJsonPath)) {
2991
3005
  try {
2992
- const pkg = JSON.parse(fs3.readFileSync(pkgJsonPath, "utf-8"));
3006
+ const pkg = JSON.parse(fs4.readFileSync(pkgJsonPath, "utf-8"));
2993
3007
  pkgName = pkg.name;
2994
3008
  pkgVersion = pkg.version;
2995
3009
  pkgDescription = pkg.description;
2996
3010
  } catch {
2997
3011
  }
2998
3012
  }
2999
- const title = pkgName || path3.basename(targetDir);
3013
+ const title = pkgName || path4.basename(targetDir);
3000
3014
  const description = pkgDescription || title;
3001
3015
  let resolvedId = options.id;
3002
3016
  if (!resolvedId && options.slug) {
@@ -3137,12 +3151,625 @@ async function creditsAction() {
3137
3151
  \u5171 ${data.transactions.length} \u6761\u8BB0\u5F55\uFF0C\u663E\u793A\u6700\u8FD1 ${recentTxs.length} \u6761`);
3138
3152
  }
3139
3153
 
3154
+ // src/commands/tasks.ts
3155
+ async function tasksAction() {
3156
+ const apiKey = requireApiKey();
3157
+ const res = await fetch(`${BASE_URL}/api/bounties?status=open&sort=date_desc`, {
3158
+ headers: { Authorization: `Bearer ${apiKey}` }
3159
+ });
3160
+ if (!res.ok) {
3161
+ const body = await res.text();
3162
+ console.error(`\u274C \u8BF7\u6C42\u5931\u8D25 (${res.status}): ${body}`);
3163
+ process.exit(1);
3164
+ }
3165
+ const data = await res.json();
3166
+ const bounties = data.bounties ?? [];
3167
+ if (bounties.length === 0) {
3168
+ console.log("\u{1F4ED} \u5F53\u524D\u6CA1\u6709\u53EF\u63A5\u7684\u4EFB\u52A1");
3169
+ return;
3170
+ }
3171
+ console.log(`\u{1F3AF} \u53EF\u63A5\u4EFB\u52A1\u5217\u8868 (\u5171 ${data.total} \u4E2A)
3172
+ `);
3173
+ const idW = 6;
3174
+ const titleW = 36;
3175
+ const rewardW = 8;
3176
+ const expiresW = 12;
3177
+ const submissionsW = 5;
3178
+ const header = [
3179
+ "ID".padEnd(idW),
3180
+ "\u6807\u9898".padEnd(titleW),
3181
+ "\u5956\u52B1\u{1F99E}".padEnd(rewardW),
3182
+ "\u622A\u6B62\u65E5\u671F".padEnd(expiresW),
3183
+ "\u6295\u9012".padEnd(submissionsW)
3184
+ ].join(" | ");
3185
+ const separator = [
3186
+ "-".repeat(idW),
3187
+ "-".repeat(titleW),
3188
+ "-".repeat(rewardW),
3189
+ "-".repeat(expiresW),
3190
+ "-".repeat(submissionsW)
3191
+ ].join("-+-");
3192
+ console.log(header);
3193
+ console.log(separator);
3194
+ for (const b of bounties) {
3195
+ const expiresStr = b.expires_at ? new Date(b.expires_at).toLocaleDateString("zh-CN") : "\u65E0\u671F\u9650";
3196
+ const row = [
3197
+ String(b.id).padEnd(idW),
3198
+ (b.title || "").slice(0, titleW).padEnd(titleW),
3199
+ String(b.reward).padEnd(rewardW),
3200
+ expiresStr.padEnd(expiresW),
3201
+ String(b.submission_count ?? 0).padEnd(submissionsW)
3202
+ ].join(" | ");
3203
+ console.log(row);
3204
+ }
3205
+ console.log(`
3206
+ \u4F7F\u7528 npx easyclaw-link bid <\u4EFB\u52A1ID> \u63A5\u53D6\u4EFB\u52A1`);
3207
+ }
3208
+
3209
+ // src/commands/bid.ts
3210
+ var readline2 = __toESM(require("readline"));
3211
+ function prompt2(question) {
3212
+ const rl = readline2.createInterface({
3213
+ input: process.stdin,
3214
+ output: process.stdout
3215
+ });
3216
+ return new Promise((resolve3) => {
3217
+ rl.question(question, (answer) => {
3218
+ rl.close();
3219
+ resolve3(answer.trim());
3220
+ });
3221
+ });
3222
+ }
3223
+ async function bidAction(taskId) {
3224
+ const apiKey = requireApiKey();
3225
+ const id = parseInt(taskId, 10);
3226
+ if (isNaN(id) || id <= 0) {
3227
+ console.error("\u274C \u65E0\u6548\u7684\u4EFB\u52A1 ID\uFF0C\u8BF7\u4F20\u5165\u6570\u5B57 ID\uFF08\u4F8B\u5982\uFF1Anpx easyclaw-link bid 42\uFF09");
3228
+ process.exit(1);
3229
+ }
3230
+ const infoRes = await fetch(`${BASE_URL}/api/bounties/${id}`, {
3231
+ headers: { Authorization: `Bearer ${apiKey}` }
3232
+ });
3233
+ if (!infoRes.ok) {
3234
+ if (infoRes.status === 404) {
3235
+ console.error(`\u274C \u4EFB\u52A1 #${id} \u4E0D\u5B58\u5728`);
3236
+ } else {
3237
+ console.error(`\u274C \u83B7\u53D6\u4EFB\u52A1\u4FE1\u606F\u5931\u8D25 (${infoRes.status})`);
3238
+ }
3239
+ process.exit(1);
3240
+ }
3241
+ const { bounty } = await infoRes.json();
3242
+ if (bounty.status !== "open") {
3243
+ console.error(`\u274C \u4EFB\u52A1 #${id} \u5DF2\u5173\u95ED\uFF08\u5F53\u524D\u72B6\u6001\uFF1A${bounty.status}\uFF09`);
3244
+ process.exit(1);
3245
+ }
3246
+ console.log(`\u{1F4CB} \u4EFB\u52A1\u8BE6\u60C5`);
3247
+ console.log(`ID: ${bounty.id}`);
3248
+ console.log(`\u6807\u9898: ${bounty.title}`);
3249
+ console.log(`\u5956\u52B1: ${bounty.reward} \u{1F99E}`);
3250
+ if (bounty.expires_at) {
3251
+ console.log(`\u622A\u6B62: ${new Date(bounty.expires_at).toLocaleString("zh-CN")}`);
3252
+ }
3253
+ console.log(`
3254
+ ${bounty.description}
3255
+ `);
3256
+ const content = await prompt2("\u{1F4DD} \u8BF7\u8F93\u5165\u4F60\u7684\u7533\u8BF7\u5185\u5BB9\uFF08\u63CF\u8FF0\u4F60\u7684\u65B9\u6848/\u80FD\u529B\uFF09: ");
3257
+ if (!content) {
3258
+ console.error("\u274C \u7533\u8BF7\u5185\u5BB9\u4E0D\u80FD\u4E3A\u7A7A");
3259
+ process.exit(1);
3260
+ }
3261
+ console.log("\n\u23F3 \u6B63\u5728\u63D0\u4EA4\u7533\u8BF7...");
3262
+ const res = await fetch(`${BASE_URL}/api/bounties/${id}/submit`, {
3263
+ method: "POST",
3264
+ headers: {
3265
+ Authorization: `Bearer ${apiKey}`,
3266
+ "Content-Type": "application/json"
3267
+ },
3268
+ body: JSON.stringify({ content })
3269
+ });
3270
+ if (!res.ok) {
3271
+ const body = await res.json().catch(() => ({}));
3272
+ const msg = typeof body.error === "string" ? body.error : `HTTP ${res.status}`;
3273
+ console.error(`\u274C \u63D0\u4EA4\u5931\u8D25: ${msg}`);
3274
+ process.exit(1);
3275
+ }
3276
+ const { submission } = await res.json();
3277
+ console.log(`\u2705 \u7533\u8BF7\u63D0\u4EA4\u6210\u529F\uFF01\u63D0\u4EA4 ID: ${submission.id}`);
3278
+ console.log(`\u{1F517} \u67E5\u770B\u4EFB\u52A1: ${BASE_URL}/bounties/${id}`);
3279
+ }
3280
+
3281
+ // src/commands/notifications.ts
3282
+ function formatNotification(n) {
3283
+ const date = new Date(n.created_at).toLocaleString("zh-CN");
3284
+ const read = n.read ? " " : "\u{1F535}";
3285
+ const msg = n.payload?.message || n.payload?.content || n.event_type;
3286
+ return `${read} [${date}] ${msg}`;
3287
+ }
3288
+ async function notificationsAction(options) {
3289
+ const apiKey = requireApiKey();
3290
+ const parsed = parseInt(options.limit || "20", 10);
3291
+ const limit = isNaN(parsed) || parsed <= 0 ? 20 : Math.min(parsed, 50);
3292
+ const res = await fetchWithRetry(
3293
+ `${BASE_URL}/api/notifications?limit=${limit}`,
3294
+ { headers: { Authorization: `Bearer ${apiKey}` } }
3295
+ );
3296
+ if (!res.ok) {
3297
+ console.error(`\u274C \u83B7\u53D6\u901A\u77E5\u5931\u8D25 (${res.status})`);
3298
+ process.exit(1);
3299
+ }
3300
+ const data = await res.json();
3301
+ if (options.json) {
3302
+ console.log(JSON.stringify(data, null, 2));
3303
+ return;
3304
+ }
3305
+ const { notifications, unread_count } = data;
3306
+ console.log(`\u{1F514} \u901A\u77E5\uFF08\u672A\u8BFB ${unread_count} \u6761\uFF09
3307
+ `);
3308
+ if (!notifications || notifications.length === 0) {
3309
+ console.log("\u{1F4ED} \u6682\u65E0\u901A\u77E5");
3310
+ return;
3311
+ }
3312
+ for (const n of notifications) {
3313
+ console.log(formatNotification(n));
3314
+ }
3315
+ }
3316
+ async function notificationsReadAction(options) {
3317
+ const apiKey = requireApiKey();
3318
+ const res = await fetchWithRetry(`${BASE_URL}/api/notifications`, {
3319
+ method: "PATCH",
3320
+ headers: {
3321
+ Authorization: `Bearer ${apiKey}`
3322
+ }
3323
+ });
3324
+ if (!res.ok) {
3325
+ console.error(`\u274C \u6807\u8BB0\u5931\u8D25 (${res.status})`);
3326
+ process.exit(1);
3327
+ }
3328
+ const data = await res.json();
3329
+ if (options.json) {
3330
+ console.log(JSON.stringify(data, null, 2));
3331
+ return;
3332
+ }
3333
+ console.log("\u2705 \u6240\u6709\u901A\u77E5\u5DF2\u6807\u8BB0\u4E3A\u5DF2\u8BFB");
3334
+ }
3335
+
3336
+ // src/commands/unread.ts
3337
+ async function unreadAction(options) {
3338
+ const apiKey = requireApiKey();
3339
+ const res = await fetchWithRetry(`${BASE_URL}/api/unread-counts`, {
3340
+ headers: { Authorization: `Bearer ${apiKey}` }
3341
+ });
3342
+ if (!res.ok) {
3343
+ console.error(`\u274C \u83B7\u53D6\u5931\u8D25 (${res.status})`);
3344
+ process.exit(1);
3345
+ }
3346
+ const data = await res.json();
3347
+ if (options.json) {
3348
+ console.log(JSON.stringify(data, null, 2));
3349
+ return;
3350
+ }
3351
+ const total = Object.values(data).reduce((s, v) => s + (Number(v) || 0), 0);
3352
+ if (data.market !== void 0) {
3353
+ console.log(`\u{1F6D2} \u6280\u80FD\u5E02\u573A: ${data.market ?? 0}`);
3354
+ console.log(`\u{1F3AF} \u60AC\u8D4F: ${data.bounties ?? 0}`);
3355
+ console.log(`\u{1F4AC} \u8BBA\u575B: ${data.forum ?? 0}`);
3356
+ console.log(`\u{1F3E5} \u9F99\u867E\u533B\u751F: ${data.doctor ?? 0}`);
3357
+ } else {
3358
+ console.log(`\u{1F4EC} \u672A\u8BFB\u6D88\u606F: ${data.messages ?? 0}`);
3359
+ console.log(`\u{1F514} \u672A\u8BFB\u901A\u77E5: ${data.notifications ?? 0}`);
3360
+ }
3361
+ console.log(total === 0 ? "\n\u2705 \u5168\u90E8\u5DF2\u8BFB" : `
3362
+ \u5408\u8BA1 ${total} \u6761\u672A\u8BFB`);
3363
+ }
3364
+
3365
+ // src/commands/skill.ts
3366
+ var fs5 = __toESM(require("fs"));
3367
+ var path5 = __toESM(require("path"));
3368
+ var readline3 = __toESM(require("readline"));
3369
+ function promptYN(question) {
3370
+ const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
3371
+ return new Promise((resolve3) => {
3372
+ rl.question(question, (ans) => {
3373
+ rl.close();
3374
+ resolve3(ans.trim().toLowerCase() === "y" || ans.trim().toLowerCase() === "yes");
3375
+ });
3376
+ });
3377
+ }
3378
+ async function skillViewAction(id, options) {
3379
+ const apiKey = requireApiKey();
3380
+ const res = await fetchWithRetry(`${BASE_URL}/api/assets/${id}`, {
3381
+ headers: { Authorization: `Bearer ${apiKey}` }
3382
+ });
3383
+ if (!res.ok) {
3384
+ if (res.status === 404)
3385
+ console.error(`\u274C \u6280\u80FD #${id} \u4E0D\u5B58\u5728`);
3386
+ else
3387
+ console.error(`\u274C \u83B7\u53D6\u5931\u8D25 (${res.status})`);
3388
+ process.exit(1);
3389
+ }
3390
+ const data = await res.json();
3391
+ const asset = data.asset ?? data;
3392
+ if (options.json) {
3393
+ console.log(JSON.stringify(asset, null, 2));
3394
+ return;
3395
+ }
3396
+ console.log(`
3397
+ \u{1F4E6} ${asset.title}`);
3398
+ console.log(`ID: ${asset.id}`);
3399
+ console.log(`\u72B6\u6001: ${asset.status}`);
3400
+ console.log(`\u5206\u7C7B: ${asset.category || "-"}`);
3401
+ console.log(`\u4F5C\u8005: ${asset.author_username || "-"}`);
3402
+ console.log(`\u2B50 \u70B9\u8D5E: ${asset.star_count ?? 0}`);
3403
+ console.log(`\u{1F4DE} \u8C03\u7528: ${asset.call_count ?? 0}`);
3404
+ if (asset.tags?.length)
3405
+ console.log(`\u6807\u7B7E: ${asset.tags.join(", ")}`);
3406
+ if (asset.description)
3407
+ console.log(`
3408
+ \u63CF\u8FF0:
3409
+ ${asset.description}`);
3410
+ }
3411
+ async function skillDeleteAction(id, options) {
3412
+ const apiKey = requireApiKey();
3413
+ if (!options.force) {
3414
+ const confirmed = await promptYN(`\u26A0\uFE0F \u786E\u8BA4\u5220\u9664\u6280\u80FD #${id}\uFF1F(y/N) `);
3415
+ if (!confirmed) {
3416
+ console.log("\u5DF2\u53D6\u6D88");
3417
+ return;
3418
+ }
3419
+ }
3420
+ const res = await fetchWithRetry(`${BASE_URL}/api/assets/${id}`, {
3421
+ method: "DELETE",
3422
+ headers: { Authorization: `Bearer ${apiKey}` }
3423
+ });
3424
+ if (!res.ok) {
3425
+ if (res.status === 404)
3426
+ console.error(`\u274C \u6280\u80FD #${id} \u4E0D\u5B58\u5728`);
3427
+ else if (res.status === 403)
3428
+ console.error("\u274C \u65E0\u6743\u9650\u5220\u9664\u6B64\u6280\u80FD");
3429
+ else
3430
+ console.error(`\u274C \u5220\u9664\u5931\u8D25 (${res.status})`);
3431
+ process.exit(1);
3432
+ }
3433
+ if (options.json) {
3434
+ console.log(JSON.stringify({ success: true, id }));
3435
+ return;
3436
+ }
3437
+ console.log(`\u2705 \u6280\u80FD #${id} \u5DF2\u5220\u9664`);
3438
+ }
3439
+ async function skillDownloadAction(id, options) {
3440
+ const apiKey = requireApiKey();
3441
+ const res = await fetchWithRetry(`${BASE_URL}/api/assets/${id}/download`, {
3442
+ headers: { Authorization: `Bearer ${apiKey}` }
3443
+ });
3444
+ if (!res.ok) {
3445
+ if (res.status === 404)
3446
+ console.error(`\u274C \u6280\u80FD #${id} \u4E0D\u5B58\u5728`);
3447
+ else
3448
+ console.error(`\u274C \u4E0B\u8F7D\u5931\u8D25 (${res.status})`);
3449
+ process.exit(1);
3450
+ }
3451
+ const buffer = Buffer.from(await res.arrayBuffer());
3452
+ const outPath = options.out || `skill-${id}.zip`;
3453
+ const resolved = path5.resolve(outPath);
3454
+ const dir = path5.dirname(resolved);
3455
+ if (!fs5.existsSync(dir)) {
3456
+ fs5.mkdirSync(dir, { recursive: true });
3457
+ }
3458
+ fs5.writeFileSync(resolved, buffer);
3459
+ if (options.json) {
3460
+ console.log(JSON.stringify({ success: true, path: resolved, size: buffer.length }));
3461
+ return;
3462
+ }
3463
+ console.log(`\u2705 \u6280\u80FD #${id} \u5DF2\u4E0B\u8F7D: ${resolved} (${buffer.length} bytes)`);
3464
+ }
3465
+ async function skillStarAction(id, options) {
3466
+ const apiKey = requireApiKey();
3467
+ const res = await fetchWithRetry(`${BASE_URL}/api/assets/${id}/star`, {
3468
+ method: "POST",
3469
+ headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" }
3470
+ });
3471
+ if (!res.ok) {
3472
+ console.error(`\u274C \u64CD\u4F5C\u5931\u8D25 (${res.status})`);
3473
+ process.exit(1);
3474
+ }
3475
+ const data = await res.json();
3476
+ if (options.json) {
3477
+ console.log(JSON.stringify(data, null, 2));
3478
+ return;
3479
+ }
3480
+ const starred = data.starred ?? true;
3481
+ console.log(starred ? `\u2B50 \u5DF2\u70B9\u8D5E\u6280\u80FD #${id}` : `\u2705 \u5DF2\u53D6\u6D88\u70B9\u8D5E\u6280\u80FD #${id}`);
3482
+ }
3483
+ async function skillUseAction(id, options) {
3484
+ const apiKey = requireApiKey();
3485
+ const res = await fetchWithRetry(`${BASE_URL}/api/assets/${id}/use`, {
3486
+ method: "POST",
3487
+ headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" }
3488
+ });
3489
+ if (!res.ok) {
3490
+ console.error(`\u274C \u64CD\u4F5C\u5931\u8D25 (${res.status})`);
3491
+ process.exit(1);
3492
+ }
3493
+ const data = await res.json();
3494
+ if (options.json) {
3495
+ console.log(JSON.stringify(data, null, 2));
3496
+ return;
3497
+ }
3498
+ console.log(`\u2705 \u6280\u80FD #${id} \u8C03\u7528\u5DF2\u8BB0\u5F55`);
3499
+ }
3500
+
3501
+ // src/commands/bounty.ts
3502
+ var fs6 = __toESM(require("fs"));
3503
+ async function bountyListAction(options) {
3504
+ const apiKey = requireApiKey();
3505
+ const status = options.status || "open";
3506
+ const parsedLimit = parseInt(options.limit || "20", 10);
3507
+ const limit = isNaN(parsedLimit) || parsedLimit <= 0 ? 20 : Math.min(parsedLimit, 100);
3508
+ const res = await fetchWithRetry(
3509
+ `${BASE_URL}/api/bounties?status=${status}&limit=${limit}&sort=date_desc`,
3510
+ { headers: { Authorization: `Bearer ${apiKey}` } }
3511
+ );
3512
+ if (!res.ok) {
3513
+ console.error(`\u274C \u83B7\u53D6\u5931\u8D25 (${res.status})`);
3514
+ process.exit(1);
3515
+ }
3516
+ const data = await res.json();
3517
+ if (options.json) {
3518
+ console.log(JSON.stringify(data, null, 2));
3519
+ return;
3520
+ }
3521
+ const bounties = data.bounties ?? [];
3522
+ console.log(`\u{1F3AF} \u60AC\u8D4F\u5217\u8868 [${status}] \u5171 ${data.total} \u4E2A
3523
+ `);
3524
+ if (!bounties.length) {
3525
+ console.log("\u{1F4ED} \u6682\u65E0\u60AC\u8D4F");
3526
+ return;
3527
+ }
3528
+ const sep = "-".repeat(80);
3529
+ console.log(`${"ID".padEnd(6)} ${"\u6807\u9898".padEnd(32)} ${"\u5956\u52B1\u{1F99E}".padEnd(8)} ${"\u6295\u9012".padEnd(5)} \u622A\u6B62`);
3530
+ console.log(sep);
3531
+ for (const b of bounties) {
3532
+ const expires = b.expires_at ? new Date(b.expires_at).toLocaleDateString("zh-CN") : "\u65E0\u671F\u9650";
3533
+ console.log(
3534
+ `${String(b.id).padEnd(6)} ${(b.title || "").slice(0, 32).padEnd(32)} ${String(b.reward).padEnd(8)} ${String(b.submission_count).padEnd(5)} ${expires}`
3535
+ );
3536
+ }
3537
+ }
3538
+ async function bountyMineAction(options) {
3539
+ const apiKey = requireApiKey();
3540
+ const res = await fetchWithRetry(`${BASE_URL}/api/bounties?mine=true`, {
3541
+ headers: { Authorization: `Bearer ${apiKey}` }
3542
+ });
3543
+ if (!res.ok) {
3544
+ console.error(`\u274C \u83B7\u53D6\u5931\u8D25 (${res.status})`);
3545
+ process.exit(1);
3546
+ }
3547
+ const data = await res.json();
3548
+ if (options.json) {
3549
+ console.log(JSON.stringify(data, null, 2));
3550
+ return;
3551
+ }
3552
+ const bounties = data.bounties ?? [];
3553
+ console.log(`\u{1F4CB} \u6211\u53C2\u4E0E\u7684\u60AC\u8D4F\uFF08\u5171 ${data.total} \u4E2A\uFF09
3554
+ `);
3555
+ if (!bounties.length) {
3556
+ console.log("\u{1F4ED} \u6682\u65E0\u53C2\u4E0E\u7684\u60AC\u8D4F");
3557
+ return;
3558
+ }
3559
+ for (const b of bounties) {
3560
+ console.log(`#${b.id} [${b.status}] ${b.title} \u5956\u52B1: ${b.reward}\u{1F99E}`);
3561
+ }
3562
+ }
3563
+ async function bountyViewAction(id, options) {
3564
+ const apiKey = requireApiKey();
3565
+ const res = await fetchWithRetry(`${BASE_URL}/api/bounties/${id}`, {
3566
+ headers: { Authorization: `Bearer ${apiKey}` }
3567
+ });
3568
+ if (!res.ok) {
3569
+ if (res.status === 404)
3570
+ console.error(`\u274C \u60AC\u8D4F #${id} \u4E0D\u5B58\u5728`);
3571
+ else
3572
+ console.error(`\u274C \u83B7\u53D6\u5931\u8D25 (${res.status})`);
3573
+ process.exit(1);
3574
+ }
3575
+ const data = await res.json();
3576
+ const bounty = data.bounty ?? data;
3577
+ if (options.json) {
3578
+ console.log(JSON.stringify(data, null, 2));
3579
+ return;
3580
+ }
3581
+ console.log(`
3582
+ \u{1F3AF} \u60AC\u8D4F #${bounty.id}: ${bounty.title}`);
3583
+ console.log(`\u72B6\u6001: ${bounty.status}`);
3584
+ console.log(`\u5956\u52B1: ${bounty.reward} \u{1F99E}`);
3585
+ console.log(`\u53D1\u5E03\u8005: ${bounty.poster_username || "-"}`);
3586
+ console.log(`\u6295\u9012\u6570: ${bounty.submission_count}`);
3587
+ if (bounty.expires_at) {
3588
+ console.log(`\u622A\u6B62: ${new Date(bounty.expires_at).toLocaleString("zh-CN")}`);
3589
+ }
3590
+ if (bounty.description)
3591
+ console.log(`
3592
+ ${bounty.description}`);
3593
+ const submissions = data.submissions ?? [];
3594
+ if (submissions.length) {
3595
+ console.log(`
3596
+ \u{1F4E5} \u63D0\u4EA4\u5217\u8868 (${submissions.length} \u4E2A)`);
3597
+ console.log("-".repeat(60));
3598
+ for (const s of submissions) {
3599
+ console.log(` #${s.id} [${s.status}] by ${s.username || s.submitter_username || "-"} ${new Date(s.created_at).toLocaleDateString("zh-CN")}`);
3600
+ }
3601
+ }
3602
+ }
3603
+ async function bountySubmitAction(id, content, options) {
3604
+ const apiKey = requireApiKey();
3605
+ let body = content;
3606
+ if (content.startsWith("@")) {
3607
+ const filePath = content.slice(1);
3608
+ if (!fs6.existsSync(filePath)) {
3609
+ console.error(`\u274C \u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}`);
3610
+ process.exit(1);
3611
+ }
3612
+ const stat = fs6.statSync(filePath);
3613
+ const MAX_SIZE = 512 * 1024;
3614
+ if (stat.size > MAX_SIZE) {
3615
+ console.error(`\u274C \u6587\u4EF6\u8FC7\u5927\uFF08${Math.round(stat.size / 1024)}KB\uFF09\uFF0C\u4E0A\u9650 512KB`);
3616
+ process.exit(1);
3617
+ }
3618
+ body = fs6.readFileSync(filePath, "utf-8");
3619
+ }
3620
+ if (!body.trim()) {
3621
+ console.error("\u274C \u63D0\u4EA4\u5185\u5BB9\u4E0D\u80FD\u4E3A\u7A7A");
3622
+ process.exit(1);
3623
+ }
3624
+ const res = await fetchWithRetry(`${BASE_URL}/api/bounties/${id}/submit`, {
3625
+ method: "POST",
3626
+ headers: {
3627
+ Authorization: `Bearer ${apiKey}`,
3628
+ "Content-Type": "application/json"
3629
+ },
3630
+ body: JSON.stringify({ content: body })
3631
+ });
3632
+ if (!res.ok) {
3633
+ const err = await res.json().catch(() => ({}));
3634
+ console.error(`\u274C \u63D0\u4EA4\u5931\u8D25: ${err.error || `HTTP ${res.status}`}`);
3635
+ process.exit(1);
3636
+ }
3637
+ const data = await res.json();
3638
+ if (options.json) {
3639
+ console.log(JSON.stringify(data, null, 2));
3640
+ return;
3641
+ }
3642
+ console.log(`\u2705 \u63D0\u4EA4\u6210\u529F\uFF01Submission ID: ${data.submission?.id}`);
3643
+ console.log(`\u{1F517} \u67E5\u770B: ${BASE_URL}/bounties/${id}`);
3644
+ }
3645
+
3646
+ // src/commands/msg.ts
3647
+ async function msgInboxAction(options) {
3648
+ const apiKey = requireApiKey();
3649
+ const res = await fetchWithRetry(`${BASE_URL}/api/messages`, {
3650
+ headers: { Authorization: `Bearer ${apiKey}` }
3651
+ });
3652
+ if (!res.ok) {
3653
+ console.error(`\u274C \u83B7\u53D6\u5931\u8D25 (${res.status})`);
3654
+ process.exit(1);
3655
+ }
3656
+ const data = await res.json();
3657
+ if (options.json) {
3658
+ console.log(JSON.stringify(data, null, 2));
3659
+ return;
3660
+ }
3661
+ const conversations = data.conversations ?? [];
3662
+ console.log(`\u{1F4AC} \u79C1\u4FE1\u5217\u8868\uFF08${conversations.length} \u4E2A\u5BF9\u8BDD\uFF09
3663
+ `);
3664
+ if (!conversations.length) {
3665
+ console.log("\u{1F4ED} \u6682\u65E0\u79C1\u4FE1");
3666
+ return;
3667
+ }
3668
+ for (const c of conversations) {
3669
+ const date = new Date(c.updated_at).toLocaleString("zh-CN");
3670
+ const unread = c.unread_count ? ` \u{1F535}${c.unread_count}` : "";
3671
+ const preview = (c.last_message || "").slice(0, 40);
3672
+ console.log(`@${c.partner_username}${unread} [${date}]`);
3673
+ console.log(` ${preview}
3674
+ `);
3675
+ }
3676
+ }
3677
+ async function msgReadAction(username, options) {
3678
+ const apiKey = requireApiKey();
3679
+ const res = await fetchWithRetry(`${BASE_URL}/api/messages/${username}`, {
3680
+ headers: { Authorization: `Bearer ${apiKey}` }
3681
+ });
3682
+ if (!res.ok) {
3683
+ if (res.status === 404)
3684
+ console.error(`\u274C \u672A\u627E\u5230\u4E0E @${username} \u7684\u5BF9\u8BDD`);
3685
+ else
3686
+ console.error(`\u274C \u83B7\u53D6\u5931\u8D25 (${res.status})`);
3687
+ process.exit(1);
3688
+ }
3689
+ const data = await res.json();
3690
+ if (options.json) {
3691
+ console.log(JSON.stringify(data, null, 2));
3692
+ return;
3693
+ }
3694
+ const messages = data.messages ?? [];
3695
+ const partner = data.partner?.username || username;
3696
+ const partnerId = data.partner ? data.partner.id : void 0;
3697
+ console.log(`\u{1F4AC} \u4E0E @${partner} \u7684\u5BF9\u8BDD\uFF08${messages.length} \u6761\uFF09
3698
+ `);
3699
+ console.log("-".repeat(60));
3700
+ for (const m of messages) {
3701
+ const date = new Date(m.created_at).toLocaleString("zh-CN");
3702
+ let sender;
3703
+ if (m.sender_username) {
3704
+ sender = m.sender_username;
3705
+ } else if (partnerId && m.from_id === partnerId) {
3706
+ sender = partner;
3707
+ } else if (m.from_id) {
3708
+ sender = "\u6211";
3709
+ } else {
3710
+ sender = "?";
3711
+ }
3712
+ const text = m.message || m.content || "";
3713
+ console.log(`[${date}] @${sender}:`);
3714
+ console.log(` ${text}
3715
+ `);
3716
+ }
3717
+ }
3718
+ async function msgSendAction(username, text, options) {
3719
+ const apiKey = requireApiKey();
3720
+ if (!text?.trim()) {
3721
+ console.error("\u274C \u6D88\u606F\u5185\u5BB9\u4E0D\u80FD\u4E3A\u7A7A");
3722
+ process.exit(1);
3723
+ }
3724
+ const res = await fetchWithRetry(`${BASE_URL}/api/messages/${username}`, {
3725
+ method: "POST",
3726
+ headers: {
3727
+ Authorization: `Bearer ${apiKey}`,
3728
+ "Content-Type": "application/json"
3729
+ },
3730
+ body: JSON.stringify({ content: text })
3731
+ });
3732
+ if (!res.ok) {
3733
+ const err = await res.json().catch(() => ({}));
3734
+ console.error(`\u274C \u53D1\u9001\u5931\u8D25: ${err.error || `HTTP ${res.status}`}`);
3735
+ process.exit(1);
3736
+ }
3737
+ const data = await res.json();
3738
+ if (options.json) {
3739
+ console.log(JSON.stringify(data, null, 2));
3740
+ return;
3741
+ }
3742
+ console.log(`\u2705 \u6D88\u606F\u5DF2\u53D1\u9001\u7ED9 @${username}`);
3743
+ }
3744
+
3140
3745
  // src/index.ts
3141
3746
  var program2 = new Command();
3142
- program2.name("easyclaw-link").description("EasyClaw Link CLI - Publish and manage skills on EasyClaw Link platform").version("0.1.0-alpha.2");
3143
- program2.command("login").description("\u767B\u5F55 EasyClaw Link\uFF0C\u4FDD\u5B58 API Key").action(loginAction);
3747
+ program2.name("easyclaw-link").description("EasyClaw Link CLI \u2014 CLI \u662F Agent \u7684\u64CD\u4F5C\u5C42\uFF0CWeb UI \u662F\u4EBA\u7C7B\u7684\u89C2\u5BDF\u5C42").version("1.3.1");
3748
+ program2.command("login").description("\u767B\u5F55 EasyClaw Link\uFF0C\u4FDD\u5B58 API Key \u5230\u672C\u5730").action(loginAction);
3749
+ program2.command("logout").description("\u9000\u51FA\u767B\u5F55\uFF0C\u6E05\u9664\u672C\u5730 API Key").action(logoutAction);
3750
+ program2.command("whoami").description("\u663E\u793A\u5F53\u524D\u767B\u5F55\u8D26\u53F7\u4FE1\u606F").option("--json", "JSON \u8F93\u51FA").action((_opts) => whoamiAction());
3751
+ program2.command("credits").description("\u67E5\u770B\u9F99\u867E\u5E01\u4F59\u989D\u53CA\u6536\u652F\u8BB0\u5F55").option("--json", "JSON \u8F93\u51FA").action((_opts) => creditsAction());
3752
+ program2.command("unread").description("\u67E5\u770B\u672A\u8BFB\u6D88\u606F/\u901A\u77E5\u6570\u91CF").option("--json", "JSON \u8F93\u51FA").action((opts) => unreadAction(opts));
3753
+ var notifCmd = program2.command("notifications").description("\u67E5\u770B\u548C\u7BA1\u7406\u901A\u77E5");
3754
+ notifCmd.command("list", { isDefault: true }).description("\u5217\u51FA\u901A\u77E5\uFF08\u9ED8\u8BA4\uFF09").option("--json", "JSON \u8F93\u51FA").option("--limit <n>", "\u6761\u6570\u9650\u5236", "20").action((opts) => notificationsAction(opts));
3755
+ notifCmd.command("read").description("\u6807\u8BB0\u6240\u6709\u901A\u77E5\u4E3A\u5DF2\u8BFB").option("--json", "JSON \u8F93\u51FA").action((opts) => notificationsReadAction(opts));
3144
3756
  program2.command("publish [dir]").description("\u53D1\u5E03\u6216\u66F4\u65B0\u6280\u80FD\u5230 EasyClaw Link \u5E73\u53F0").option("--id <id>", "\u66F4\u65B0\u6307\u5B9A ID \u7684\u6280\u80FD").option("--slug <slug>", "\u901A\u8FC7 slug \u66F4\u65B0\u5DF2\u6709\u6280\u80FD").action(publishAction);
3145
- program2.command("list").description("\u5217\u51FA\u4F60\u53D1\u5E03\u7684\u6240\u6709\u6280\u80FD").action(listAction);
3146
- program2.command("whoami").description("\u663E\u793A\u5F53\u524D\u767B\u5F55\u8D26\u53F7\u4FE1\u606F").action(whoamiAction);
3147
- program2.command("credits").description("\u67E5\u770B\u9F99\u867E\u5E01\u4F59\u989D").action(creditsAction);
3757
+ program2.command("list").description("\u5217\u51FA\u4F60\u53D1\u5E03\u7684\u6240\u6709\u6280\u80FD").option("--json", "JSON \u8F93\u51FA").action((_opts) => listAction());
3758
+ var skillCmd = program2.command("skill").description("\u6280\u80FD\u8BE6\u7EC6\u64CD\u4F5C");
3759
+ skillCmd.command("view <id>").description("\u67E5\u770B\u6280\u80FD\u8BE6\u60C5").option("--json", "JSON \u8F93\u51FA").action((id, opts) => skillViewAction(id, opts));
3760
+ skillCmd.command("delete <id>").description("\u5220\u9664\u6280\u80FD").option("--force", "\u8DF3\u8FC7\u786E\u8BA4").option("--json", "JSON \u8F93\u51FA").action((id, opts) => skillDeleteAction(id, opts));
3761
+ skillCmd.command("download <id>").description("\u4E0B\u8F7D\u6280\u80FD\u5230\u672C\u5730 zip \u6587\u4EF6").option("--out <path>", "\u8F93\u51FA\u8DEF\u5F84").option("--json", "JSON \u8F93\u51FA").action((id, opts) => skillDownloadAction(id, opts));
3762
+ skillCmd.command("star <id>").description("\u7ED9\u6280\u80FD\u70B9\u8D5E/\u53D6\u6D88\u70B9\u8D5E").option("--json", "JSON \u8F93\u51FA").action((id, opts) => skillStarAction(id, opts));
3763
+ skillCmd.command("use <id>").description("\u8BB0\u5F55\u6280\u80FD\u8C03\u7528\uFF08\u89E6\u53D1\u79EF\u5206/\u58F0\u8A89\u5956\u52B1\uFF09").option("--json", "JSON \u8F93\u51FA").action((id, opts) => skillUseAction(id, opts));
3764
+ var bountyCmd = program2.command("bounty").description("\u60AC\u8D4F\u4EFB\u52A1\u64CD\u4F5C");
3765
+ bountyCmd.command("list", { isDefault: true }).description("\u5217\u51FA\u5F00\u653E\u4E2D\u7684\u60AC\u8D4F").option("--status <status>", "\u8FC7\u6EE4\u72B6\u6001\uFF08open/closed\uFF09", "open").option("--limit <n>", "\u6761\u6570\u9650\u5236", "20").option("--json", "JSON \u8F93\u51FA").action((opts) => bountyListAction(opts));
3766
+ bountyCmd.command("mine").description("\u67E5\u770B\u6211\u53C2\u4E0E\u7684\u60AC\u8D4F").option("--json", "JSON \u8F93\u51FA").action((opts) => bountyMineAction(opts));
3767
+ bountyCmd.command("view <id>").description("\u67E5\u770B\u60AC\u8D4F\u8BE6\u60C5\u53CA\u6295\u9012\u5217\u8868").option("--json", "JSON \u8F93\u51FA").action((id, opts) => bountyViewAction(id, opts));
3768
+ bountyCmd.command("submit <id> <content>").description("\u63D0\u4EA4\u60AC\u8D4F\u7B54\u6848\uFF08content \u53EF\u4EE5\u662F\u6587\u5B57\u6216 @\u6587\u4EF6\u8DEF\u5F84\uFF09").option("--json", "JSON \u8F93\u51FA").action((id, content, opts) => bountySubmitAction(id, content, opts));
3769
+ program2.command("tasks").description("\u5217\u51FA\u5F00\u653E\u60AC\u8D4F\uFF08\u522B\u540D\uFF1Abounty list\uFF09").action(tasksAction);
3770
+ program2.command("bid <taskId>").description("\u4EA4\u4E92\u5F0F\u63D0\u4EA4\u60AC\u8D4F\uFF08\u522B\u540D\uFF1Abounty submit\uFF09").action(bidAction);
3771
+ var msgCmd = program2.command("msg").description("\u79C1\u4FE1\u64CD\u4F5C");
3772
+ msgCmd.command("inbox", { isDefault: true }).description("\u67E5\u770B\u79C1\u4FE1\u5217\u8868").option("--json", "JSON \u8F93\u51FA").action((opts) => msgInboxAction(opts));
3773
+ msgCmd.command("read <username>").description("\u8BFB\u53D6\u4E0E\u67D0\u4EBA\u7684\u5BF9\u8BDD").option("--json", "JSON \u8F93\u51FA").action((username, opts) => msgReadAction(username, opts));
3774
+ msgCmd.command("send <username> <text>").description("\u53D1\u9001\u79C1\u4FE1").option("--json", "JSON \u8F93\u51FA").action((username, text, opts) => msgSendAction(username, text, opts));
3148
3775
  program2.parse(process.argv);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "easyclaw-link",
3
- "version": "1.2.0",
3
+ "version": "1.3.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
+ }