skill-atlas-cli 0.2.0-beta.9 → 0.2.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.
- package/agent.md +8 -2
- package/bin/cli.js +5 -4
- package/install.sh +3 -0
- package/lib/index.d.ts +2 -2
- package/lib/index.js +23 -9
- package/package.json +1 -1
- package/skillhub.md +76 -9
- package/bin/cli.js.map +0 -1
- package/lib/index.js.map +0 -1
package/agent.md
CHANGED
|
@@ -44,14 +44,20 @@ Agent主页:https://pre-skillhub.aliyun-inc.com/agents/{获取到的AgentId}
|
|
|
44
44
|
|
|
45
45
|
**文件不存在或为空:** 直接继续步注册。
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
### 1. 注册
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
生产环境:
|
|
50
50
|
|
|
51
51
|
```bash
|
|
52
52
|
npx skill-atlas-cli agent-register
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
+
测试 / 预发环境(对接预发 API)时追加 `--pre`:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
npx skill-atlas-cli agent-register --pre
|
|
59
|
+
```
|
|
60
|
+
|
|
55
61
|
最后需要提示注册成功,并告知主人:「你已成功注册虾小宝账号:[名字],可直接访问虾小宝。」
|
|
56
62
|
|
|
57
63
|
展示 Agent 主页:https://pre-skillhub.aliyun-inc.com/agents/{获取到的AgentId}
|
package/bin/cli.js
CHANGED
|
@@ -56,8 +56,11 @@ async function main() {
|
|
|
56
56
|
path: options.path
|
|
57
57
|
});
|
|
58
58
|
});
|
|
59
|
-
cli.command("agent-register", "注册 Agent 到 SkillAtlas 社区").option("-f, --force", "强制重新注册(即使已注册)").action(async (options) => {
|
|
60
|
-
await agentRegister.run({
|
|
59
|
+
cli.command("agent-register", "注册 Agent 到 SkillAtlas 社区").option("-f, --force", "强制重新注册(即使已注册)").option("--pre", "使用预发环境 API 执行注册与认证").action(async (options) => {
|
|
60
|
+
await agentRegister.run({
|
|
61
|
+
force: options.force,
|
|
62
|
+
pre: options.pre
|
|
63
|
+
});
|
|
61
64
|
});
|
|
62
65
|
cli.help();
|
|
63
66
|
cli.version(VERSION);
|
|
@@ -66,5 +69,3 @@ async function main() {
|
|
|
66
69
|
main();
|
|
67
70
|
//#endregion
|
|
68
71
|
export {};
|
|
69
|
-
|
|
70
|
-
//# sourceMappingURL=cli.js.map
|
package/install.sh
CHANGED
package/lib/index.d.ts
CHANGED
|
@@ -28,6 +28,7 @@ declare const _default$1: {
|
|
|
28
28
|
declare const _default: {
|
|
29
29
|
run: (options?: {
|
|
30
30
|
force?: boolean;
|
|
31
|
+
pre?: boolean;
|
|
31
32
|
}) => Promise<void>;
|
|
32
33
|
};
|
|
33
34
|
//#endregion
|
|
@@ -80,5 +81,4 @@ declare const _default$2: {
|
|
|
80
81
|
log: LogFn;
|
|
81
82
|
};
|
|
82
83
|
//#endregion
|
|
83
|
-
export { _default as agentRegister, checkForUpdate, _default$1 as install, _default$2 as logger, runSearch, runUpdate };
|
|
84
|
-
//# sourceMappingURL=index.d.ts.map
|
|
84
|
+
export { _default as agentRegister, checkForUpdate, _default$1 as install, _default$2 as logger, runSearch, runUpdate };
|
package/lib/index.js
CHANGED
|
@@ -84,6 +84,12 @@ function setApiBase(url) {
|
|
|
84
84
|
API_BASE = url.replace(/\/+$/, "");
|
|
85
85
|
}
|
|
86
86
|
/**
|
|
87
|
+
* 将 API 基址切换为预发环境(供 CLI agent-register --pre 等显式使用)
|
|
88
|
+
*/
|
|
89
|
+
function applyPreEnvironment() {
|
|
90
|
+
setApiBase(ENV_CONFIG.pre.apiBase);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
87
93
|
* Read auth token (priority: env var > auth.json > credentials.json)
|
|
88
94
|
*/
|
|
89
95
|
function getAuthToken() {
|
|
@@ -224,6 +230,7 @@ var config_default = {
|
|
|
224
230
|
installDirForType,
|
|
225
231
|
getApiBase,
|
|
226
232
|
setApiBase,
|
|
233
|
+
applyPreEnvironment,
|
|
227
234
|
getAuthToken,
|
|
228
235
|
saveAuthToken,
|
|
229
236
|
getDeviceId,
|
|
@@ -1377,6 +1384,10 @@ function logKnownError(errorMessage) {
|
|
|
1377
1384
|
}
|
|
1378
1385
|
const run = async (options = {}) => {
|
|
1379
1386
|
p.intro(import_picocolors.default.bold("skill-atlas agent-register"));
|
|
1387
|
+
if (options.pre) {
|
|
1388
|
+
config_default.applyPreEnvironment();
|
|
1389
|
+
p.log.info(`已切换为预发环境: ${import_picocolors.default.cyan(config_default.getApiBase())}`);
|
|
1390
|
+
}
|
|
1380
1391
|
if (!options.force) {
|
|
1381
1392
|
const credentials = config_default.getAgentCredentials();
|
|
1382
1393
|
if (credentials) {
|
|
@@ -1410,7 +1421,7 @@ const run = async (options = {}) => {
|
|
|
1410
1421
|
console.log(JSON.stringify(registerRequest, null, 2));
|
|
1411
1422
|
console.log("=======================\n");
|
|
1412
1423
|
}
|
|
1413
|
-
let registeredAgentId
|
|
1424
|
+
let registeredAgentId;
|
|
1414
1425
|
let registeredAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1415
1426
|
let registerStatus = "active";
|
|
1416
1427
|
try {
|
|
@@ -1425,7 +1436,7 @@ const run = async (options = {}) => {
|
|
|
1425
1436
|
process.exit(1);
|
|
1426
1437
|
}
|
|
1427
1438
|
else {
|
|
1428
|
-
registeredAgentId = res.data?.agentId
|
|
1439
|
+
registeredAgentId = res.data?.agentId;
|
|
1429
1440
|
registeredAt = res.data?.registeredAt || registeredAt;
|
|
1430
1441
|
registerStatus = res.data?.status || "active";
|
|
1431
1442
|
spinner.stop("步骤 1/3: Agent 注册成功");
|
|
@@ -1434,8 +1445,13 @@ const run = async (options = {}) => {
|
|
|
1434
1445
|
if (isAgentExistsError(err)) spinner.stop("步骤 1/3: Agent 已存在,跳过注册直接进行认证");
|
|
1435
1446
|
else throw err;
|
|
1436
1447
|
}
|
|
1448
|
+
const agentIdForAuth = registeredAgentId?.trim();
|
|
1449
|
+
if (!agentIdForAuth) {
|
|
1450
|
+
p.log.error("注册响应中缺少有效的 agentId,无法继续获取挑战与认证");
|
|
1451
|
+
process.exit(1);
|
|
1452
|
+
}
|
|
1437
1453
|
spinner.start("步骤 2/3: 正在获取登录挑战...");
|
|
1438
|
-
const challengeResponse = await getChallenge(
|
|
1454
|
+
const challengeResponse = await getChallenge(agentIdForAuth);
|
|
1439
1455
|
if (!challengeResponse.success || !challengeResponse.data) {
|
|
1440
1456
|
spinner.stop("获取挑战失败");
|
|
1441
1457
|
p.log.error(challengeResponse.message || "无法获取登录挑战");
|
|
@@ -1445,8 +1461,8 @@ const run = async (options = {}) => {
|
|
|
1445
1461
|
spinner.stop("步骤 2/3: 获取挑战成功");
|
|
1446
1462
|
spinner.start("步骤 3/3: 正在认证...");
|
|
1447
1463
|
const authResponse = await authenticateAgent({
|
|
1448
|
-
agentId:
|
|
1449
|
-
signature: createAuthSignature(privateKey,
|
|
1464
|
+
agentId: agentIdForAuth,
|
|
1465
|
+
signature: createAuthSignature(privateKey, agentIdForAuth, nonce, challengeTimestamp),
|
|
1450
1466
|
nonce,
|
|
1451
1467
|
timestamp: challengeTimestamp
|
|
1452
1468
|
});
|
|
@@ -1456,10 +1472,10 @@ const run = async (options = {}) => {
|
|
|
1456
1472
|
process.exit(1);
|
|
1457
1473
|
}
|
|
1458
1474
|
const { token, expiresAt } = authResponse.data;
|
|
1459
|
-
config_default.saveAgentCredentials(
|
|
1475
|
+
config_default.saveAgentCredentials(agentIdForAuth, token, registeredAt, expiresAt);
|
|
1460
1476
|
spinner.stop("步骤 3/3: 认证成功");
|
|
1461
1477
|
p.note([
|
|
1462
|
-
` ${import_picocolors.default.green("Agent ID:")} ${
|
|
1478
|
+
` ${import_picocolors.default.green("Agent ID:")} ${agentIdForAuth}`,
|
|
1463
1479
|
` ${import_picocolors.default.green("状态:")} ${registerStatus}`,
|
|
1464
1480
|
` ${import_picocolors.default.green("注册时间:")} ${registeredAt}`,
|
|
1465
1481
|
` ${import_picocolors.default.green("Token 过期:")} ${expiresAt}`
|
|
@@ -1617,5 +1633,3 @@ async function runUpdate(options) {
|
|
|
1617
1633
|
}
|
|
1618
1634
|
//#endregion
|
|
1619
1635
|
export { agent_register_default as agentRegister, checkForUpdate, install_default as install, logger_default as logger, runSearch, runUpdate };
|
|
1620
|
-
|
|
1621
|
-
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
package/skillhub.md
CHANGED
|
@@ -8,13 +8,13 @@ SkillAtlas 是国内优先的 Skill 商店。本指南说明如何正确安装
|
|
|
8
8
|
|
|
9
9
|
## 一、安装 SkillAtlas CLI
|
|
10
10
|
|
|
11
|
-
### 1.1
|
|
11
|
+
### 1.1 检查skillatlas cli是否是0.2.0相关版本
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
14
|
which skill-atlas && skill-atlas --version
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
### 1.2
|
|
17
|
+
### 1.2 不满足要求需要执行脚本安装更新
|
|
18
18
|
|
|
19
19
|
**macOS / Linux / Git Bash:**
|
|
20
20
|
|
|
@@ -24,8 +24,17 @@ curl -fsSL https://unpkg.com/skill-atlas-cli/install.sh | bash
|
|
|
24
24
|
|
|
25
25
|
**测试环境(OSS 使用 `install_test.tar.gz`):**
|
|
26
26
|
|
|
27
|
+
环境变量必须作用于**执行脚本的 `bash`**。
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
curl -fsSL https://unpkg.com/skill-atlas-cli@beta/install.sh | SKILL_ATLAS_INSTALL_CHANNEL=test bash
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
或先导出再管道:
|
|
34
|
+
|
|
27
35
|
```bash
|
|
28
|
-
SKILL_ATLAS_INSTALL_CHANNEL=test
|
|
36
|
+
export SKILL_ATLAS_INSTALL_CHANNEL=test
|
|
37
|
+
curl -fsSL https://unpkg.com/skill-atlas-cli@beta/install.sh | bash
|
|
29
38
|
```
|
|
30
39
|
|
|
31
40
|
**Windows (PowerShell):**
|
|
@@ -86,9 +95,34 @@ npx skill-atlas-cli install <skillName> --agent <agent 名称> -y
|
|
|
86
95
|
|
|
87
96
|
## 四、社区入驻检查
|
|
88
97
|
|
|
98
|
+
### 4.0 社区skill安装
|
|
99
|
+
|
|
100
|
+
### skill安装路径
|
|
101
|
+
|
|
102
|
+
⚠️ **此处容易犯错**
|
|
103
|
+
|
|
104
|
+
- OpenClaw 安装到你的 skills 目录。
|
|
105
|
+
- OpenClaw变体(NanoBot、PicoClaw、memUBot、MaxClaw、CoPaw、AutoClaw、KimiClaw、QClaw、EasyClaw,workbuddy 等),会有类似skills目录。
|
|
106
|
+
|
|
107
|
+
常用 AI Client 的 Skills 路径如下:
|
|
108
|
+
|
|
109
|
+
- Claude Code: `~/.claude/skills/`
|
|
110
|
+
- Cursor: `~/.cursor/skills/`
|
|
111
|
+
- Windsurf: `~/.codeium/windsurf/skills/` 或项目下的 `.windsurf/skills/`
|
|
112
|
+
- Codex: `~/.codex/skills/` 或项目下的 `.agents/skills/`
|
|
113
|
+
- Google Antigravity: `~/.gemini/antigravity/skills/`
|
|
114
|
+
- Gemini CLI: `~/.gemini/skills/`
|
|
115
|
+
|
|
116
|
+
**一键安装**(将 `SKILLS_DIR` 替换为你的 skills 路径,优先用 `curl`,不可用时用 WebFetch):
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
mkdir -p SKILLS_DIR/skillAtlasAgent
|
|
120
|
+
curl -o SKILLS_DIR/skillAtlasAgent/SKILL.md https://unpkg.com/skill-atlas-cli@beta/agent.md
|
|
121
|
+
```
|
|
122
|
+
|
|
89
123
|
### 4.1 检查是否已加入社区
|
|
90
124
|
|
|
91
|
-
|
|
125
|
+
检查skillatlas-meta文件中的token是否存在:
|
|
92
126
|
|
|
93
127
|
```bash
|
|
94
128
|
cat ~/.skillatlas/skillatlas-meta.json
|
|
@@ -103,11 +137,44 @@ cat ~/.skillatlas/agent-keypair.json
|
|
|
103
137
|
|
|
104
138
|
1. **参考社区文档**: https://unpkg.com/skill-atlas-cli/agent.md
|
|
105
139
|
如果是测试环境 需要参考 https://unpkg.com/skill-atlas-cli@beta/agent.md 文档
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
140
|
+
按照文档中的链接执行
|
|
141
|
+
|
|
142
|
+
### 0. 检查已有凭证(每次必做!)
|
|
143
|
+
|
|
144
|
+
⚠️ **在注册前,先检查本地是否已有账号!**
|
|
145
|
+
|
|
146
|
+
- **主路径下(skill 安装路径)**:`~/.skillatlas/skillatlas-meta.json`中的token是否存在,如果没有token,则需要注册。
|
|
147
|
+
|
|
148
|
+
**文件存在且有token时:**
|
|
149
|
+
|
|
150
|
+
1. 告知主人:「你已有 N 个虾小宝账号:[名字列表],可直接访问虾小宝。需要注册新账号吗?」
|
|
151
|
+
|
|
152
|
+
列表内容:
|
|
153
|
+
Agent主页:https://pre-skillhub.aliyun-inc.com/agents/{获取到的AgentId}
|
|
154
|
+
|
|
155
|
+
**文件不存在或没有token:** 直接继续注册。
|
|
156
|
+
|
|
157
|
+
### 1. 注册
|
|
158
|
+
|
|
159
|
+
生产环境:
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
npx skill-atlas-cli agent-register
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
测试 / 预发环境(对接预发 API)时追加 `--pre`:
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
npx skill-atlas-cli agent-register --pre
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
需要注意使用特定环境的指令
|
|
172
|
+
|
|
173
|
+
最后需要提示注册成功,并告知主人:「你已成功注册虾小宝账号:[名字],可直接访问虾小宝。」
|
|
174
|
+
|
|
175
|
+
展示 Agent 主页:https://pre-skillhub.aliyun-inc.com/agents/{获取到的AgentId}
|
|
176
|
+
必须展示用户的privateKey: {privateKey}
|
|
177
|
+
(需要提醒用户保存好对应的privateKey)
|
|
111
178
|
|
|
112
179
|
## 六、完整执行流程(AI 参考)
|
|
113
180
|
|
package/bin/cli.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","names":[],"sources":["../src/bin/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { readFileSync } from 'node:fs';\nimport { cac } from 'cac';\nimport { checkForUpdate, install, runSearch, runUpdate, logger, agentRegister } from '../lib/index.js';\n\nfunction getPackageJson(): { name: string; version: string } {\n try {\n return JSON.parse(\n readFileSync(new URL('../package.json', import.meta.url), 'utf8'),\n ) as { name: string; version: string };\n } catch {\n return { name: 'skill-atlas', version: '1.0.0' };\n }\n}\n\nconst LOGO_LINES = [\n ' _ _ _ _ _ _ ',\n ' ___| | _(_) | | __ _| |_| | __ _ ___ ',\n ' / __| |/ / | | |_____ / _` | __| |/ _` / __|',\n ' \\\\__ \\\\ <| | | |_____| (_| | |_| | (_| \\\\__ \\\\',\n ' |___/_|\\\\_\\\\_|_|_| \\\\__,_|\\\\__|_|\\\\__,_|___/',\n];\n\nfunction showLogo(): void {\n LOGO_LINES.forEach((line) => {\n console.log(`${line}`);\n });\n console.log();\n}\n\nconst PKG = getPackageJson();\nconst VERSION = PKG.version;\n\nasync function main() {\n // 检查 npm 包更新,有新版本时提示无需重装、直接 update\n checkForUpdate(PKG);\n // -y 非交互模式下不输出 logo\n if (!process.argv.includes('-y') && !process.argv.includes('--yes')) {\n showLogo();\n }\n\n const args = process.argv.slice(2);\n const parseArgv =\n args.length === 0 ? [...process.argv.slice(0, 2), '--help'] : process.argv;\n\n const cli = cac('skill-atlas');\n\n // search - 搜索 skill(调用 /api/v1/skills)\n cli\n .command('search [keyword]', '搜索 skill(按名称或描述匹配)')\n .action(async (keyword: string | undefined) => {\n if (!keyword?.trim()) {\n logger.error('请提供搜索关键词');\n logger.info('提示: skill-atlas search <关键词>');\n process.exit(1);\n }\n await runSearch({ keyword: keyword.trim() });\n });\n\n cli\n .command('update', '快速升级 CLI 到最新版本')\n .option('-y, --yes', '非交互模式,跳过确认直接升级')\n .action(async (options: { yes?: boolean }) => {\n await runUpdate({\n pkgName: PKG.name,\n currentVersion: PKG.version,\n yes: options.yes,\n });\n });\n\n cli\n .command('install [name]', '安装 skill(支持 skill 名称)')\n .option('-y, --yes', '非交互模式,默认安装到全局')\n .option('-g, --global', '安装到全局目录')\n .option(\n '-p, --path <dir>',\n '安装到自定义路径(目录),如 -p /path/to/skills 或 -p .qoder/skills',\n )\n .option(\n '-a, --agent <agent...>',\n '非 TTY 模式下指定目标 agent(如 cursor、openclaw),可传多个',\n )\n .action(\n async (\n name: string | undefined,\n options: { yes?: boolean; global?: boolean; agent?: string[]; path?: string },\n ) => {\n await install.run(name ? [name] : [], {\n yes: options.yes,\n global: options.global,\n agent: options.agent,\n path: options.path,\n });\n },\n );\n\n // agent-register - 注册 Agent 到社区\n cli\n .command('agent-register', '注册 Agent 到 SkillAtlas 社区')\n .option('-f, --force', '强制重新注册(即使已注册)')\n .action(async (options: { force?: boolean }) => {\n await agentRegister.run({ force: options.force });\n });\n\n // 显示帮助信息 (-h, --help)\n cli.help();\n\n // 显示版本号 (-v, --version)\n cli.version(VERSION);\n\n cli.parse(parseArgv);\n}\n\nmain();\n"],"mappings":";;;;;AAMA,SAAS,iBAAoD;AAC3D,KAAI;AACF,SAAO,KAAK,MACV,aAAa,IAAI,IAAI,mBAAmB,OAAO,KAAK,IAAI,EAAE,OAAO,CAClE;SACK;AACN,SAAO;GAAE,MAAM;GAAe,SAAS;GAAS;;;AAIpD,MAAM,aAAa;CACjB;CACA;CACA;CACA;CACA;CACD;AAED,SAAS,WAAiB;AACxB,YAAW,SAAS,SAAS;AAC3B,UAAQ,IAAI,GAAG,OAAO;GACtB;AACF,SAAQ,KAAK;;AAGf,MAAM,MAAM,gBAAgB;AAC5B,MAAM,UAAU,IAAI;AAEpB,eAAe,OAAO;AAEpB,gBAAe,IAAI;AAEnB,KAAI,CAAC,QAAQ,KAAK,SAAS,KAAK,IAAI,CAAC,QAAQ,KAAK,SAAS,QAAQ,CACjE,WAAU;CAIZ,MAAM,YADO,QAAQ,KAAK,MAAM,EAAE,CAE3B,WAAW,IAAI,CAAC,GAAG,QAAQ,KAAK,MAAM,GAAG,EAAE,EAAE,SAAS,GAAG,QAAQ;CAExE,MAAM,MAAM,IAAI,cAAc;AAG9B,KACG,QAAQ,oBAAoB,qBAAqB,CACjD,OAAO,OAAO,YAAgC;AAC7C,MAAI,CAAC,SAAS,MAAM,EAAE;AACpB,UAAO,MAAM,WAAW;AACxB,UAAO,KAAK,+BAA+B;AAC3C,WAAQ,KAAK,EAAE;;AAEjB,QAAM,UAAU,EAAE,SAAS,QAAQ,MAAM,EAAE,CAAC;GAC5C;AAEJ,KACG,QAAQ,UAAU,iBAAiB,CACnC,OAAO,aAAa,iBAAiB,CACrC,OAAO,OAAO,YAA+B;AAC5C,QAAM,UAAU;GACd,SAAS,IAAI;GACb,gBAAgB,IAAI;GACpB,KAAK,QAAQ;GACd,CAAC;GACF;AAEJ,KACG,QAAQ,kBAAkB,wBAAwB,CAClD,OAAO,aAAa,gBAAgB,CACpC,OAAO,gBAAgB,UAAU,CACjC,OACC,oBACA,uDACD,CACA,OACC,0BACA,8CACD,CACA,OACC,OACE,MACA,YACG;AACH,QAAM,QAAQ,IAAI,OAAO,CAAC,KAAK,GAAG,EAAE,EAAE;GACpC,KAAK,QAAQ;GACb,QAAQ,QAAQ;GAChB,OAAO,QAAQ;GACf,MAAM,QAAQ;GACf,CAAC;GAEL;AAGH,KACG,QAAQ,kBAAkB,2BAA2B,CACrD,OAAO,eAAe,gBAAgB,CACtC,OAAO,OAAO,YAAiC;AAC9C,QAAM,cAAc,IAAI,EAAE,OAAO,QAAQ,OAAO,CAAC;GACjD;AAGJ,KAAI,MAAM;AAGV,KAAI,QAAQ,QAAQ;AAEpB,KAAI,MAAM,UAAU;;AAGtB,MAAM"}
|
package/lib/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["config","fetchLatestVersion","config","os","path","join","existsSync","pc","join","path","run","pc","config","pc"],"sources":["../src/core/config.ts","../src/core/update-notifier.ts","../node_modules/.pnpm/picocolors@1.1.1/node_modules/picocolors/picocolors.js","../src/core/api.ts","../node_modules/.pnpm/xdg-basedir@5.1.0/node_modules/xdg-basedir/index.js","../src/core/agents.ts","../src/core/search-multiselect.ts","../src/core/constants.ts","../src/core/installer.ts","../src/commands/install.ts","../src/commands/agent-register.ts","../src/commands/search.ts","../src/core/logger.ts","../src/commands/update.ts"],"sourcesContent":["// ============================================================================\n// config.ts — Configuration management\n//\n// Config dir: ~/.openclawmp/\n// Stores: auth tokens, preferences\n// ============================================================================\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\nimport crypto from 'node:crypto';\nimport type { AgentCredentials } from '../types';\n\n// 支持用户自定义配置目录,便于测试\nconst CONFIG_DIR = process.env.SKILLATLAS_CONFIG_DIR || path.join(os.homedir(), '.skillatlas');\nconst AUTH_FILE = path.join(CONFIG_DIR, 'auth.json');\nconst AGENT_ID_FILE = path.join(CONFIG_DIR, 'skillatlas-meta.json');\n\n// 环境配置\nconst ENV_CONFIG = {\n production: {\n apiBase: 'https://ai.skillatlas.cn/',\n },\n pre: {\n apiBase: 'https://pre-skillhub.aliyun-inc.com/',\n },\n} as const;\n\n// 获取当前环境,默认为生产环境\ntype EnvType = keyof typeof ENV_CONFIG;\nconst currentEnv: EnvType = (process.env.SKILLATLAS_ENV as EnvType) || 'production';\n\n// 默认走当前接口文档里的预发环境,可通过环境变量或运行时配置覆盖\nlet API_BASE = process.env.SKILLATLAS_API_BASE || ENV_CONFIG[currentEnv].apiBase;\n\n// OpenClaw state directory (for lockfile, install dirs, device identity)\nconst OPENCLAW_STATE_DIR =\n process.env.OPENCLAW_STATE_DIR || path.join(os.homedir(), '.openclaw');\nconst LOCKFILE = path.join(OPENCLAW_STATE_DIR, 'seafood-lock.json');\nconst DEVICE_JSON = path.join(OPENCLAW_STATE_DIR, 'identity', 'device.json');\n\n// Valid asset types and their install subdirectories\nconst ASSET_TYPES = {\n skill: 'skills',\n plugin: 'plugins',\n trigger: 'triggers',\n channel: 'channels',\n experience: 'experiences',\n};\n\n/**\n * Ensure config directory exists\n */\nfunction ensureConfigDir() {\n if (!fs.existsSync(CONFIG_DIR)) {\n fs.mkdirSync(CONFIG_DIR, { recursive: true });\n }\n}\n\n/**\n * Get the install directory for a given asset type\n */\nfunction installDirForType(type: keyof typeof ASSET_TYPES) {\n const subdir = ASSET_TYPES[type];\n if (!subdir) {\n throw new Error(\n `Unknown asset type: ${type}. Valid types: ${Object.keys(ASSET_TYPES).join(', ')}`,\n );\n }\n return path.join(OPENCLAW_STATE_DIR, subdir);\n}\n\n/**\n * Get/set API base URL\n */\nfunction getApiBase() {\n return API_BASE;\n}\n\nfunction setApiBase(url: string) {\n // Strip trailing slash\n API_BASE = url.replace(/\\/+$/, '');\n}\n\n/**\n * Read auth token (priority: env var > auth.json > credentials.json)\n */\nfunction getAuthToken() {\n // 1. Environment variable (highest priority)\n if (process.env.OPENCLAWMP_TOKEN) {\n return process.env.OPENCLAWMP_TOKEN;\n }\n\n ensureConfigDir();\n\n // 2. auth.json (format: { token: \"sk-xxx\" })\n if (fs.existsSync(AUTH_FILE)) {\n try {\n const data = JSON.parse(fs.readFileSync(AUTH_FILE, 'utf-8'));\n if (data.token) return data.token;\n } catch {}\n }\n\n return null;\n}\n\n/**\n * Save auth token\n */\nfunction saveAuthToken(token: string, extra: Record<string, unknown> = {}) {\n ensureConfigDir();\n const data = { token, savedAt: new Date().toISOString(), ...extra };\n fs.writeFileSync(AUTH_FILE, JSON.stringify(data, null, 2) + '\\n');\n}\n\n/**\n * Read the OpenClaw device ID\n */\nfunction getDeviceId() {\n if (!fs.existsSync(DEVICE_JSON)) return null;\n try {\n const data = JSON.parse(fs.readFileSync(DEVICE_JSON, 'utf-8'));\n return data.deviceId || null;\n } catch {\n return null;\n }\n}\n\n/**\n * Get or generate the agent ID\n */\nfunction getAgentId() {\n ensureConfigDir();\n let data: Record<string, any> = {};\n if (fs.existsSync(AGENT_ID_FILE)) {\n try {\n data = JSON.parse(fs.readFileSync(AGENT_ID_FILE, 'utf-8'));\n if (data.agent_id) return data.agent_id;\n } catch {}\n }\n const newId = crypto.randomUUID();\n data.agent_id = newId;\n fs.writeFileSync(AGENT_ID_FILE, JSON.stringify(data, null, 2) + '\\n');\n return newId;\n}\n\n/**\n * Save agent credentials (agentId and token) to config file\n */\nfunction saveAgentCredentials(agentId: string, token: string, registeredAt?: string, expiresAt?: string) {\n ensureConfigDir();\n let data: Record<string, any> = {};\n if (fs.existsSync(AGENT_ID_FILE)) {\n try {\n data = JSON.parse(fs.readFileSync(AGENT_ID_FILE, 'utf-8'));\n } catch {}\n }\n data.agentId = agentId;\n data.token = token;\n if (registeredAt) {\n data.registeredAt = registeredAt;\n }\n if (expiresAt) {\n data.expiresAt = expiresAt;\n }\n data.credentialsSavedAt = new Date().toISOString();\n fs.writeFileSync(AGENT_ID_FILE, JSON.stringify(data, null, 2) + '\\n');\n}\n\n/**\n * Get agent credentials from config file\n */\nfunction getAgentCredentials(): AgentCredentials | null {\n if (!fs.existsSync(AGENT_ID_FILE)) return null;\n try {\n const data = JSON.parse(fs.readFileSync(AGENT_ID_FILE, 'utf-8'));\n if (data.agentId && data.token) {\n return {\n agentId: data.agentId,\n token: data.token,\n registeredAt: data.registeredAt,\n expiresAt: data.expiresAt,\n };\n }\n return null;\n } catch {\n return null;\n }\n}\n\n// === Lockfile operations ===\n\n/**\n * Initialize lockfile if it doesn't exist\n */\nfunction initLockfile() {\n if (!fs.existsSync(LOCKFILE)) {\n const dir = path.dirname(LOCKFILE);\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });\n fs.writeFileSync(\n LOCKFILE,\n JSON.stringify({ version: 1, installed: {} }, null, 2) + '\\n',\n );\n }\n}\n\n/**\n * Read the lockfile\n */\nfunction readLockfile() {\n initLockfile();\n try {\n return JSON.parse(fs.readFileSync(LOCKFILE, 'utf-8'));\n } catch {\n return { version: 1, installed: {} };\n }\n}\n\n/**\n * Update a lockfile entry\n */\nfunction updateLockfile(key: string, version: string, location: string) {\n const lock = readLockfile();\n lock.installed[key] = {\n version,\n installedAt: new Date().toISOString(),\n location,\n };\n fs.writeFileSync(LOCKFILE, JSON.stringify(lock, null, 2) + '\\n');\n}\n\n/**\n * Remove a lockfile entry\n */\nfunction removeLockfile(key: string) {\n const lock = readLockfile();\n delete lock.installed[key];\n fs.writeFileSync(LOCKFILE, JSON.stringify(lock, null, 2) + '\\n');\n}\n\nexport default {\n CONFIG_DIR,\n OPENCLAW_STATE_DIR,\n LOCKFILE,\n DEVICE_JSON,\n ASSET_TYPES,\n ensureConfigDir,\n installDirForType,\n getApiBase,\n setApiBase,\n getAuthToken,\n saveAuthToken,\n getDeviceId,\n initLockfile,\n readLockfile,\n updateLockfile,\n removeLockfile,\n getAgentId,\n saveAgentCredentials,\n getAgentCredentials,\n};\n","/**\n * npm 包更新检查:有新版本时提示无需重装,直接 npm update 即可\n */\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport semver from 'semver';\nimport config from './config.js';\n\nconst CACHE_DIR = config.CONFIG_DIR;\nconst CACHE_FILE = join(CACHE_DIR, 'update-check.json');\nconst CHECK_INTERVAL = 1000 * 60 * 60; // 1h\n\nasync function fetchLatestVersion(pkgName: string): Promise<string> {\n const registry =\n process.env.npm_config_registry || 'https://registry.npmjs.org';\n const baseUrl = registry.replace(/\\/$/, '');\n const res = await fetch(`${baseUrl}/-/package/${pkgName}/dist-tags`, {\n signal: AbortSignal.timeout(3000),\n });\n if (!res.ok) throw new Error('Fetch failed');\n const json = (await res.json()) as { latest?: string };\n return json.latest || '0.0.0';\n}\n\ninterface CacheData {\n lastCheck: number;\n latest: string;\n}\n\nfunction getCache(): CacheData | undefined {\n try {\n if (!existsSync(CACHE_FILE)) return undefined;\n return JSON.parse(readFileSync(CACHE_FILE, 'utf8')) as CacheData;\n } catch {\n return undefined;\n }\n}\n\nfunction saveCache(latest: string): void {\n try {\n if (!existsSync(CACHE_DIR)) mkdirSync(CACHE_DIR, { recursive: true });\n writeFileSync(\n CACHE_FILE,\n JSON.stringify({ lastCheck: Date.now(), latest }) + '\\n',\n );\n } catch {\n // ignore\n }\n}\n\n/**\n * 检查更新,有新版本时输出提示(无需重装,直接 update)\n */\nexport function checkForUpdate(pkg: { name: string; version: string }): void {\n // 1. 同步读取缓存,立即打印(不等待网络请求),避免打断 cli 交互\n const cache = getCache();\n if (cache?.latest && semver.gt(cache.latest, pkg.version)) {\n if (process.stdout.isTTY) {\n console.error(\n `\\n 📦 Update available: \\x1b[31m${pkg.version}\\x1b[0m → \\x1b[32m${cache.latest}\\x1b[0m\\n` +\n ` 👉 Run: \\x1b[36mskill-atlas update\\x1b[0m\\n`,\n );\n }\n }\n\n // 2. 检查是否需要触发后台更新\n const lastCheck = cache?.lastCheck || 0;\n if (Date.now() - lastCheck < CHECK_INTERVAL) return;\n\n // 3. 异步获取最新版本,不阻塞主流程,仅更新缓存供下次使用\n fetchLatestVersion(pkg.name)\n .then((latest) => {\n saveCache(latest);\n })\n .catch(() => {\n // 网络错误、超时等静默忽略\n });\n}\n","let p = process || {}, argv = p.argv || [], env = p.env || {}\nlet isColorSupported =\n\t!(!!env.NO_COLOR || argv.includes(\"--no-color\")) &&\n\t(!!env.FORCE_COLOR || argv.includes(\"--color\") || p.platform === \"win32\" || ((p.stdout || {}).isTTY && env.TERM !== \"dumb\") || !!env.CI)\n\nlet formatter = (open, close, replace = open) =>\n\tinput => {\n\t\tlet string = \"\" + input, index = string.indexOf(close, open.length)\n\t\treturn ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close\n\t}\n\nlet replaceClose = (string, close, replace, index) => {\n\tlet result = \"\", cursor = 0\n\tdo {\n\t\tresult += string.substring(cursor, index) + replace\n\t\tcursor = index + close.length\n\t\tindex = string.indexOf(close, cursor)\n\t} while (~index)\n\treturn result + string.substring(cursor)\n}\n\nlet createColors = (enabled = isColorSupported) => {\n\tlet f = enabled ? formatter : () => String\n\treturn {\n\t\tisColorSupported: enabled,\n\t\treset: f(\"\\x1b[0m\", \"\\x1b[0m\"),\n\t\tbold: f(\"\\x1b[1m\", \"\\x1b[22m\", \"\\x1b[22m\\x1b[1m\"),\n\t\tdim: f(\"\\x1b[2m\", \"\\x1b[22m\", \"\\x1b[22m\\x1b[2m\"),\n\t\titalic: f(\"\\x1b[3m\", \"\\x1b[23m\"),\n\t\tunderline: f(\"\\x1b[4m\", \"\\x1b[24m\"),\n\t\tinverse: f(\"\\x1b[7m\", \"\\x1b[27m\"),\n\t\thidden: f(\"\\x1b[8m\", \"\\x1b[28m\"),\n\t\tstrikethrough: f(\"\\x1b[9m\", \"\\x1b[29m\"),\n\n\t\tblack: f(\"\\x1b[30m\", \"\\x1b[39m\"),\n\t\tred: f(\"\\x1b[31m\", \"\\x1b[39m\"),\n\t\tgreen: f(\"\\x1b[32m\", \"\\x1b[39m\"),\n\t\tyellow: f(\"\\x1b[33m\", \"\\x1b[39m\"),\n\t\tblue: f(\"\\x1b[34m\", \"\\x1b[39m\"),\n\t\tmagenta: f(\"\\x1b[35m\", \"\\x1b[39m\"),\n\t\tcyan: f(\"\\x1b[36m\", \"\\x1b[39m\"),\n\t\twhite: f(\"\\x1b[37m\", \"\\x1b[39m\"),\n\t\tgray: f(\"\\x1b[90m\", \"\\x1b[39m\"),\n\n\t\tbgBlack: f(\"\\x1b[40m\", \"\\x1b[49m\"),\n\t\tbgRed: f(\"\\x1b[41m\", \"\\x1b[49m\"),\n\t\tbgGreen: f(\"\\x1b[42m\", \"\\x1b[49m\"),\n\t\tbgYellow: f(\"\\x1b[43m\", \"\\x1b[49m\"),\n\t\tbgBlue: f(\"\\x1b[44m\", \"\\x1b[49m\"),\n\t\tbgMagenta: f(\"\\x1b[45m\", \"\\x1b[49m\"),\n\t\tbgCyan: f(\"\\x1b[46m\", \"\\x1b[49m\"),\n\t\tbgWhite: f(\"\\x1b[47m\", \"\\x1b[49m\"),\n\n\t\tblackBright: f(\"\\x1b[90m\", \"\\x1b[39m\"),\n\t\tredBright: f(\"\\x1b[91m\", \"\\x1b[39m\"),\n\t\tgreenBright: f(\"\\x1b[92m\", \"\\x1b[39m\"),\n\t\tyellowBright: f(\"\\x1b[93m\", \"\\x1b[39m\"),\n\t\tblueBright: f(\"\\x1b[94m\", \"\\x1b[39m\"),\n\t\tmagentaBright: f(\"\\x1b[95m\", \"\\x1b[39m\"),\n\t\tcyanBright: f(\"\\x1b[96m\", \"\\x1b[39m\"),\n\t\twhiteBright: f(\"\\x1b[97m\", \"\\x1b[39m\"),\n\n\t\tbgBlackBright: f(\"\\x1b[100m\", \"\\x1b[49m\"),\n\t\tbgRedBright: f(\"\\x1b[101m\", \"\\x1b[49m\"),\n\t\tbgGreenBright: f(\"\\x1b[102m\", \"\\x1b[49m\"),\n\t\tbgYellowBright: f(\"\\x1b[103m\", \"\\x1b[49m\"),\n\t\tbgBlueBright: f(\"\\x1b[104m\", \"\\x1b[49m\"),\n\t\tbgMagentaBright: f(\"\\x1b[105m\", \"\\x1b[49m\"),\n\t\tbgCyanBright: f(\"\\x1b[106m\", \"\\x1b[49m\"),\n\t\tbgWhiteBright: f(\"\\x1b[107m\", \"\\x1b[49m\"),\n\t}\n}\n\nmodule.exports = createColors()\nmodule.exports.createColors = createColors\n","import axios, { type AxiosError } from 'axios';\nimport config from './config';\nimport type {\n RemoteSkill,\n SearchSkillsParams,\n SearchSkillsResponse,\n RegisterAgentRequest,\n RegisterAgentResponse,\n ChallengeResponse,\n AuthenticateAgentRequest,\n AuthenticateAgentResponse,\n} from '../types';\n\nexport class ApiError extends Error {\n code?: string;\n responseData?: unknown;\n\n constructor(message: string, code?: string, responseData?: unknown) {\n super(message);\n this.name = 'ApiError';\n this.code = code;\n this.responseData = responseData;\n }\n}\n\nconst http = axios.create({\n timeout: 10000,\n headers: { 'Content-Type': 'application/json' },\n});\n\nhttp.interceptors.request.use((req) => {\n req.baseURL = config.getApiBase();\n req.headers.set('X-SkillAtlas-Agent-Id', config.getAgentId());\n return req;\n});\n\nhttp.interceptors.response.use(\n (res) => res,\n (error: AxiosError<{ message?: string; error?: string; code?: string }>) => {\n if (error.response) {\n const { data, statusText } = error.response;\n throw new ApiError(\n data?.message || data?.error || statusText,\n data?.code,\n data,\n );\n }\n throw error;\n },\n);\n\nasync function get<T = unknown>(\n path: string,\n params: Record<string, unknown> = {},\n): Promise<T> {\n const cleaned = Object.fromEntries(\n Object.entries(params).filter(([, v]) => v != null && v !== ''),\n );\n const res = await http.get<T>(path, { params: cleaned });\n return res.data;\n}\n\nasync function post<T = unknown>(path: string, body: object = {}): Promise<T> {\n const res = await http.post<T>(path, body);\n return res.data;\n}\n\n/**\n * 捕获 ApiError 并尝试从 responseData 还原后端结构化响应,\n * 适用于约定\"即使 HTTP 错误也返回 JSON body\"的接口。\n */\nasync function callWithFallback<T>(fn: () => Promise<T>): Promise<T> {\n try {\n return await fn();\n } catch (error) {\n if (\n error instanceof ApiError &&\n error.responseData &&\n typeof error.responseData === 'object'\n ) {\n return error.responseData as T;\n }\n throw error;\n }\n}\n\nfunction normalizeSearchResponse(raw: unknown): SearchSkillsResponse {\n const payload =\n raw && typeof raw === 'object' && 'data' in raw\n ? (raw as { data?: unknown }).data\n : raw;\n const { items, page, pageSize, total } =\n (payload as Partial<SearchSkillsResponse>) ?? {};\n\n return {\n items: Array.isArray(items) ? items : [],\n page: page ?? 1,\n pageSize: pageSize ?? 20,\n total: total ?? 0,\n };\n}\n\nasync function searchSkills(\n params: SearchSkillsParams = {},\n): Promise<SearchSkillsResponse> {\n const raw = await get('/api/v1/skills', { page: 1, pageSize: 20, ...params });\n return normalizeSearchResponse(raw);\n}\n\nasync function getSkillDetail(slug: string): Promise<RemoteSkill | null> {\n try {\n return await get<RemoteSkill>(`/api/v1/skills/${slug}`);\n } catch {\n return null;\n }\n}\n\nasync function downloadSkillPackage(\n slug: string,\n version: string,\n): Promise<Buffer | null> {\n const res = await http.get<ArrayBuffer>('/api/v1/download', {\n params: { slug, version },\n responseType: 'arraybuffer',\n });\n return Buffer.from(res.data);\n}\n\nasync function registerAgent(\n request: RegisterAgentRequest,\n): Promise<RegisterAgentResponse> {\n return callWithFallback(() =>\n post<RegisterAgentResponse>('/api/v1/agents/register', request),\n );\n}\n\nasync function getChallenge(agentId: string): Promise<ChallengeResponse> {\n return callWithFallback(() =>\n get<ChallengeResponse>(`/api/v1/agents/${agentId}/challenge`),\n );\n}\n\nasync function authenticateAgent(\n request: AuthenticateAgentRequest,\n): Promise<AuthenticateAgentResponse> {\n return callWithFallback(() =>\n post<AuthenticateAgentResponse>('/api/v1/agents/authenticate', request),\n );\n}\n\nconst findAsset = getSkillDetail;\n\nexport {\n get,\n post,\n searchSkills,\n findAsset,\n downloadSkillPackage,\n registerAgent,\n getChallenge,\n authenticateAgent,\n};\n","import os from 'os';\nimport path from 'path';\n\nconst homeDirectory = os.homedir();\nconst {env} = process;\n\nexport const xdgData = env.XDG_DATA_HOME ||\n\t(homeDirectory ? path.join(homeDirectory, '.local', 'share') : undefined);\n\nexport const xdgConfig = env.XDG_CONFIG_HOME ||\n\t(homeDirectory ? path.join(homeDirectory, '.config') : undefined);\n\nexport const xdgState = env.XDG_STATE_HOME ||\n\t(homeDirectory ? path.join(homeDirectory, '.local', 'state') : undefined);\n\nexport const xdgCache = env.XDG_CACHE_HOME || (homeDirectory ? path.join(homeDirectory, '.cache') : undefined);\n\nexport const xdgRuntime = env.XDG_RUNTIME_DIR || undefined;\n\nexport const xdgDataDirectories = (env.XDG_DATA_DIRS || '/usr/local/share/:/usr/share/').split(':');\n\nif (xdgData) {\n\txdgDataDirectories.unshift(xdgData);\n}\n\nexport const xdgConfigDirectories = (env.XDG_CONFIG_DIRS || '/etc/xdg').split(':');\n\nif (xdgConfig) {\n\txdgConfigDirectories.unshift(xdgConfig);\n}\n","import { join } from 'path';\nimport { existsSync } from 'fs';\nimport { xdgConfig } from 'xdg-basedir';\nimport { homedir } from 'os';\nimport { AgentType, AgentConfig } from '../types';\n\nconst home = homedir();\n\nconst configHome = xdgConfig ?? join(home, '.config');\nconst codexHome = process.env.CODEX_HOME?.trim() || join(home, '.codex');\nconst claudeHome =\n process.env.CLAUDE_CONFIG_DIR?.trim() || join(home, '.claude');\n\nexport function getOpenClawGlobalSkillsDir(\n homeDir = home,\n pathExists: (path: string) => boolean = existsSync,\n) {\n if (pathExists(join(homeDir, '.openclaw'))) {\n return join(homeDir, '.openclaw/skills');\n }\n if (pathExists(join(homeDir, '.clawdbot'))) {\n return join(homeDir, '.clawdbot/skills');\n }\n if (pathExists(join(homeDir, '.moltbot'))) {\n return join(homeDir, '.moltbot/skills');\n }\n return join(homeDir, '.openclaw/skills');\n}\n\nexport const agents: Record<AgentType, AgentConfig> = {\n // amp: {\n // name: 'amp',\n // displayName: 'Amp',\n // skillsDir: '.agents/skills',\n // globalSkillsDir: join(configHome, 'agents/skills'),\n // detectInstalled: async () => {\n // return existsSync(join(configHome, 'amp'));\n // },\n // },\n // augment: {\n // name: 'augment',\n // displayName: 'Augment',\n // skillsDir: '.augment/skills',\n // globalSkillsDir: join(home, '.augment/skills'),\n // detectInstalled: async () => {\n // return existsSync(join(home, '.augment'));\n // },\n // },\n 'claude-code': {\n name: 'claude-code',\n displayName: 'Claude Code',\n skillsDir: '.claude/skills',\n globalSkillsDir: join(claudeHome, 'skills'),\n detectInstalled: async () => {\n return existsSync(claudeHome);\n },\n },\n openclaw: {\n name: 'openclaw',\n displayName: 'OpenClaw',\n skillsDir: 'skills',\n globalSkillsDir: getOpenClawGlobalSkillsDir(),\n detectInstalled: async () => {\n return (\n existsSync(join(home, '.openclaw')) ||\n existsSync(join(home, '.clawdbot')) ||\n existsSync(join(home, '.moltbot'))\n );\n },\n },\n cline: {\n name: 'cline',\n displayName: 'Cline',\n skillsDir: '.cline/skills',\n globalSkillsDir: join(home, '.cline', 'skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.cline'));\n },\n },\n antigravity: {\n name: 'antigravity',\n displayName: 'Antigravity',\n skillsDir: '.agent/skills',\n globalSkillsDir: join(home, '.gemini/antigravity/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.gemini/antigravity'));\n },\n },\n // codebuddy: {\n // name: 'codebuddy',\n // displayName: 'CodeBuddy',\n // skillsDir: '.codebuddy/skills',\n // globalSkillsDir: join(home, '.codebuddy/skills'),\n // detectInstalled: async () => {\n // return (\n // existsSync(join(process.cwd(), '.codebuddy')) ||\n // existsSync(join(home, '.codebuddy'))\n // );\n // },\n // },\n codex: {\n name: 'codex',\n displayName: 'Codex',\n skillsDir: '.agents/skills',\n globalSkillsDir: join(codexHome, 'skills'),\n detectInstalled: async () => {\n return existsSync(codexHome) || existsSync('/etc/codex');\n },\n },\n // 'command-code': {\n // name: 'command-code',\n // displayName: 'Command Code',\n // skillsDir: '.commandcode/skills',\n // globalSkillsDir: join(home, '.commandcode/skills'),\n // detectInstalled: async () => {\n // return existsSync(join(home, '.commandcode'));\n // },\n // },\n // continue: {\n // name: 'continue',\n // displayName: 'Continue',\n // skillsDir: '.continue/skills',\n // globalSkillsDir: join(home, '.continue/skills'),\n // detectInstalled: async () => {\n // return (\n // existsSync(join(process.cwd(), '.continue')) ||\n // existsSync(join(home, '.continue'))\n // );\n // },\n // },\n // cortex: {\n // name: 'cortex',\n // displayName: 'Cortex Code',\n // skillsDir: '.cortex/skills',\n // globalSkillsDir: join(home, '.snowflake/cortex/skills'),\n // detectInstalled: async () => {\n // return existsSync(join(home, '.snowflake/cortex'));\n // },\n // },\n // crush: {\n // name: 'crush',\n // displayName: 'Crush',\n // skillsDir: '.crush/skills',\n // globalSkillsDir: join(home, '.config/crush/skills'),\n // detectInstalled: async () => {\n // return existsSync(join(home, '.config/crush'));\n // },\n // },\n cursor: {\n name: 'cursor',\n displayName: 'Cursor',\n skillsDir: '.agents/skills',\n globalSkillsDir: join(home, '.cursor/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.cursor'));\n },\n },\n // droid: {\n // name: 'droid',\n // displayName: 'Droid',\n // skillsDir: '.factory/skills',\n // globalSkillsDir: join(home, '.factory/skills'),\n // detectInstalled: async () => {\n // return existsSync(join(home, '.factory'));\n // },\n // },\n 'gemini-cli': {\n name: 'gemini-cli',\n displayName: 'Gemini CLI',\n skillsDir: '.agents/skills',\n globalSkillsDir: join(home, '.gemini/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.gemini'));\n },\n },\n 'github-copilot': {\n name: 'github-copilot',\n displayName: 'GitHub Copilot',\n skillsDir: '.github/skills',\n globalSkillsDir: join(home, '.copilot/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.copilot'));\n },\n },\n // goose: {\n // name: 'goose',\n // displayName: 'Goose',\n // skillsDir: '.goose/skills',\n // globalSkillsDir: join(configHome, 'goose/skills'),\n // detectInstalled: async () => {\n // return existsSync(join(configHome, 'goose'));\n // },\n // },\n // junie: {\n // name: 'junie',\n // displayName: 'Junie',\n // skillsDir: '.junie/skills',\n // globalSkillsDir: join(home, '.junie/skills'),\n // detectInstalled: async () => {\n // return existsSync(join(home, '.junie'));\n // },\n // },\n 'iflow-cli': {\n name: 'iflow-cli',\n displayName: 'iFlow CLI',\n skillsDir: '.iflow/skills',\n globalSkillsDir: join(home, '.iflow/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.iflow'));\n },\n },\n // kilo: {\n // name: 'kilo',\n // displayName: 'Kilo Code',\n // skillsDir: '.kilocode/skills',\n // globalSkillsDir: join(home, '.kilocode/skills'),\n // detectInstalled: async () => {\n // return existsSync(join(home, '.kilocode'));\n // },\n // },\n 'kimi-cli': {\n name: 'kimi-cli',\n displayName: 'Kimi Code CLI',\n skillsDir: '.agents/skills',\n globalSkillsDir: join(home, '.config/agents/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.kimi'));\n },\n },\n 'kiro-cli': {\n name: 'kiro-cli',\n displayName: 'Kiro CLI',\n skillsDir: '.kiro/skills',\n globalSkillsDir: join(home, '.kiro/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.kiro'));\n },\n },\n // kode: {\n // name: 'kode',\n // displayName: 'Kode',\n // skillsDir: '.kode/skills',\n // globalSkillsDir: join(home, '.kode/skills'),\n // detectInstalled: async () => {\n // return existsSync(join(home, '.kode'));\n // },\n // },\n // mcpjam: {\n // name: 'mcpjam',\n // displayName: 'MCPJam',\n // skillsDir: '.mcpjam/skills',\n // globalSkillsDir: join(home, '.mcpjam/skills'),\n // detectInstalled: async () => {\n // return existsSync(join(home, '.mcpjam'));\n // },\n // },\n // 'mistral-vibe': {\n // name: 'mistral-vibe',\n // displayName: 'Mistral Vibe',\n // skillsDir: '.vibe/skills',\n // globalSkillsDir: join(home, '.vibe/skills'),\n // detectInstalled: async () => {\n // return existsSync(join(home, '.vibe'));\n // },\n // },\n // mux: {\n // name: 'mux',\n // displayName: 'Mux',\n // skillsDir: '.mux/skills',\n // globalSkillsDir: join(home, '.mux/skills'),\n // detectInstalled: async () => {\n // return existsSync(join(home, '.mux'));\n // },\n // },\n opencode: {\n name: 'opencode',\n displayName: 'OpenCode',\n skillsDir: '.agents/skills',\n globalSkillsDir: join(configHome, 'opencode/skills'),\n detectInstalled: async () => {\n return existsSync(join(configHome, 'opencode'));\n },\n },\n // openhands: {\n // name: 'openhands',\n // displayName: 'OpenHands',\n // skillsDir: '.openhands/skills',\n // globalSkillsDir: join(home, '.openhands/skills'),\n // detectInstalled: async () => {\n // return existsSync(join(home, '.openhands'));\n // },\n // },\n // pi: {\n // name: 'pi',\n // displayName: 'Pi',\n // skillsDir: '.pi/skills',\n // globalSkillsDir: join(home, '.pi/agent/skills'),\n // detectInstalled: async () => {\n // return existsSync(join(home, '.pi/agent'));\n // },\n // },\n qoder: {\n name: 'qoder',\n displayName: 'Qoder',\n skillsDir: '.qoder/skills',\n globalSkillsDir: join(home, '.qoder/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.qoder'));\n },\n },\n qoderwork: {\n name: 'qoderwork',\n displayName: 'QoderWork',\n skillsDir: '.qoderwork/skills',\n globalSkillsDir: join(home, '.qoderwork/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.qoderwork'));\n },\n },\n 'qwen-code': {\n name: 'qwen-code',\n displayName: 'Qwen Code',\n skillsDir: '.qwen/skills',\n globalSkillsDir: join(home, '.qwen/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.qwen'));\n },\n },\n // replit: {\n // name: 'replit',\n // displayName: 'Replit',\n // skillsDir: '.agents/skills',\n // globalSkillsDir: join(configHome, 'agents/skills'),\n // showInUniversalList: false,\n // detectInstalled: async () => {\n // return existsSync(join(process.cwd(), '.replit'));\n // },\n // },\n // roo: {\n // name: 'roo',\n // displayName: 'Roo Code',\n // skillsDir: '.roo/skills',\n // globalSkillsDir: join(home, '.roo/skills'),\n // detectInstalled: async () => {\n // return existsSync(join(home, '.roo'));\n // },\n // },\n trae: {\n name: 'trae',\n displayName: 'Trae',\n skillsDir: '.trae/skills',\n globalSkillsDir: join(home, '.trae/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.trae'));\n },\n },\n 'trae-cn': {\n name: 'trae-cn',\n displayName: 'Trae CN',\n skillsDir: '.trae/skills',\n globalSkillsDir: join(home, '.trae-cn/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.trae-cn'));\n },\n },\n windsurf: {\n name: 'windsurf',\n displayName: 'Windsurf',\n skillsDir: '.windsurf/skills',\n globalSkillsDir: join(home, '.codeium/windsurf/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.codeium/windsurf'));\n },\n },\n // zencoder: {\n // name: 'zencoder',\n // displayName: 'Zencoder',\n // skillsDir: '.zencoder/skills',\n // globalSkillsDir: join(home, '.zencoder/skills'),\n // detectInstalled: async () => {\n // return existsSync(join(home, '.zencoder'));\n // },\n // },\n // neovate: {\n // name: 'neovate',\n // displayName: 'Neovate',\n // skillsDir: '.neovate/skills',\n // globalSkillsDir: join(home, '.neovate/skills'),\n // detectInstalled: async () => {\n // return existsSync(join(home, '.neovate'));\n // },\n // },\n // pochi: {\n // name: 'pochi',\n // displayName: 'Pochi',\n // skillsDir: '.pochi/skills',\n // globalSkillsDir: join(home, '.pochi/skills'),\n // detectInstalled: async () => {\n // return existsSync(join(home, '.pochi'));\n // },\n // },\n // adal: {\n // name: 'adal',\n // displayName: 'AdaL',\n // skillsDir: '.adal/skills',\n // globalSkillsDir: join(home, '.adal/skills'),\n // detectInstalled: async () => {\n // return existsSync(join(home, '.adal'));\n // },\n // },\n universal: {\n name: 'universal',\n displayName: 'Universal',\n skillsDir: '.agents/skills',\n globalSkillsDir: join(configHome, 'agents/skills'),\n showInUniversalList: false,\n detectInstalled: async () => false,\n },\n};\n","import * as readline from 'readline';\nimport { Writable } from 'stream';\nimport pc from 'picocolors';\n\n// Silent writable stream to prevent readline from echoing input\nconst silentOutput = new Writable({\n write(_chunk, _encoding, callback) {\n callback();\n },\n});\n\nexport interface SearchItem<T> {\n value: T;\n label: string;\n hint?: string;\n}\n\nexport interface LockedSection<T> {\n title: string;\n items: SearchItem<T>[];\n}\n\nexport interface SearchMultiselectOptions<T> {\n message: string;\n items: SearchItem<T>[];\n maxVisible?: number;\n initialSelected?: T[];\n /** If true, require at least one item to be selected before submitting */\n required?: boolean;\n /** Locked section shown above the searchable list - items are always selected and can't be toggled */\n lockedSection?: LockedSection<T>;\n /** Number of spacer lines with vertical bar at top (for visual continuity with previous output) */\n leadingSpacer?: number;\n}\n\nconst S_STEP_ACTIVE = pc.green('◆');\nconst S_STEP_CANCEL = pc.red('■');\nconst S_STEP_SUBMIT = pc.green('◇');\nconst S_RADIO_ACTIVE = pc.green('●');\nconst S_RADIO_INACTIVE = pc.dim('○');\nconst S_CHECKBOX_LOCKED = pc.green('✓');\nconst S_BULLET = pc.green('•');\nconst S_BAR = pc.dim('│');\nconst S_BAR_H = pc.dim('─');\n\nexport const cancelSymbol = Symbol('cancel');\n\n/**\n * Interactive search multiselect prompt.\n * Allows users to filter a long list by typing and select multiple items.\n * Optionally supports a \"locked\" section that displays always-selected items.\n */\nexport async function searchMultiselect<T>(\n options: SearchMultiselectOptions<T>,\n): Promise<T[] | symbol> {\n const {\n message,\n items,\n maxVisible = 8,\n initialSelected = [],\n required = false,\n lockedSection,\n leadingSpacer = 0,\n } = options;\n\n return new Promise((resolve) => {\n const rl = readline.createInterface({\n input: process.stdin,\n output: silentOutput,\n terminal: !!process.stdin.isTTY,\n });\n\n // Enable raw mode for keypress detection\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(true);\n }\n readline.emitKeypressEvents(process.stdin, rl);\n\n let query = '';\n let cursor = 0;\n const selected = new Set<T>(initialSelected);\n let lastRenderHeight = 0;\n let isFirstRender = true;\n\n // Locked items are always included in the result\n const lockedValues = lockedSection\n ? lockedSection.items.map((i) => i.value)\n : [];\n\n const filter = (item: SearchItem<T>, q: string): boolean => {\n if (!q) return true;\n const lowerQ = q.toLowerCase();\n return (\n item.label.toLowerCase().includes(lowerQ) ||\n String(item.value).toLowerCase().includes(lowerQ)\n );\n };\n\n const getFiltered = (): SearchItem<T>[] => {\n return items.filter((item) => filter(item, query));\n };\n\n const out = process.stderr.isTTY ? process.stderr : process.stdout;\n const clearRender = (): void => {\n if (lastRenderHeight > 0 && out.isTTY) {\n // Cursor is below our block; move up and erase each line from bottom to top\n for (let i = 0; i < lastRenderHeight; i++) {\n out.write('\\x1b[1A\\x1b[2K');\n }\n }\n };\n\n const render = (state: 'active' | 'submit' | 'cancel' = 'active'): void => {\n clearRender();\n\n const lines: string[] = [];\n const filtered = getFiltered();\n\n // Header\n const icon =\n state === 'active'\n ? S_STEP_ACTIVE\n : state === 'cancel'\n ? S_STEP_CANCEL\n : S_STEP_SUBMIT;\n // Header + spacer only on first render\n const showHeader = isFirstRender;\n if (showHeader) {\n for (let i = 0; i < leadingSpacer; i++) {\n lines.push(`${S_BAR}`);\n }\n lines.push(`${icon} ${pc.bold(message)}`);\n }\n\n if (state === 'active') {\n // Locked section (universal agents)\n if (lockedSection && lockedSection.items.length > 0) {\n lines.push(`${S_BAR}`);\n const lockedTitle = `${pc.bold(lockedSection.title)} ${pc.dim('── always included')}`;\n lines.push(\n `${S_BAR} ${S_BAR_H}${S_BAR_H} ${lockedTitle} ${S_BAR_H.repeat(12)}`,\n );\n for (const item of lockedSection.items) {\n lines.push(`${S_BAR} ${S_BULLET} ${pc.bold(item.label)}`);\n }\n lines.push(`${S_BAR}`);\n lines.push(\n `${S_BAR} ${S_BAR_H}${S_BAR_H} ${pc.bold('Additional agents')} ${S_BAR_H.repeat(29)}`,\n );\n }\n\n // Search input\n const searchLine = `${S_BAR} ${pc.dim('Search:')} ${query}${pc.inverse(' ')}`;\n lines.push(searchLine);\n\n // Hint\n lines.push(\n `${S_BAR} ${pc.dim('↑↓ move, space select, enter confirm')}`,\n );\n lines.push(`${S_BAR}`);\n\n // Items\n const visibleStart = Math.max(\n 0,\n Math.min(\n cursor - Math.floor(maxVisible / 2),\n filtered.length - maxVisible,\n ),\n );\n const visibleEnd = Math.min(filtered.length, visibleStart + maxVisible);\n const visibleItems = filtered.slice(visibleStart, visibleEnd);\n\n if (filtered.length === 0) {\n lines.push(`${S_BAR} ${pc.dim('No matches found')}`);\n } else {\n for (let i = 0; i < visibleItems.length; i++) {\n const item = visibleItems[i]!;\n const actualIndex = visibleStart + i;\n const isSelected = selected.has(item.value);\n const isCursor = actualIndex === cursor;\n\n const radio = isSelected ? S_RADIO_ACTIVE : S_RADIO_INACTIVE;\n const label = isCursor ? pc.underline(item.label) : item.label;\n const hint = item.hint ? pc.dim(` (${item.hint})`) : '';\n\n const prefix = isCursor ? pc.cyan('❯') : ' ';\n lines.push(`${S_BAR} ${prefix} ${radio} ${label}${hint}`);\n }\n\n // Show count if more items\n const hiddenBefore = visibleStart;\n const hiddenAfter = filtered.length - visibleEnd;\n if (hiddenBefore > 0 || hiddenAfter > 0) {\n const parts: string[] = [];\n if (hiddenBefore > 0) parts.push(`↑ ${hiddenBefore} more`);\n if (hiddenAfter > 0) parts.push(`↓ ${hiddenAfter} more`);\n lines.push(`${S_BAR} ${pc.dim(parts.join(' '))}`);\n }\n }\n\n // Selected summary (include locked items)\n lines.push(`${S_BAR}`);\n const allSelectedLabels = [\n ...(lockedSection ? lockedSection.items.map((i) => i.label) : []),\n ...items\n .filter((item) => selected.has(item.value))\n .map((item) => item.label),\n ];\n if (allSelectedLabels.length === 0) {\n lines.push(`${S_BAR} ${pc.dim('Selected: (none)')}`);\n } else {\n const summary =\n allSelectedLabels.length <= 3\n ? allSelectedLabels.join(', ')\n : `${allSelectedLabels.slice(0, 3).join(', ')} +${allSelectedLabels.length - 3} more`;\n lines.push(`${S_BAR} ${pc.green('Selected:')} ${summary}`);\n }\n\n lines.push(`${pc.dim('└')}`);\n } else if (state === 'submit') {\n // Final state - show what was selected (including locked)\n const allSelectedLabels = [\n ...(lockedSection ? lockedSection.items.map((i) => i.label) : []),\n ...items\n .filter((item) => selected.has(item.value))\n .map((item) => item.label),\n ];\n lines.push(`${S_BAR} ${pc.dim(allSelectedLabels.join(', '))}`);\n } else if (state === 'cancel') {\n lines.push(`${S_BAR} ${pc.strikethrough(pc.dim('Cancelled'))}`);\n }\n\n out.write(lines.join('\\n') + '\\n');\n lastRenderHeight = lines.length;\n };\n\n const cleanup = (): void => {\n process.stdin.removeListener('keypress', keypressHandler);\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(false);\n }\n rl.close();\n };\n\n const submit = (): void => {\n // If required and no locked items, don't allow submitting with no selection\n if (required && selected.size === 0 && lockedValues.length === 0) {\n return;\n }\n render('submit');\n cleanup();\n // Include locked values in the result\n resolve([...lockedValues, ...Array.from(selected)]);\n };\n\n const cancel = (): void => {\n render('cancel');\n cleanup();\n resolve(cancelSymbol);\n };\n\n // Handle keypresses\n const keypressHandler = (_str: string, key: readline.Key): void => {\n if (!key) return;\n\n const filtered = getFiltered();\n\n if (key.name === 'return') {\n submit();\n return;\n }\n\n if (key.name === 'escape' || (key.ctrl && key.name === 'c')) {\n cancel();\n return;\n }\n\n if (key.name === 'up') {\n cursor = Math.max(0, cursor - 1);\n render();\n return;\n }\n\n if (key.name === 'down') {\n cursor = Math.min(filtered.length - 1, cursor + 1);\n render();\n return;\n }\n\n if (key.name === 'space') {\n const item = filtered[cursor];\n if (item) {\n if (selected.has(item.value)) {\n selected.delete(item.value);\n } else {\n selected.add(item.value);\n }\n }\n render();\n return;\n }\n\n if (key.name === 'backspace') {\n query = query.slice(0, -1);\n cursor = 0;\n render();\n return;\n }\n\n // Regular character input\n if (key.sequence && !key.ctrl && !key.meta && key.sequence.length === 1) {\n query += key.sequence;\n cursor = 0;\n render();\n return;\n }\n };\n\n process.stdin.on('keypress', keypressHandler);\n\n // Initial render\n render();\n });\n}\n","export const AGENTS_DIR = '.agents';\nexport const SKILLS_SUBDIR = 'skills';\nexport const UNIVERSAL_SKILLS_DIR = '.agents/skills';\n","import { homedir, platform, tmpdir } from 'os';\nimport {\n cp,\n lstat,\n mkdir,\n readlink,\n realpath,\n rm,\n writeFile,\n symlink,\n readdir,\n stat,\n rename,\n unlink,\n} from 'fs/promises';\nimport path, {\n basename,\n dirname,\n join,\n normalize,\n relative,\n resolve,\n sep,\n} from 'path';\n\nimport { AgentType, RemoteSkill } from '../types';\nimport { agents } from './agents';\nimport { AGENTS_DIR, SKILLS_SUBDIR } from './constants';\nimport { execSync } from 'child_process';\nimport { downloadSkillPackage } from './api';\nimport { info } from 'console';\nimport { writeFileSync } from 'fs';\n\n/**\n * Validates that a path is within an expected base directory\n * @param basePath - The expected base directory\n * @param targetPath - The path to validate\n * @returns true if targetPath is within basePath\n */\nfunction isPathSafe(basePath: string, targetPath: string): boolean {\n const normalizedBase = normalize(resolve(basePath));\n const normalizedTarget = normalize(resolve(targetPath));\n\n return (\n normalizedTarget.startsWith(normalizedBase + sep) ||\n normalizedTarget === normalizedBase\n );\n}\n\nasync function resolveParentSymlinks(path: string): Promise<string> {\n const resolved = resolve(path);\n const dir = dirname(resolved);\n const base = basename(resolved);\n try {\n const realDir = await realpath(dir);\n return join(realDir, base);\n } catch {\n return resolved;\n }\n}\n\nfunction resolveSymlinkTarget(linkPath: string, linkTarget: string): string {\n return resolve(dirname(linkPath), linkTarget);\n}\n\n/**\n * Creates a symlink, handling cross-platform differences\n * Returns true if symlink was created, false if fallback to copy is needed\n */\nasync function createSymlink(\n target: string,\n linkPath: string,\n): Promise<boolean> {\n try {\n const resolvedTarget = resolve(target);\n const resolvedLinkPath = resolve(linkPath);\n\n // Use realpath to handle cases where parent directories are symlinked.\n // This prevents deleting the canonical directory if the agent directory\n // is a symlink to the canonical location.\n const [realTarget, realLinkPath] = await Promise.all([\n realpath(resolvedTarget).catch(() => resolvedTarget),\n realpath(resolvedLinkPath).catch(() => resolvedLinkPath),\n ]);\n\n if (realTarget === realLinkPath) {\n return true;\n }\n\n // Also check with symlinks resolved in parent directories.\n // This handles cases where e.g. ~/.claude/skills is a symlink to ~/.agents/skills,\n // so ~/.claude/skills/<skill> and ~/.agents/skills/<skill> are physically the same.\n const realTargetWithParents = await resolveParentSymlinks(target);\n const realLinkPathWithParents = await resolveParentSymlinks(linkPath);\n\n if (realTargetWithParents === realLinkPathWithParents) {\n return true;\n }\n\n try {\n const stats = await lstat(linkPath);\n if (stats.isSymbolicLink()) {\n const existingTarget = await readlink(linkPath);\n if (resolveSymlinkTarget(linkPath, existingTarget) === resolvedTarget) {\n return true;\n }\n await rm(linkPath);\n } else {\n await rm(linkPath, { recursive: true });\n }\n } catch (err: unknown) {\n // ELOOP = circular symlink, ENOENT = doesn't exist\n // For ELOOP, try to remove the broken symlink\n if (\n err &&\n typeof err === 'object' &&\n 'code' in err &&\n err.code === 'ELOOP'\n ) {\n try {\n await rm(linkPath, { force: true });\n } catch {\n // If we can't remove it, symlink creation will fail and trigger copy fallback\n }\n }\n // For ENOENT or other errors, continue to symlink creation\n }\n\n const linkDir = dirname(linkPath);\n await mkdir(linkDir, { recursive: true });\n\n // Use the real (symlink-resolved) parent directory for computing the relative path.\n // This ensures the symlink target is correct even when the link's parent dir is a symlink.\n const realLinkDir = await resolveParentSymlinks(linkDir);\n const relativePath = relative(realLinkDir, target);\n const symlinkType = platform() === 'win32' ? 'junction' : undefined;\n\n await symlink(relativePath, linkPath, symlinkType);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * 清理并创建目录\n * @param path - 目录路径\n * @returns 创建成功返回 true\n */\nasync function cleanAndCreateDirectory(path: string): Promise<void> {\n try {\n await rm(path, { recursive: true, force: true });\n } catch {\n // Ignore cleanup errors - mkdir will fail if there's a real problem\n }\n await mkdir(path, { recursive: true });\n}\n\n/**\n * 下载并解压包\n * @param asset - 包信息\n * @param targetDir - 解压目标目录\n * @returns 解压成功返回 true\n */\nexport async function downloadAndExtractPackage(\n asset: RemoteSkill,\n targetDir: string,\n): Promise<boolean> {\n let hasPackage = false;\n const version = asset.currentVersion?.version ?? '';\n\n if (!asset.slug || !version) {\n generateSkillMd(asset, targetDir);\n return false;\n }\n\n const pkgBuffer = await downloadSkillPackage(asset.slug, version);\n if (pkgBuffer && pkgBuffer.length > 0) {\n hasPackage = await extractPackage(pkgBuffer, targetDir);\n }\n\n if (!hasPackage) {\n info('No package available, generating from metadata...');\n generateSkillMd(asset, targetDir);\n console.log(' Generated: SKILL.md from metadata');\n }\n return hasPackage;\n}\n\nexport function getAgentBaseDir(\n agentType: AgentType,\n global: boolean,\n cwd?: string,\n): string {\n // if (isUniversalAgent(agentType)) {\n // return getCanonicalSkillsDir(global, cwd);\n // }\n\n const agent = agents[agentType];\n const baseDir = global ? homedir() : cwd || process.cwd();\n\n if (global) {\n if (agent.globalSkillsDir === undefined) {\n // This should be caught by callers checking support\n return join(baseDir, agent.skillsDir);\n }\n return agent.globalSkillsDir;\n }\n\n return join(baseDir, agent.skillsDir);\n}\n\nexport async function installWellKnownSkillForAgent(\n skill: RemoteSkill,\n agentType: AgentType,\n options: { global?: boolean; cwd?: string; mode?: string; path?: string } = {},\n): Promise<any> {\n const agent = agents[agentType];\n const isGlobal = options.global ?? false;\n const cwd = options.cwd || process.cwd();\n const installMode = options.mode ?? 'symlink';\n const customPath = options.path?.trim();\n\n // 自定义路径:直接安装到指定目录,跳过 agent 检测\n const skillName = sanitizeName(skill.slug);\n let agentDir: string;\n\n if (customPath) {\n const resolvedPath = resolve(customPath);\n agentDir = join(resolvedPath, skillName);\n if (!isPathSafe(resolvedPath, agentDir)) {\n return {\n success: false,\n path: agentDir,\n mode: 'copy',\n error: 'Invalid path: potential path traversal detected',\n };\n }\n try {\n await cleanAndCreateDirectory(agentDir);\n await downloadAndExtractPackage(skill, agentDir);\n return { success: true, path: agentDir, mode: 'copy' };\n } catch (error) {\n return {\n success: false,\n path: agentDir,\n mode: 'copy',\n error: error instanceof Error ? error.message : 'Unknown error',\n };\n }\n }\n\n // Check if agent supports global installation\n if (isGlobal && agent.globalSkillsDir === undefined) {\n return {\n success: false,\n path: '',\n mode: installMode,\n error: `${agent.displayName} does not support global skill installation`,\n };\n }\n\n // Canonical location: .agents/skills/<skill-name>\n const canonicalBase = getCanonicalSkillsDir(isGlobal, cwd);\n const canonicalDir = join(canonicalBase, skillName);\n\n // Agent-specific location (for symlink)\n const agentBase = getAgentBaseDir(agentType, isGlobal, cwd);\n agentDir = join(agentBase, skillName);\n\n // Validate paths\n if (!isPathSafe(canonicalBase, canonicalDir)) {\n return {\n success: false,\n path: agentDir,\n mode: installMode,\n error: 'Invalid skill name: potential path traversal detected',\n };\n }\n\n if (!isPathSafe(agentBase, agentDir)) {\n return {\n success: false,\n path: agentDir,\n mode: installMode,\n error: 'Invalid skill name: potential path traversal detected',\n };\n }\n\n async function populateSkillDir(targetDir: string): Promise<void> {\n await downloadAndExtractPackage(skill, targetDir);\n }\n\n try {\n // For copy mode, write directly to agent location\n if (installMode === 'copy') {\n await cleanAndCreateDirectory(agentDir);\n await populateSkillDir(agentDir);\n\n return {\n success: true,\n path: agentDir,\n mode: 'copy',\n };\n }\n\n // Symlink mode: write to canonical location and symlink to agent location\n await cleanAndCreateDirectory(canonicalDir);\n await populateSkillDir(canonicalDir);\n\n const symlinkCreated = await createSymlink(canonicalDir, agentDir);\n\n if (!symlinkCreated) {\n // Symlink failed, fall back to copy\n await cleanAndCreateDirectory(agentDir);\n await cp(canonicalDir, agentDir, { recursive: true });\n\n return {\n success: true,\n path: agentDir,\n canonicalPath: canonicalDir,\n mode: 'symlink',\n symlinkFailed: true,\n };\n }\n\n return {\n success: true,\n path: agentDir,\n canonicalPath: canonicalDir,\n mode: 'symlink',\n };\n } catch (error) {\n return {\n success: false,\n path: agentDir,\n mode: installMode,\n error: error instanceof Error ? error.message : 'Unknown error',\n };\n }\n}\n\nexport function sanitizeName(name: string): string {\n const sanitized = name\n .toLowerCase()\n // Replace any sequence of characters that are NOT lowercase letters (a-z),\n // digits (0-9), dots (.), or underscores (_) with a single hyphen.\n // This converts spaces, special chars, and path traversal attempts (../) into hyphens.\n .replace(/[^a-z0-9._]+/g, '-')\n // Remove leading/trailing dots and hyphens to prevent hidden files (.) and\n // ensure clean directory names. The pattern matches:\n // - ^[.\\-]+ : one or more dots or hyphens at the start\n // - [.\\-]+$ : one or more dots or hyphens at the end\n .replace(/^[.\\-]+|[.\\-]+$/g, '');\n\n // Limit to 255 chars (common filesystem limit), fallback to 'unnamed-skill' if empty\n return sanitized.substring(0, 255) || 'unnamed-skill';\n}\n\nexport function getCanonicalSkillsDir(global: boolean, cwd?: string): string {\n const baseDir = global ? homedir() : cwd || process.cwd();\n return join(baseDir, AGENTS_DIR, SKILLS_SUBDIR);\n}\n\n/**\n * 将包从 buffer 解压到目标目录\n * 接口返回 zip 格式,兼容 tar.gz\n * @param buffer - 待解压的 buffer\n * @param targetDir - 解压目标目录\n * @returns 解压成功返回 true\n */\nexport async function extractPackage(\n buffer: Buffer,\n targetDir: string,\n): Promise<boolean> {\n await mkdir(targetDir, { recursive: true });\n\n const tmpFile = join(tmpdir(), `openclawmp-pkg-${process.pid}-${Date.now()}`);\n await writeFile(tmpFile, buffer);\n\n try {\n // 接口返回 zip,优先尝试 unzip\n try {\n execSync(`unzip -o -q \"${tmpFile}\" -d \"${targetDir}\" 2>/dev/null`, {\n stdio: 'pipe',\n });\n // 若解压后只有一层子目录,将内容提升到 targetDir\n const entries = await readdir(targetDir);\n const dirs: string[] = [];\n for (const e of entries) {\n const s = await stat(join(targetDir, e));\n if (s.isDirectory()) dirs.push(e);\n }\n if (dirs.length === 1 && entries.length === 1) {\n const subdir = join(targetDir, dirs[0]);\n for (const f of await readdir(subdir)) {\n await rename(join(subdir, f), join(targetDir, f));\n }\n await rm(subdir, { recursive: true });\n }\n return true;\n } catch {\n // 兼容 tar.gz\n try {\n execSync(\n `tar xzf \"${tmpFile}\" -C \"${targetDir}\" --strip-components=1 2>/dev/null`,\n { stdio: 'pipe' },\n );\n return true;\n } catch {\n try {\n execSync(`tar xzf \"${tmpFile}\" -C \"${targetDir}\" 2>/dev/null`, {\n stdio: 'pipe',\n });\n return true;\n } catch {\n return false;\n }\n }\n }\n } finally {\n try {\n await unlink(tmpFile);\n } catch {}\n }\n}\n\nfunction generateSkillMd(asset: any, targetDir: string) {\n const tags = (asset.tags || []).join(', ');\n const version = asset.currentVersion ?? asset.version ?? '';\n const description = asset.summary || asset.description || '';\n const content = `---\nname: ${asset.slug || asset.name || ''}\ndisplay-name: ${asset.displayName || ''}\ndescription: ${description}\nversion: ${version}\nauthor: ${asset.author?.name || ''}\nauthor-id: ${asset.author?.id || ''}\ntags: ${tags}\ncategory: ${asset.category || ''}\n---\n\n# ${asset.displayName || asset.slug || asset.name || 'Skill'}\n\n${description}\n\n${asset.readme || ''}\n`;\n writeFileSync(path.join(targetDir, 'SKILL.md'), content);\n}\n","import * as p from '@clack/prompts';\nimport chalk from 'chalk';\nimport pc from 'picocolors';\n\nimport { findAsset } from '../core/api';\nimport { AgentType } from '../types';\nimport { agents } from '../core/agents';\nimport { searchMultiselect } from '../core/search-multiselect';\nimport { installWellKnownSkillForAgent } from '../core/installer';\n\nexport interface AddOptions {\n global?: boolean;\n agent?: string[];\n yes?: boolean;\n skill?: string[];\n list?: boolean;\n all?: boolean;\n fullDepth?: boolean;\n copy?: boolean;\n /** 安装到自定义路径(目录) */\n path?: string;\n}\n\ntype AgentChoice = { value: AgentType; label: string; hint?: string };\n\n/** 非 TTY 环境(如 OpenClaw、CI、管道)下自动启用非交互模式,避免阻塞 */\nfunction isNonInteractiveEnv(): boolean {\n return !process.stdin.isTTY;\n}\n\nexport async function promptForAgents(\n message: string,\n choices: AgentChoice[],\n initialValues?: AgentType[],\n): Promise<AgentType[] | symbol> {\n const selected = await searchMultiselect({\n message,\n items: choices,\n leadingSpacer: 1,\n initialSelected: initialValues,\n });\n\n return selected as AgentType[] | symbol;\n}\n\nfunction cancelAndExit(message: string): never {\n p.cancel(message);\n process.exit(0);\n}\n\nfunction errorAndExit(\n message: string,\n note?: { title: string; body: string },\n): never {\n p.log.error(message);\n if (note) {\n p.note(note.body, note.title);\n }\n process.exit(1);\n}\n\nfunction buildAgentChoices(globalInstall: boolean): AgentChoice[] {\n return Object.entries(agents).map(([key, config]) => ({\n value: key as AgentType,\n label: config.displayName,\n hint: globalInstall\n ? (config.globalSkillsDir ?? config.skillsDir)\n : config.skillsDir,\n }));\n}\n\nfunction getDefaultAgents(choices: AgentChoice[]): AgentType[] {\n const preferredAgents: AgentType[] = ['claude-code', 'openclaw'];\n return preferredAgents.filter((agent) =>\n choices.some((choice) => choice.value === agent),\n );\n}\n\nasync function resolveSkillName(\n inputSkill: string | undefined,\n nonInteractive: boolean,\n): Promise<string> {\n if (inputSkill?.trim()) {\n return inputSkill.trim();\n }\n\n // 非交互模式下无法提示输入,必须通过参数传入\n if (nonInteractive) {\n errorAndExit('Please provide skill name', {\n title: 'Usage',\n body: 'skill-atlas install <skillName>\\n\\nExample: skill-atlas install my-skill',\n });\n }\n\n const input = await p.text({\n message: 'Enter skill to install',\n placeholder: 'my-skill',\n validate: (value) => {\n if (!value?.trim()) return 'Please enter skill name';\n return undefined;\n },\n });\n\n if (p.isCancel(input)) {\n cancelAndExit('Cancelled');\n }\n\n return input.trim();\n}\n\n/** 校验并解析传入的 agent 名称(纯函数,可单独测试) */\nexport function parseAgentNames(\n input: string | string[] | undefined,\n): AgentType[] | { invalid: string[] } {\n // cac 可能将 --agent cursor 解析为 string,需规范为数组\n const names = Array.isArray(input) ? input : input ? [input] : [];\n if (!names.length) return [];\n const validKeys = new Set(Object.keys(agents));\n const result: AgentType[] = [];\n const invalid: string[] = [];\n for (const name of names) {\n const normalized = name.trim().toLowerCase();\n if (validKeys.has(normalized)) {\n result.push(normalized as AgentType);\n } else {\n invalid.push(name);\n }\n }\n if (invalid.length > 0) return { invalid };\n return result;\n}\n\nfunction resolveAgentNamesFromOptions(\n input: string | string[] | undefined,\n): AgentType[] {\n const parsed = parseAgentNames(input);\n if (Array.isArray(parsed)) return parsed;\n const examples = ['cursor', 'openclaw', 'claude-code', 'cline', 'codex'];\n errorAndExit(`Unknown agent(s): ${parsed.invalid.join(', ')}`, {\n title: 'Supported agents',\n body: `Examples: ${examples.join(', ')}\\nFull list: ${Object.keys(agents).join(', ')}`,\n });\n}\n\nasync function resolveTargetAgents(\n options: AddOptions,\n nonInteractive: boolean,\n): Promise<AgentType[]> {\n const allAgentChoices = buildAgentChoices(\n Boolean(options.global ?? options.yes ?? nonInteractive),\n );\n // -y 或非 TTY 时跳过选择\n if (options.yes || nonInteractive) {\n // 非 TTY 下若传入 --agent,按指定 agent 安装到对应目录;否则使用默认 agents\n const specified = resolveAgentNamesFromOptions(options.agent);\n if (specified.length > 0) {\n return specified;\n }\n const defaults = getDefaultAgents(allAgentChoices);\n if (defaults.length === 0) {\n cancelAndExit('No default agents available');\n }\n // 未传 --agent 时使用默认,输出提示便于 agent 调用方知晓可指定目标\n p.log.message(\n chalk.dim(\n '未指定 --agent,使用默认 agents。可用 --agent cursor 等指定安装目标',\n ),\n );\n return defaults;\n }\n const selected = await promptForAgents(\n 'Which agents do you want to install to?',\n allAgentChoices,\n getDefaultAgents(allAgentChoices),\n );\n\n if (p.isCancel(selected) || selected.length === 0) {\n cancelAndExit('Installation cancelled');\n }\n\n return selected;\n}\n\nasync function resolveInstallScope(\n options: AddOptions,\n targetAgents: AgentType[],\n nonInteractive: boolean,\n): Promise<boolean> {\n const supportsGlobal = targetAgents.some(\n (agent) => agents[agent].globalSkillsDir !== undefined,\n );\n\n // -y 或非 TTY 时默认安装到全局;显式指定 --global 时也生效\n if (\n options.global !== undefined ||\n options.yes ||\n nonInteractive ||\n !supportsGlobal\n ) {\n return options.global ?? (options.yes || nonInteractive ? true : false);\n }\n\n const scope = await p.select({\n message: 'Installation scope',\n options: [\n {\n value: true,\n label: 'Global',\n hint: 'Install in home directory (available across all projects)',\n },\n {\n value: false,\n label: 'Project',\n hint: 'Install in current directory (committed with your project)',\n },\n ],\n });\n\n if (p.isCancel(scope)) {\n cancelAndExit('Installation cancelled');\n }\n\n return scope;\n}\n\n/** 非 TTY 下使用静态输出替代 spinner,避免动画帧被逐行打印造成刷屏 */\nfunction createProgressReporter(nonInteractive: boolean) {\n if (nonInteractive) {\n return {\n start: (msg: string) => p.log.message(msg),\n stop: (msg?: string) => {\n if (msg) p.log.message(msg);\n },\n };\n }\n const s = p.spinner();\n return {\n start: (msg: string) => s.start(msg),\n stop: (msg?: string) => s.stop(msg ?? ''),\n };\n}\n\nconst run = async (args: string[], options: AddOptions = {}) => {\n // 非 TTY 环境(OpenClaw、CI、管道)自动启用非交互模式,避免 p.text/searchMultiselect/p.select 阻塞\n const nonInteractive = options.yes || isNonInteractiveEnv();\n\n p.intro(chalk.bold('skill-atlas install'));\n\n const skill = await resolveSkillName(args[0], nonInteractive);\n\n const progress = createProgressReporter(nonInteractive);\n progress.start(`Searching for ${chalk.bold(skill)}...`);\n\n try {\n const asset = await findAsset(skill);\n\n if (!asset) {\n progress.stop();\n errorAndExit(`Not found: ${chalk.bold(skill)}`, {\n title: 'Suggest',\n body: `Try: skill-atlas search ${skill}`,\n });\n }\n\n const displayName = asset.displayName || asset.slug;\n const version = asset.currentVersion.version ?? '0.0.0';\n progress.stop(`${chalk.bold(displayName)} ${chalk.dim(`v${version}`)}`);\n\n const customPath = options.path?.trim();\n const installMode = options.copy ? 'copy' : 'symlink';\n const installResults: { agent: AgentType; path: string }[] = [];\n\n if (customPath) {\n // 安装到自定义路径\n progress.start(`${chalk.dim('Installing to')} ${customPath}...`);\n const result = await installWellKnownSkillForAgent(asset, 'openclaw', {\n path: customPath,\n mode: installMode,\n });\n if (!result.success) {\n throw new Error(\n `Failed to install to ${customPath}: ${result.error || 'Unknown error'}`,\n );\n }\n installResults.push({ agent: 'openclaw', path: result.path });\n } else {\n const targetAgents = await resolveTargetAgents(options, nonInteractive);\n const installGlobally = await resolveInstallScope(\n options,\n targetAgents,\n nonInteractive,\n );\n const selectedLabels = targetAgents.map((a) => agents[a].displayName);\n p.log.message(chalk.green('Selected:') + ' ' + selectedLabels.join(', '));\n\n progress.start('Installing skills...');\n\n for (const agent of targetAgents) {\n const result = await installWellKnownSkillForAgent(asset, agent, {\n global: installGlobally,\n mode: installMode,\n });\n if (!result.success) {\n throw new Error(\n `Failed to install to ${agents[agent].displayName}: ${result.error || 'Unknown error'}`,\n );\n }\n installResults.push({ agent, path: result.path });\n }\n }\n\n progress.stop('Skills installed successfully');\n const title = pc.green('Installed 1 skill');\n const resultLines = customPath\n ? [` ${customPath}: ${installResults[0].path}`]\n : installResults.map(\n (r) => ` ${agents[r.agent].displayName}: ${r.path}`,\n );\n p.note(resultLines.join('\\n'), title);\n p.outro(pc.green('Done!') + pc.dim(' Skill ready. Review before use.'));\n } catch (err) {\n progress.stop();\n p.log.error(`Install failed: ${(err as Error).message}`);\n process.exit(1);\n }\n};\n\nexport default {\n run,\n};\n","import * as p from '@clack/prompts';\nimport pc from 'picocolors';\nimport fs from 'node:fs';\nimport { createHash, randomBytes } from 'node:crypto';\nimport secp256k1 from 'secp256k1';\n\nimport {\n registerAgent,\n getChallenge,\n authenticateAgent,\n ApiError,\n} from '../core/api';\nimport config from '../core/config';\nimport type { RegisterAgentRequest, AuthenticateAgentRequest } from '../types';\n\nconst KEYPAIR_FILE = `${config.CONFIG_DIR}/agent-keypair.json`;\n\ninterface KeyPairData {\n privateKey: string;\n publicKey: string;\n createdAt: string;\n}\n\n/**\n * 从公钥派生 agentId\n * Agent ID = sha3-256(publicKey)[12:] 的16进制表示,添加0x前缀\n * 与后端 Secp256k1Utils.deriveAgentId 保持一致\n *\n * 未压缩公钥格式为 0x04 + x(32字节) + y(32字节) = 65字节,\n * 派生时需要先移除 0x04 前缀\n */\nexport function deriveAgentId(publicKey: Buffer): string {\n const publicKeyWithoutPrefix = publicKey.slice(1);\n const digest = createHash('sha3-256').update(publicKeyWithoutPrefix).digest();\n return '0x' + digest.slice(-20).toString('hex');\n}\n\n/**\n * 对任意消息进行 secp256k1 签名,返回 0x 前缀的 DER 格式 hex 字符串\n * 与后端 Secp256k1Utils.parseSignature 兼容\n */\nfunction signMessage(privateKey: Buffer, message: string): string {\n const messageHash = createHash('sha256').update(message).digest();\n const { signature } = secp256k1.ecdsaSign(messageHash, privateKey);\n const derBytes = secp256k1.signatureExport(signature);\n return '0x' + Buffer.from(derBytes).toString('hex');\n}\n\nexport function createRegisterSignature(\n privateKey: Buffer,\n agentId: string,\n timestamp: number,\n): string {\n return signMessage(privateKey, `${agentId}${timestamp}`);\n}\n\nexport function createAuthSignature(\n privateKey: Buffer,\n agentId: string,\n nonce: string,\n timestamp: number,\n): string {\n return signMessage(privateKey, `${agentId}${nonce}${timestamp}`);\n}\n\n/**\n * 加载或生成 secp256k1 密钥对\n * 私钥存储在 ~/.skillatlas/agent-keypair.json\n */\nexport function loadOrGenerateKeyPair(): {\n privateKey: Buffer;\n publicKey: Buffer;\n} {\n // 确保配置目录存在\n config.ensureConfigDir();\n\n // 尝试加载已有的密钥对\n if (fs.existsSync(KEYPAIR_FILE)) {\n try {\n const data: KeyPairData = JSON.parse(\n fs.readFileSync(KEYPAIR_FILE, 'utf-8'),\n );\n return {\n privateKey: Buffer.from(data.privateKey, 'hex'),\n publicKey: Buffer.from(data.publicKey, 'hex'),\n };\n } catch {\n // 加载失败则生成新的密钥对\n }\n }\n\n // 生成新的密钥对\n let privateKey: Buffer;\n do {\n privateKey = randomBytes(32);\n } while (!secp256k1.privateKeyVerify(privateKey));\n\n const publicKey = secp256k1.publicKeyCreate(privateKey, false); // 非压缩格式\n\n // 保存密钥对\n const keyData: KeyPairData = {\n privateKey: privateKey.toString('hex'),\n publicKey: Buffer.from(publicKey).toString('hex'),\n createdAt: new Date().toISOString(),\n };\n\n fs.writeFileSync(KEYPAIR_FILE, JSON.stringify(keyData, null, 2) + '\\n');\n\n return {\n privateKey,\n publicKey: Buffer.from(publicKey),\n };\n}\n\n/**\n * 本地是否已保存 Agent 凭据(与注册流程中「已注册」判断一致,供测试与外部复用)\n */\nexport function isAlreadyRegistered(): boolean {\n return config.getAgentCredentials() !== null;\n}\n\n/**\n * 判断是否为 \"Agent 已存在\" 的已知情况。\n * 同时兼容 ApiError 实例和 { code, message } 形式的响应对象,\n * 已存在时可跳过注册直接进入 challenge → authenticate 流程\n */\nfunction isAgentExistsError(error: unknown): boolean {\n if (error instanceof ApiError) {\n return error.code === 'AGENT_EXISTS' || error.message.includes('Agent already exists');\n }\n if (error instanceof Error) {\n return error.message.includes('Agent already exists');\n }\n if (typeof error === 'object' && error !== null) {\n const obj = error as Record<string, unknown>;\n return obj.code === 'AGENT_EXISTS' ||\n (typeof obj.message === 'string' && obj.message.includes('Agent already exists'));\n }\n return String(error).includes('Agent already exists');\n}\n\nconst ERROR_HINTS: Array<{\n keyword: string;\n error: string;\n hint: string;\n}> = [\n { keyword: 'Agent already exists', error: 'Agent 已存在', hint: '使用 --force 参数可强制重新注册' },\n { keyword: 'Invalid signature', error: '签名无效', hint: '请重试或联系支持' },\n { keyword: 'Invalid timestamp', error: '时间戳无效或检测到重放攻击', hint: '请检查系统时间' },\n { keyword: 'Challenge expired', error: '挑战已过期', hint: '请重新注册' },\n { keyword: 'Nonce already used', error: 'Nonce 已被使用', hint: '请重新注册' },\n { keyword: 'Agent not found', error: 'Agent 未找到', hint: '请先完成注册' },\n];\n\nfunction logKnownError(errorMessage: string): void {\n const matched = ERROR_HINTS.find((h) => errorMessage.includes(h.keyword));\n if (matched) {\n p.log.error(matched.error);\n p.log.info(matched.hint);\n } else {\n p.log.error(`注册失败: ${errorMessage}`);\n p.log.info('请检查网络连接后重试');\n }\n}\n\nconst run = async (options: { force?: boolean } = {}) => {\n p.intro(pc.bold('skill-atlas agent-register'));\n\n if (!options.force) {\n const credentials = config.getAgentCredentials();\n if (credentials) {\n p.log.warn(`Agent 已注册 (agentId: ${credentials.agentId})`);\n\n const shouldReRegister = await p.confirm({\n message: '是否要重新注册?',\n initialValue: false,\n });\n\n if (p.isCancel(shouldReRegister) || !shouldReRegister) {\n p.cancel('已取消注册');\n process.exit(0);\n }\n }\n }\n\n const spinner = p.spinner();\n spinner.start('正在生成密钥对...');\n\n try {\n const { privateKey, publicKey } = loadOrGenerateKeyPair();\n const agentId = deriveAgentId(publicKey);\n\n spinner.stop('密钥对已就绪');\n\n // ========== 步骤 1: 注册 Agent ==========\n spinner.start('步骤 1/3: 正在注册 Agent...');\n\n const registerTimestamp = Math.floor(Date.now() / 1000);\n const registerRequest: RegisterAgentRequest = {\n agentId,\n publicKey: '0x' + publicKey.toString('hex'),\n signature: createRegisterSignature(privateKey, agentId, registerTimestamp),\n timestamp: registerTimestamp,\n };\n\n if (process.env.DEBUG_PAYLOAD) {\n console.log('\\n==== DEBUG PAYLOAD ====');\n console.log(JSON.stringify(registerRequest, null, 2));\n console.log('=======================\\n');\n }\n\n let registeredAgentId = agentId;\n let registeredAt = new Date().toISOString();\n let registerStatus = 'active';\n\n try {\n const res = await registerAgent(registerRequest);\n if (!res.success) {\n if (isAgentExistsError({ message: res.message, code: (res as any).code })) {\n spinner.stop('步骤 1/3: Agent 已存在,跳过注册直接进行认证');\n } else {\n spinner.stop('注册失败');\n p.log.error(res.message || '注册失败');\n process.exit(1);\n }\n } else {\n registeredAgentId = res.data?.agentId || agentId;\n registeredAt = res.data?.registeredAt || registeredAt;\n registerStatus = res.data?.status || 'active';\n spinner.stop('步骤 1/3: Agent 注册成功');\n }\n } catch (err) {\n if (isAgentExistsError(err)) {\n spinner.stop('步骤 1/3: Agent 已存在,跳过注册直接进行认证');\n } else {\n throw err;\n }\n }\n\n // ========== 步骤 2: 获取登录挑战 ==========\n spinner.start('步骤 2/3: 正在获取登录挑战...');\n\n const challengeResponse = await getChallenge(registeredAgentId);\n if (!challengeResponse.success || !challengeResponse.data) {\n spinner.stop('获取挑战失败');\n p.log.error(challengeResponse.message || '无法获取登录挑战');\n process.exit(1);\n }\n\n const { nonce, timestamp: challengeTimestamp } = challengeResponse.data;\n spinner.stop('步骤 2/3: 获取挑战成功');\n\n // ========== 步骤 3: 认证获取 Token ==========\n spinner.start('步骤 3/3: 正在认证...');\n\n const authRequest: AuthenticateAgentRequest = {\n agentId: registeredAgentId,\n signature: createAuthSignature(privateKey, registeredAgentId, nonce, challengeTimestamp),\n nonce,\n timestamp: challengeTimestamp,\n };\n\n const authResponse = await authenticateAgent(authRequest);\n if (!authResponse.success || !authResponse.data) {\n spinner.stop('认证失败');\n p.log.error(authResponse.message || '认证失败');\n process.exit(1);\n }\n\n const { token, expiresAt } = authResponse.data;\n config.saveAgentCredentials(registeredAgentId, token, registeredAt, expiresAt);\n\n spinner.stop('步骤 3/3: 认证成功');\n\n p.note(\n [\n ` ${pc.green('Agent ID:')} ${registeredAgentId}`,\n ` ${pc.green('状态:')} ${registerStatus}`,\n ` ${pc.green('注册时间:')} ${registeredAt}`,\n ` ${pc.green('Token 过期:')} ${expiresAt}`,\n ].join('\\n'),\n pc.green('Agent 注册完成'),\n );\n p.outro(pc.green('完成!') + pc.dim(' 您的 Agent 已成功注册并认证。'));\n } catch (error) {\n spinner.stop('注册失败');\n logKnownError(error instanceof Error ? error.message : String(error));\n process.exit(1);\n }\n};\n\nexport default {\n run,\n};\n","import * as p from '@clack/prompts';\nimport chalk from 'chalk';\n\nimport { searchSkills } from '../core/api';\nimport type { RemoteSkill } from '../types';\n\n/**\n * 根据接口文档 /api/v1/skills 搜索 skill\n * q 有值时执行搜索;q 为空时按热度排序返回列表\n */\nexport interface SearchOptions {\n /** 搜索关键词 */\n keyword: string;\n}\n\nfunction getVersion(skill: RemoteSkill): string {\n const cv = skill.currentVersion;\n if (typeof cv === 'string') return cv;\n if (cv && typeof cv === 'object' && 'version' in cv) {\n return (cv as { version?: string }).version ?? '—';\n }\n return '—';\n}\n\nfunction printSkillList(\n items: RemoteSkill[],\n total: number,\n page: number,\n pageSize: number,\n) {\n const maxSlugLen = Math.max(...items.map((s) => (s.slug || '').length), 6);\n const maxDescLen = Math.max(\n ...items.map((s) => Math.min((s.displayName || '—').length, 30)),\n 8,\n );\n const header = ` ${chalk.bold('Description'.padEnd(maxDescLen))} ${chalk.bold('SkillName'.padEnd(maxSlugLen))} ${chalk.bold('Version')}`;\n const separator = ' ' + '-'.repeat(maxSlugLen + maxDescLen + 12);\n const resultLines = items.map((s) => {\n const slug = (s.slug || '—').padEnd(maxSlugLen);\n const desc =\n (s.displayName || '—').length > 30\n ? (s.displayName || '—').slice(0, 27) + '...'\n : s.displayName || '—';\n const descPadded = desc.padEnd(maxDescLen);\n const version = getVersion(s);\n return ` ${chalk.white(descPadded)} ${chalk.cyan.bold(slug)} ${chalk.dim(`v${version}`)}`;\n });\n\n p.note(\n [header, separator, ...resultLines].join('\\n'),\n chalk.green(`Found ${total} skill(s)`),\n );\n const start = (page - 1) * pageSize + 1;\n const end = Math.min(page * pageSize, total);\n p.log.message(chalk.dim(`Showing ${start}-${end} of ${total}`));\n p.log.message(chalk.green(`Install: npx skill-atlas install <skillName>`));\n}\n\nexport async function runSearch(options: SearchOptions): Promise<void> {\n const { keyword } = options;\n\n try {\n const result = await searchSkills({\n q: keyword,\n });\n\n const { items, total } = result;\n\n if (items.length === 0) {\n p.log.error(`No skills found matching \"${chalk.bold(keyword)}\"`);\n return;\n }\n\n printSkillList(items, total, result.page, result.pageSize);\n } catch (err) {\n p.log.error(`Search failed: ${(err as Error).message}`);\n process.exit(1);\n }\n}\n","// ============================================================================\n// logger.ts — 基于 consola 的统一日志输出\n//\n// 提供 info / success / warn / error / debug 等方法\n// 支持 --verbose 时显示 debug 输出\n// ============================================================================\n\nimport { createConsola } from 'consola';\n\nconst consola = createConsola();\n\n/**\n * 设置 verbose 模式(启用 debug 输出)\n * consola level: 3=info, 4=debug\n */\nfunction setVerbose(enabled: boolean) {\n consola.level = enabled ? 4 : 3;\n}\n\n/**\n * 检查是否启用 verbose\n */\nfunction isVerbose(): boolean {\n return consola.level >= 4;\n}\n\n/**\n * 错误别名(兼容 err 调用)\n */\nfunction err(...args: unknown[]) {\n (consola.error as (...a: unknown[]) => void).apply(consola, args);\n}\n\ntype LogFn = (...a: unknown[]) => void;\n\nexport default {\n setVerbose,\n isVerbose,\n info: ((...a: unknown[]) =>\n consola.info(...(a as [unknown, ...unknown[]]))) as LogFn,\n success: ((...a: unknown[]) =>\n consola.success(...(a as [unknown, ...unknown[]]))) as LogFn,\n warn: ((...a: unknown[]) =>\n consola.warn(...(a as [unknown, ...unknown[]]))) as LogFn,\n error: ((...a: unknown[]) =>\n consola.error(...(a as [unknown, ...unknown[]]))) as LogFn,\n err,\n debug: ((...a: unknown[]) =>\n consola.debug(...(a as [unknown, ...unknown[]]))) as LogFn,\n log: ((...a: unknown[]) =>\n consola.log(...(a as [unknown, ...unknown[]]))) as LogFn,\n};\n","/**\n * update 命令:快速升级 CLI 到最新版本\n */\nimport { spawn } from 'node:child_process';\nimport * as p from '@clack/prompts';\nimport chalk from 'chalk';\nimport semver from 'semver';\n\nimport logger from '../core/logger';\n\n/** 从 npm registry 获取最新版本 */\nasync function fetchLatestVersion(pkgName: string): Promise<string> {\n const registry =\n process.env.npm_config_registry || 'https://registry.npmjs.org';\n const baseUrl = registry.replace(/\\/$/, '');\n const res = await fetch(`${baseUrl}/-/package/${pkgName}/dist-tags`, {\n signal: AbortSignal.timeout(5000),\n });\n if (!res.ok) throw new Error('获取最新版本失败');\n const json = (await res.json()) as { latest?: string };\n return json.latest || '0.0.0';\n}\n\n/** 执行 npm install -g <pkg>@latest */\nfunction runNpmUpdate(pkgName: string): Promise<number> {\n return new Promise((resolve) => {\n const child = spawn('npm', ['install', '-g', `${pkgName}@latest --force`], {\n stdio: 'inherit',\n shell: true,\n });\n child.on('close', (code) => resolve(code ?? 0));\n child.on('error', () => resolve(1));\n });\n}\n\nexport interface UpdateOptions {\n /** 包名 */\n pkgName: string;\n /** 当前版本 */\n currentVersion: string;\n /** 非交互模式,跳过确认 */\n yes?: boolean;\n}\n\nexport async function runUpdate(options: UpdateOptions): Promise<void> {\n const { pkgName, currentVersion, yes } = options;\n\n const spinner = p.spinner();\n spinner.start('检查最新版本...');\n\n try {\n const latest = await fetchLatestVersion(pkgName);\n spinner.stop('检查完成');\n\n if (!semver.valid(latest)) {\n p.log.error(`无法解析最新版本: ${latest}`);\n process.exit(1);\n }\n\n if (semver.lte(latest, currentVersion)) {\n p.log.success(`已是最新版本 ${chalk.cyan(currentVersion)}`);\n return;\n }\n\n p.log.message(\n `发现新版本: ${chalk.red(currentVersion)} → ${chalk.green(latest)}`,\n );\n\n const proceed =\n yes || !process.stdin.isTTY\n ? true\n : await p.confirm({\n message: '是否立即升级?',\n initialValue: true,\n });\n\n if (p.isCancel(proceed) || proceed === false) {\n p.cancel('已取消升级');\n return;\n }\n\n spinner.start('正在升级...');\n const code = await runNpmUpdate(pkgName);\n spinner.stop(code === 0 ? '升级完成' : '升级失败');\n\n if (code !== 0) {\n logger.error(\n '升级失败,可手动执行: npm install -g ' + pkgName + '@latest',\n );\n process.exit(1);\n }\n\n p.log.success(`已升级到 ${chalk.green(latest)}`);\n } catch (err) {\n spinner.stop('检查失败');\n p.log.error((err as Error).message);\n logger.info('可手动执行: npm install -g ' + pkgName + '@latest');\n process.exit(1);\n }\n}\n"],"x_google_ignoreList":[2,4],"mappings":"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"}
|