skill-atlas-cli 0.1.17 → 0.1.18

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/lib/index.js +138 -117
  2. package/package.json +4 -4
package/lib/index.js CHANGED
@@ -1,12 +1,13 @@
1
1
  import fs, { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
2
  import path, { join } from "node:path";
3
- import os, { homedir } from "node:os";
4
3
  import semver from "semver";
4
+ import os from "node:os";
5
+ import crypto from "node:crypto";
5
6
  import * as p from "@clack/prompts";
6
7
  import chalk from "chalk";
7
8
  import path$1, { basename, dirname, join as join$1, normalize, relative, resolve, sep } from "path";
8
9
  import { existsSync as existsSync$1, writeFileSync as writeFileSync$1 } from "fs";
9
- import os$1, { homedir as homedir$1, platform, tmpdir } from "os";
10
+ import os$1, { homedir, platform, tmpdir } from "os";
10
11
  import * as readline from "readline";
11
12
  import { Writable } from "stream";
12
13
  import { cp, lstat, mkdir, readdir, readlink, realpath, rename, rm, stat, symlink, unlink, writeFile } from "fs/promises";
@@ -36,113 +37,10 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
36
37
  enumerable: true
37
38
  }) : target, mod));
38
39
  //#endregion
39
- //#region src/core/update-notifier.ts
40
- /**
41
- * npm 包更新检查:有新版本时提示无需重装,直接 npm update 即可
42
- */
43
- const CACHE_DIR = process.env.XDG_CONFIG_HOME || join(homedir(), ".config", "skill-atlas");
44
- const CACHE_FILE = join(CACHE_DIR, "update-check.json");
45
- const CHECK_INTERVAL = 1e3 * 60 * 60 * 24;
46
- async function fetchLatestVersion(pkgName) {
47
- return (await (await fetch(`https://registry.npmjs.org/-/package/${pkgName}/dist-tags`)).json()).latest || "0.0.0";
48
- }
49
- function getLastCheck() {
50
- try {
51
- if (!existsSync(CACHE_FILE)) return void 0;
52
- return JSON.parse(readFileSync(CACHE_FILE, "utf8")).lastCheck;
53
- } catch {
54
- return;
55
- }
56
- }
57
- function saveLastCheck() {
58
- try {
59
- if (!existsSync(CACHE_DIR)) mkdirSync(CACHE_DIR, { recursive: true });
60
- writeFileSync(CACHE_FILE, JSON.stringify({ lastCheck: Date.now() }) + "\n");
61
- } catch {}
62
- }
63
- /**
64
- * 检查更新,有新版本时输出提示(无需重装,直接 update)
65
- */
66
- function checkForUpdate(pkg) {
67
- if (!process.stdout.isTTY) return;
68
- const lastCheck = getLastCheck();
69
- if (lastCheck && Date.now() - lastCheck < CHECK_INTERVAL) return;
70
- fetchLatestVersion(pkg.name).then((latest) => {
71
- saveLastCheck();
72
- if (semver.gt(latest, pkg.version)) console.error(`\n Update available: ${pkg.version} → ${latest}\n No need to reinstall. Run: npm update -g ${pkg.name}\n`);
73
- }).catch(() => {});
74
- }
75
- //#endregion
76
40
  //#region src/core/config.ts
77
- var import_picocolors = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {
78
- let p = process || {}, argv = p.argv || [], env = p.env || {};
79
- let isColorSupported = !(!!env.NO_COLOR || argv.includes("--no-color")) && (!!env.FORCE_COLOR || argv.includes("--color") || p.platform === "win32" || (p.stdout || {}).isTTY && env.TERM !== "dumb" || !!env.CI);
80
- let formatter = (open, close, replace = open) => (input) => {
81
- let string = "" + input, index = string.indexOf(close, open.length);
82
- return ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close;
83
- };
84
- let replaceClose = (string, close, replace, index) => {
85
- let result = "", cursor = 0;
86
- do {
87
- result += string.substring(cursor, index) + replace;
88
- cursor = index + close.length;
89
- index = string.indexOf(close, cursor);
90
- } while (~index);
91
- return result + string.substring(cursor);
92
- };
93
- let createColors = (enabled = isColorSupported) => {
94
- let f = enabled ? formatter : () => String;
95
- return {
96
- isColorSupported: enabled,
97
- reset: f("\x1B[0m", "\x1B[0m"),
98
- bold: f("\x1B[1m", "\x1B[22m", "\x1B[22m\x1B[1m"),
99
- dim: f("\x1B[2m", "\x1B[22m", "\x1B[22m\x1B[2m"),
100
- italic: f("\x1B[3m", "\x1B[23m"),
101
- underline: f("\x1B[4m", "\x1B[24m"),
102
- inverse: f("\x1B[7m", "\x1B[27m"),
103
- hidden: f("\x1B[8m", "\x1B[28m"),
104
- strikethrough: f("\x1B[9m", "\x1B[29m"),
105
- black: f("\x1B[30m", "\x1B[39m"),
106
- red: f("\x1B[31m", "\x1B[39m"),
107
- green: f("\x1B[32m", "\x1B[39m"),
108
- yellow: f("\x1B[33m", "\x1B[39m"),
109
- blue: f("\x1B[34m", "\x1B[39m"),
110
- magenta: f("\x1B[35m", "\x1B[39m"),
111
- cyan: f("\x1B[36m", "\x1B[39m"),
112
- white: f("\x1B[37m", "\x1B[39m"),
113
- gray: f("\x1B[90m", "\x1B[39m"),
114
- bgBlack: f("\x1B[40m", "\x1B[49m"),
115
- bgRed: f("\x1B[41m", "\x1B[49m"),
116
- bgGreen: f("\x1B[42m", "\x1B[49m"),
117
- bgYellow: f("\x1B[43m", "\x1B[49m"),
118
- bgBlue: f("\x1B[44m", "\x1B[49m"),
119
- bgMagenta: f("\x1B[45m", "\x1B[49m"),
120
- bgCyan: f("\x1B[46m", "\x1B[49m"),
121
- bgWhite: f("\x1B[47m", "\x1B[49m"),
122
- blackBright: f("\x1B[90m", "\x1B[39m"),
123
- redBright: f("\x1B[91m", "\x1B[39m"),
124
- greenBright: f("\x1B[92m", "\x1B[39m"),
125
- yellowBright: f("\x1B[93m", "\x1B[39m"),
126
- blueBright: f("\x1B[94m", "\x1B[39m"),
127
- magentaBright: f("\x1B[95m", "\x1B[39m"),
128
- cyanBright: f("\x1B[96m", "\x1B[39m"),
129
- whiteBright: f("\x1B[97m", "\x1B[39m"),
130
- bgBlackBright: f("\x1B[100m", "\x1B[49m"),
131
- bgRedBright: f("\x1B[101m", "\x1B[49m"),
132
- bgGreenBright: f("\x1B[102m", "\x1B[49m"),
133
- bgYellowBright: f("\x1B[103m", "\x1B[49m"),
134
- bgBlueBright: f("\x1B[104m", "\x1B[49m"),
135
- bgMagentaBright: f("\x1B[105m", "\x1B[49m"),
136
- bgCyanBright: f("\x1B[106m", "\x1B[49m"),
137
- bgWhiteBright: f("\x1B[107m", "\x1B[49m")
138
- };
139
- };
140
- module.exports = createColors();
141
- module.exports.createColors = createColors;
142
- })))(), 1);
143
- const CONFIG_DIR = path.join(os.homedir(), ".openclawmp");
41
+ const CONFIG_DIR = path.join(os.homedir(), ".skillatlas");
144
42
  const AUTH_FILE = path.join(CONFIG_DIR, "auth.json");
145
- const CREDENTIALS_FILE = path.join(CONFIG_DIR, "credentials.json");
43
+ const AGENT_ID_FILE = path.join(CONFIG_DIR, "skillatlas-meta.json");
146
44
  let API_BASE = "https://skillatlas.cn/";
147
45
  const OPENCLAW_STATE_DIR = process.env.OPENCLAW_STATE_DIR || path.join(os.homedir(), ".openclaw");
148
46
  const LOCKFILE = path.join(OPENCLAW_STATE_DIR, "seafood-lock.json");
@@ -187,10 +85,6 @@ function getAuthToken() {
187
85
  const data = JSON.parse(fs.readFileSync(AUTH_FILE, "utf-8"));
188
86
  if (data.token) return data.token;
189
87
  } catch {}
190
- if (fs.existsSync(CREDENTIALS_FILE)) try {
191
- const data = JSON.parse(fs.readFileSync(CREDENTIALS_FILE, "utf-8"));
192
- if (data.api_key) return data.api_key;
193
- } catch {}
194
88
  return null;
195
89
  }
196
90
  /**
@@ -217,6 +111,21 @@ function getDeviceId() {
217
111
  }
218
112
  }
219
113
  /**
114
+ * Get or generate the agent ID
115
+ */
116
+ function getAgentId() {
117
+ ensureConfigDir();
118
+ let data = {};
119
+ if (fs.existsSync(AGENT_ID_FILE)) try {
120
+ data = JSON.parse(fs.readFileSync(AGENT_ID_FILE, "utf-8"));
121
+ if (data.agent_id) return data.agent_id;
122
+ } catch {}
123
+ const newId = crypto.randomUUID();
124
+ data.agent_id = newId;
125
+ fs.writeFileSync(AGENT_ID_FILE, JSON.stringify(data, null, 2) + "\n");
126
+ return newId;
127
+ }
128
+ /**
220
129
  * Initialize lockfile if it doesn't exist
221
130
  */
222
131
  function initLockfile() {
@@ -279,10 +188,122 @@ var config_default = {
279
188
  initLockfile,
280
189
  readLockfile,
281
190
  updateLockfile,
282
- removeLockfile
191
+ removeLockfile,
192
+ getAgentId
283
193
  };
284
194
  //#endregion
195
+ //#region src/core/update-notifier.ts
196
+ /**
197
+ * npm 包更新检查:有新版本时提示无需重装,直接 npm update 即可
198
+ */
199
+ const CACHE_DIR = config_default.CONFIG_DIR;
200
+ const CACHE_FILE = join(CACHE_DIR, "update-check.json");
201
+ const CHECK_INTERVAL = 1e3 * 60 * 60;
202
+ async function fetchLatestVersion(pkgName) {
203
+ const baseUrl = (process.env.npm_config_registry || "https://registry.npmjs.org").replace(/\/$/, "");
204
+ const res = await fetch(`${baseUrl}/-/package/${pkgName}/dist-tags`, { signal: AbortSignal.timeout(3e3) });
205
+ if (!res.ok) throw new Error("Fetch failed");
206
+ return (await res.json()).latest || "0.0.0";
207
+ }
208
+ function getCache() {
209
+ try {
210
+ if (!existsSync(CACHE_FILE)) return void 0;
211
+ return JSON.parse(readFileSync(CACHE_FILE, "utf8"));
212
+ } catch {
213
+ return;
214
+ }
215
+ }
216
+ function saveCache(latest) {
217
+ try {
218
+ if (!existsSync(CACHE_DIR)) mkdirSync(CACHE_DIR, { recursive: true });
219
+ writeFileSync(CACHE_FILE, JSON.stringify({
220
+ lastCheck: Date.now(),
221
+ latest
222
+ }) + "\n");
223
+ } catch {}
224
+ }
225
+ /**
226
+ * 检查更新,有新版本时输出提示(无需重装,直接 update)
227
+ */
228
+ function checkForUpdate(pkg) {
229
+ const cache = getCache();
230
+ if (cache?.latest && semver.gt(cache.latest, pkg.version)) {
231
+ if (process.stdout.isTTY) console.error(`\n 📦 Update available: \x1b[31m${pkg.version}\x1b[0m → \x1b[32m${cache.latest}\x1b[0m\n 👉 No need to reinstall. Run: \x1b[36mnpm update -g ${pkg.name}\x1b[0m\n`);
232
+ }
233
+ const lastCheck = cache?.lastCheck || 0;
234
+ if (Date.now() - lastCheck < CHECK_INTERVAL) return;
235
+ fetchLatestVersion(pkg.name).then((latest) => {
236
+ saveCache(latest);
237
+ }).catch(() => {});
238
+ }
239
+ //#endregion
285
240
  //#region src/core/api.ts
241
+ var import_picocolors = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {
242
+ let p = process || {}, argv = p.argv || [], env = p.env || {};
243
+ let isColorSupported = !(!!env.NO_COLOR || argv.includes("--no-color")) && (!!env.FORCE_COLOR || argv.includes("--color") || p.platform === "win32" || (p.stdout || {}).isTTY && env.TERM !== "dumb" || !!env.CI);
244
+ let formatter = (open, close, replace = open) => (input) => {
245
+ let string = "" + input, index = string.indexOf(close, open.length);
246
+ return ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close;
247
+ };
248
+ let replaceClose = (string, close, replace, index) => {
249
+ let result = "", cursor = 0;
250
+ do {
251
+ result += string.substring(cursor, index) + replace;
252
+ cursor = index + close.length;
253
+ index = string.indexOf(close, cursor);
254
+ } while (~index);
255
+ return result + string.substring(cursor);
256
+ };
257
+ let createColors = (enabled = isColorSupported) => {
258
+ let f = enabled ? formatter : () => String;
259
+ return {
260
+ isColorSupported: enabled,
261
+ reset: f("\x1B[0m", "\x1B[0m"),
262
+ bold: f("\x1B[1m", "\x1B[22m", "\x1B[22m\x1B[1m"),
263
+ dim: f("\x1B[2m", "\x1B[22m", "\x1B[22m\x1B[2m"),
264
+ italic: f("\x1B[3m", "\x1B[23m"),
265
+ underline: f("\x1B[4m", "\x1B[24m"),
266
+ inverse: f("\x1B[7m", "\x1B[27m"),
267
+ hidden: f("\x1B[8m", "\x1B[28m"),
268
+ strikethrough: f("\x1B[9m", "\x1B[29m"),
269
+ black: f("\x1B[30m", "\x1B[39m"),
270
+ red: f("\x1B[31m", "\x1B[39m"),
271
+ green: f("\x1B[32m", "\x1B[39m"),
272
+ yellow: f("\x1B[33m", "\x1B[39m"),
273
+ blue: f("\x1B[34m", "\x1B[39m"),
274
+ magenta: f("\x1B[35m", "\x1B[39m"),
275
+ cyan: f("\x1B[36m", "\x1B[39m"),
276
+ white: f("\x1B[37m", "\x1B[39m"),
277
+ gray: f("\x1B[90m", "\x1B[39m"),
278
+ bgBlack: f("\x1B[40m", "\x1B[49m"),
279
+ bgRed: f("\x1B[41m", "\x1B[49m"),
280
+ bgGreen: f("\x1B[42m", "\x1B[49m"),
281
+ bgYellow: f("\x1B[43m", "\x1B[49m"),
282
+ bgBlue: f("\x1B[44m", "\x1B[49m"),
283
+ bgMagenta: f("\x1B[45m", "\x1B[49m"),
284
+ bgCyan: f("\x1B[46m", "\x1B[49m"),
285
+ bgWhite: f("\x1B[47m", "\x1B[49m"),
286
+ blackBright: f("\x1B[90m", "\x1B[39m"),
287
+ redBright: f("\x1B[91m", "\x1B[39m"),
288
+ greenBright: f("\x1B[92m", "\x1B[39m"),
289
+ yellowBright: f("\x1B[93m", "\x1B[39m"),
290
+ blueBright: f("\x1B[94m", "\x1B[39m"),
291
+ magentaBright: f("\x1B[95m", "\x1B[39m"),
292
+ cyanBright: f("\x1B[96m", "\x1B[39m"),
293
+ whiteBright: f("\x1B[97m", "\x1B[39m"),
294
+ bgBlackBright: f("\x1B[100m", "\x1B[49m"),
295
+ bgRedBright: f("\x1B[101m", "\x1B[49m"),
296
+ bgGreenBright: f("\x1B[102m", "\x1B[49m"),
297
+ bgYellowBright: f("\x1B[103m", "\x1B[49m"),
298
+ bgBlueBright: f("\x1B[104m", "\x1B[49m"),
299
+ bgMagentaBright: f("\x1B[105m", "\x1B[49m"),
300
+ bgCyanBright: f("\x1B[106m", "\x1B[49m"),
301
+ bgWhiteBright: f("\x1B[107m", "\x1B[49m")
302
+ };
303
+ };
304
+ module.exports = createColors();
305
+ module.exports.createColors = createColors;
306
+ })))(), 1);
286
307
  /**
287
308
  * Make a GET request to the API
288
309
  * @param {string} apiPath - API path (e.g., '/api/assets')
@@ -292,7 +313,7 @@ var config_default = {
292
313
  async function get(apiPath, params = {}) {
293
314
  const url = new URL(apiPath, config_default.getApiBase());
294
315
  for (const [k, v] of Object.entries(params)) if (v !== void 0 && v !== null && v !== "") url.searchParams.set(k, String(v));
295
- const res = await fetch(url.toString(), {});
316
+ const res = await fetch(url.toString(), { headers: { agent_id: config_default.getAgentId() } });
296
317
  if (!res.ok) {
297
318
  const body = await res.text().catch(() => "");
298
319
  throw new Error(`API error ${res.status}: ${body || res.statusText}`);
@@ -331,7 +352,7 @@ async function downloadSkillPackage(slug, version) {
331
352
  const url = new URL("/api/v1/download", config_default.getApiBase());
332
353
  url.searchParams.set("slug", slug);
333
354
  url.searchParams.set("version", version);
334
- const res = await fetch(url.toString(), {});
355
+ const res = await fetch(url.toString(), { headers: { agent_id: config_default.getAgentId() } });
335
356
  if (!res.ok) {
336
357
  const body = await res.text().catch(() => "");
337
358
  throw new Error(`下载失败 ${res.status}: ${body || res.statusText}。`);
@@ -354,7 +375,7 @@ const xdgConfigDirectories = (env.XDG_CONFIG_DIRS || "/etc/xdg").split(":");
354
375
  if (xdgConfig) xdgConfigDirectories.unshift(xdgConfig);
355
376
  //#endregion
356
377
  //#region src/core/agents.ts
357
- const home = homedir$1();
378
+ const home = homedir();
358
379
  const configHome = xdgConfig ?? join$1(home, ".config");
359
380
  const codexHome = process.env.CODEX_HOME?.trim() || join$1(home, ".codex");
360
381
  const claudeHome = process.env.CLAUDE_CONFIG_DIR?.trim() || join$1(home, ".claude");
@@ -783,7 +804,7 @@ async function downloadAndExtractPackage(asset, targetDir) {
783
804
  }
784
805
  function getAgentBaseDir(agentType, global, cwd) {
785
806
  const agent = agents[agentType];
786
- const baseDir = global ? homedir$1() : cwd || process.cwd();
807
+ const baseDir = global ? homedir() : cwd || process.cwd();
787
808
  if (global) {
788
809
  if (agent.globalSkillsDir === void 0) return join$1(baseDir, agent.skillsDir);
789
810
  return agent.globalSkillsDir;
@@ -863,7 +884,7 @@ function sanitizeName(name) {
863
884
  return name.toLowerCase().replace(/[^a-z0-9._]+/g, "-").replace(/^[.\-]+|[.\-]+$/g, "").substring(0, 255) || "unnamed-skill";
864
885
  }
865
886
  function getCanonicalSkillsDir(global, cwd) {
866
- return join$1(global ? homedir$1() : cwd || process.cwd(), AGENTS_DIR, SKILLS_SUBDIR);
887
+ return join$1(global ? homedir() : cwd || process.cwd(), AGENTS_DIR, SKILLS_SUBDIR);
867
888
  }
868
889
  /**
869
890
  * 将包从 buffer 解压到目标目录
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skill-atlas-cli",
3
- "version": "0.1.17",
3
+ "version": "0.1.18",
4
4
  "description": "skill-atlas CLI - 虾小宝 命令行工具",
5
5
  "homepage": "https://skillatlas.cn/",
6
6
  "type": "module",
@@ -17,9 +17,9 @@
17
17
  "start": "node bin/cli.js",
18
18
  "prepare": "npm run build",
19
19
  "prepublishOnly": "npm run build",
20
- "release:patch": "npm whoami && npm version patch && npm publish --registry https://registry.npmjs.org/",
21
- "release:minor": "npm whoami && npm version minor && npm publish --registry https://registry.npmjs.org/",
22
- "release:major": "npm whoami && npm version major && npm publish --registry https://registry.npmjs.org/"
20
+ "release:patch": "npm whoami && npm version patch && npm publish",
21
+ "release:minor": "npm whoami && npm version minor && npm publish",
22
+ "release:major": "npm whoami && npm version major && npm publish"
23
23
  },
24
24
  "files": [
25
25
  "bin",