skill-atlas-cli 0.3.3-beta.5 → 0.3.3-beta.7
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/bin/cli.js +7 -7
- package/package.json +1 -1
- package/skillhub.md +13 -5
package/bin/cli.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import e,{readFileSync as t}from"node:fs";import{cac as n}from"cac";import{agentRegister as r,checkForUpdate as i,install as a,
|
|
3
|
-
`)}function
|
|
4
|
-
`)}function
|
|
5
|
-
`)}}function j(){A();try{return JSON.parse(e.readFileSync(
|
|
6
|
-
`)}function
|
|
7
|
-
`)}var
|
|
8
|
-
`),
|
|
2
|
+
import e,{readFileSync as t}from"node:fs";import{cac as n}from"cac";import{agentRegister as r,checkForUpdate as i,install as a,logger as o,skillReview as s,skillUpload as c}from"../lib/index.js";import*as l from"@clack/prompts";import u from"chalk";import d from"axios";import f from"node:path";import p from"node:os";import m from"semver";import{createConsola as h}from"consola";import{spawn as g}from"node:child_process";const _=process.env.SKILLATLAS_CONFIG_DIR||f.join(p.homedir(),`.skillatlas`),v=f.join(_,`auth.json`),y=f.join(_,`skillatlas-meta.json`),b={production:{apiBase:`https://skillatlas.cn/`},pre:{apiBase:`https://pre-skillhub.aliyun-inc.com/`}},ee=process.env.SKILLATLAS_ENV||`production`;let x=process.env.SKILLATLAS_API_BASE||b[ee].apiBase;const S=process.env.OPENCLAW_STATE_DIR||f.join(p.homedir(),`.openclaw`),C=f.join(S,`seafood-lock.json`),w=f.join(S,`identity`,`device.json`),T={skill:`skills`,plugin:`plugins`,trigger:`triggers`,channel:`channels`,experience:`experiences`};function E(){e.existsSync(_)||e.mkdirSync(_,{recursive:!0})}function te(e){let t=T[e];if(!t)throw Error(`Unknown asset type: ${e}. Valid types: ${Object.keys(T).join(`, `)}`);return f.join(S,t)}function D(){return x}function O(e){x=e.replace(/\/+$/,``)}function k(){O(b.pre.apiBase)}function ne(){if(process.env.OPENCLAWMP_TOKEN)return process.env.OPENCLAWMP_TOKEN;if(E(),e.existsSync(v))try{let t=JSON.parse(e.readFileSync(v,`utf-8`));if(t.token)return t.token}catch{}return null}function re(t,n={}){E();let r={token:t,savedAt:new Date().toISOString(),...n};e.writeFileSync(v,JSON.stringify(r,null,2)+`
|
|
3
|
+
`)}function ie(){if(!e.existsSync(w))return null;try{return JSON.parse(e.readFileSync(w,`utf-8`)).deviceId||null}catch{return null}}function ae(){E();let t={};if(e.existsSync(y))try{if(t=JSON.parse(e.readFileSync(y,`utf-8`)),t.agentId)return t.agentId}catch{}return null}function oe(t,n,r,i){E();let a={};if(e.existsSync(y))try{a=JSON.parse(e.readFileSync(y,`utf-8`))}catch{}a.agentId=t,a.token=n,r&&(a.registeredAt=r),i&&(a.expiresAt=i),a.credentialsSavedAt=new Date().toISOString(),e.writeFileSync(y,JSON.stringify(a,null,2)+`
|
|
4
|
+
`)}function se(){if(!e.existsSync(y))return null;try{let t=JSON.parse(e.readFileSync(y,`utf-8`));return t.agentId&&t.token?{agentId:t.agentId,token:t.token,registeredAt:t.registeredAt,expiresAt:t.expiresAt}:null}catch{return null}}function A(){if(!e.existsSync(C)){let t=f.dirname(C);e.existsSync(t)||e.mkdirSync(t,{recursive:!0}),e.writeFileSync(C,JSON.stringify({version:1,installed:{}},null,2)+`
|
|
5
|
+
`)}}function j(){A();try{return JSON.parse(e.readFileSync(C,`utf-8`))}catch{return{version:1,installed:{}}}}function ce(t,n,r){let i=j();i.installed[t]={version:n,installedAt:new Date().toISOString(),location:r},e.writeFileSync(C,JSON.stringify(i,null,2)+`
|
|
6
|
+
`)}function M(t){let n=j();delete n.installed[t],e.writeFileSync(C,JSON.stringify(n,null,2)+`
|
|
7
|
+
`)}var N={CONFIG_DIR:_,OPENCLAW_STATE_DIR:S,LOCKFILE:C,DEVICE_JSON:w,ASSET_TYPES:T,ensureConfigDir:E,installDirForType:te,getApiBase:D,setApiBase:O,applyPreEnvironment:k,getAuthToken:ne,saveAuthToken:re,getDeviceId:ie,initLockfile:A,readLockfile:j,updateLockfile:ce,removeLockfile:M,getAgentId:ae,saveAgentCredentials:oe,getAgentCredentials:se},P=class extends Error{code;responseData;constructor(e,t,n){super(e),this.name=`ApiError`,this.code=t,this.responseData=n}};const F=d.create({timeout:1e4,headers:{"Content-Type":`application/json`}});F.interceptors.request.use(e=>(e.baseURL=N.getApiBase(),e.headers.set(`X-SkillAtlas-Agent-Id`,N.getAgentId()),e)),F.interceptors.response.use(e=>e,e=>{if(e.response){let{data:t,statusText:n}=e.response;throw new P(t?.message||t?.error||n,t?.code,t)}throw e});async function I(e,t={}){let n=Object.fromEntries(Object.entries(t).filter(([,e])=>e!=null&&e!==``));return(await F.get(e,{params:n})).data}function L(e){let{items:t,page:n,pageSize:r,total:i}=(e&&typeof e==`object`&&`data`in e?e.data:e)??{};return{items:Array.isArray(t)?t:[],page:n??1,pageSize:r??20,total:i??0}}async function R(e={}){return L(await I(`/api/v1/skills`,{page:1,pageSize:20,...e}))}function z(e){let t=e.currentVersion;return typeof t==`string`?t:t&&typeof t==`object`&&`version`in t?t.version??`—`:`—`}function B(e,t,n,r){let i=Math.max(...e.map(e=>(e.slug||``).length),6),a=Math.max(...e.map(e=>Math.min((e.displayName||`—`).length,30)),8),o=` ${u.bold(`Description`.padEnd(a))} ${u.bold(`SkillName`.padEnd(i))} ${u.bold(`Version`)}`,s=` `+`-`.repeat(i+a+12),c=e.map(e=>{let t=(e.slug||`—`).padEnd(i),n=((e.displayName||`—`).length>30?(e.displayName||`—`).slice(0,27)+`...`:e.displayName||`—`).padEnd(a),r=z(e);return` ${u.white(n)} ${u.cyan.bold(t)} ${u.dim(`v${r}`)}`});l.note([o,s,...c].join(`
|
|
8
|
+
`),u.green(`Found ${t} skill(s)`));let d=(n-1)*r+1,f=Math.min(n*r,t);l.log.message(u.dim(`Showing ${d}-${f} of ${t}`)),l.log.message(u.green(`Install: npx skill-atlas install <skillName>`))}async function V(e){let{keyword:t}=e;try{let e=await R({q:t}),{items:n,total:r}=e;if(n.length===0){l.log.error(`No skills found matching "${u.bold(t)}"`);return}B(n,r,e.page,e.pageSize)}catch(e){l.log.error(`Search failed: ${e.message}`),process.exit(1)}}const H=h();function U(e){H.level=e?4:3}function W(){return H.level>=4}function G(...e){H.error.apply(H,e)}var K={setVerbose:U,isVerbose:W,info:((...e)=>H.info(...e)),success:((...e)=>H.success(...e)),warn:((...e)=>H.warn(...e)),error:((...e)=>H.error(...e)),err:G,debug:((...e)=>H.debug(...e)),log:((...e)=>H.log(...e))};const q=`https://unpkg.com/skill-atlas-cli`,J=`curl -fsSL ${q}/install.sh | bash`,Y=`irm ${q}/install.ps1 | iex`;function X(){return process.platform===`win32`?Y:J}function le(e){return new Promise(t=>{let n=g(`npm`,[`install`,`-g`,`${e}@latest`,`--force`],{stdio:`inherit`,shell:!0});n.on(`close`,e=>t(e??0)),n.on(`error`,()=>t(1))})}function ue(){return new Promise(e=>{let t=process.platform===`win32`?g(`powershell.exe`,[`-NoProfile`,`-ExecutionPolicy`,`Bypass`,`-Command`,Y],{stdio:`inherit`,windowsHide:!0}):g(`bash`,[`-c`,J],{stdio:`inherit`});t.on(`close`,t=>e(t??0)),t.on(`error`,()=>e(1))})}async function de(e){let t=(process.env.npm_config_registry||`https://registry.npmjs.org`).replace(/\/$/,``),n=await fetch(`${t}/-/package/${e}/dist-tags`,{signal:AbortSignal.timeout(5e3)});if(!n.ok)throw Error(`获取最新版本失败`);return(await n.json()).latest||`0.0.0`}async function fe(e){let{pkgName:t,currentVersion:n,yes:r,plugin:i}=e,a=l.spinner();a.start(`检查最新版本...`);try{let e=await de(t);if(a.stop(`检查完成`),m.valid(e)||(l.log.error(`无法解析最新版本: ${e}`),process.exit(1)),m.lte(e,n)){l.log.success(`已是最新版本 ${u.cyan(n)}`);return}l.log.message(`发现新版本: ${u.red(n)} → ${u.green(e)}`+(i?u.dim(`(将使用官方安装脚本更新 CLI 与插件)`):``));let o=r||!process.stdin.isTTY?!0:await l.confirm({message:`是否立即升级?`,initialValue:!0});if(l.isCancel(o)||o===!1){l.cancel(`已取消升级`);return}a.start(i?`正在通过官方脚本升级(CLI + 插件)…`:`正在升级...`);let s=i?await ue():await le(t);a.stop(s===0?`升级完成`:`升级失败`),s!==0&&(i?K.error(`升级失败,可手动执行: `+X()):K.error(`升级失败,可手动执行: npm install -g `+t+`@latest`),process.exit(1)),l.log.success(i?`已通过官方脚本更新(目标版本 ${u.green(e)})`:`已升级到 ${u.green(e)}`)}catch(e){a.stop(`检查失败`),l.log.error(e.message),i?K.info(`可手动执行: `+X()):K.info(`可手动执行: npm install -g `+t+`@latest`),process.exit(1)}}const pe={name:`search [keyword]`,description:`搜索 skill(按名称或描述匹配)`,action:async e=>{e?.trim()||(K.error(`请提供搜索关键词`),K.info(`提示: skill-atlas search <关键词>`),process.exit(1)),await V({keyword:e.trim()})}},Z={name:`update`,description:`快速升级 CLI 到最新版本`,options:[{flags:`-y, --yes`,description:`非交互模式,跳过确认直接升级`},{flags:`-p, --plugin`,description:`使用官方安装脚本,同步更新 agent 插件与 CLI(推荐: skill-atlas update -y -p)`}],action:async e=>{let t=Z._pkgInfo||{name:`skill-atlas`,version:`1.0.0`};await fe({pkgName:t.name,currentVersion:t.version,yes:e.yes,plugin:e.plugin})}},me=[pe,Z,{name:`install [name]`,description:`安装 skill(支持 skill 名称)`,options:[{flags:`-y, --yes`,description:`非交互模式,默认安装到全局`},{flags:`-g, --global`,description:`安装到全局目录`},{flags:`-p, --path <dir>`,description:`安装到自定义路径(目录),如 -p /path/to/skills 或 -p .qoder/skills`},{flags:`-a, --agent <agent...>`,description:`非交互/非 TTY 时指定目标 agent(如 cursor、openclaw)`}],action:async(e,t)=>{await a.run(e?[e]:[],{yes:t.yes,global:t.global,agent:t.agent,path:t.path})}},{name:`agent-register`,description:`注册 Agent 到 SkillAtlas 社区`,options:[{flags:`-f, --force`,description:`强制重新注册(即使已注册)`},{flags:`--pre`,description:`使用预发环境 API 执行注册与认证`}],action:async e=>{await r.run({force:e.force,pre:e.pre})}},{name:`skill-review <skillSlug>`,description:`对指定 Skill 发表评论`,options:[{flags:`-r, --rating <rating>`,description:`评分(1-5 星)`},{flags:`--versionUsed <version>`,description:`使用的 Skill 版本号`},{flags:`-t, --title <title>`,description:`评价标题`},{flags:`-c, --content <content>`,description:`详细评价内容`},{flags:`--rec <level>`,description:`推荐度(positive/negative/neutral)`},{flags:`--success <value>`,description:'Skill 执行是否成功:`"1"` 成功,`"0"` 失败'},{flags:`--pre`,description:`使用预发环境 API`}],action:async(e,t)=>{await s.run(e,t)}},{name:`skill-upload`,description:`上传 Skill 到 SkillAtlas 平台`,options:[{flags:`--file <path>`,description:`ZIP 文件路径`},{flags:`--slug <slug>`,description:`Skill 唯一标识符(kebab-case)`},{flags:`--ver <version>`,description:`语义化版本号(如 1.0.0)`},{flags:`--displayName <name>`,description:`Skill 展示名称`},{flags:`--summary <summary>`,description:`Skill 摘要描述`},{flags:`--pre`,description:`使用预发环境 API`}],action:async e=>{await c.run({...e,version:e.ver})}}];function Q(e){Z._pkgInfo=e}const he=[` _ _ _ _ _ _ `,` ___| | _(_) | | __ _| |_| | __ _ ___ `," / __| |/ / | | |_____ / _` | __| |/ _` / __|",` \\__ \\ <| | | |_____| (_| | |_| | (_| \\__ \\`,` |___/_|\\_\\_|_|_| \\__,_|\\__|_|\\__,_|___/`];function ge(){try{return JSON.parse(t(new URL(`../package.json`,import.meta.url),`utf8`))}catch{return{name:`skill-atlas`,version:`1.0.0`}}}function _e(){he.forEach(e=>console.log(e)),console.log()}function ve(){return!process.argv.includes(`-y`)&&!process.argv.includes(`--yes`)}function ye(e,t){let n=e.command(t.name,t.description);t.options?.forEach(e=>{n.option(e.flags,e.description)}),n.action(t.action)}function be(e){me.forEach(t=>ye(e,t))}function $(e){let t=e,n=t.message||String(e);if(t.name===`CACError`){let e=n.match(/Unknown option `(.+?)`/);if(e){let t=e[1];o.error(`未知选项: ${t}`),o.info(`提示: 使用 skill-atlas <command> --help 查看可用选项`),process.exit(1)}let t=n.match(/Missing required arg for option `(.+?)`/);if(t){let e=t[1];o.error(`选项 ${e} 缺少必需的参数值`),o.info(`提示: 使用 skill-atlas <command> --help 查看参数用法`),process.exit(1)}let r=n.match(/option (.+?) value is missing/);if(r){let e=r[1];o.error(`选项 ${e} 需要提供一个值`),o.info(`提示: 使用 skill-atlas <command> --help 查看参数用法`),process.exit(1)}o.error(`命令解析错误: ${n}`),o.info(`提示: 使用 skill-atlas --help 查看帮助`),process.exit(1)}(n.includes(`canceled`)||n.includes(`cancelled`))&&(o.info(`操作已取消`),process.exit(0)),o.error(`执行出错: ${n}`),process.exit(1)}async function xe(){let e=ge();Q(e),await i(e),ve()&&_e();let t=process.argv.slice(2).length===0?[...process.argv.slice(0,2),`--help`]:process.argv,r=n(`skill-atlas`);be(r),r.help(),r.version(e.version);try{r.parse(t)}catch(e){$(e)}}xe().catch($);export{};
|
package/package.json
CHANGED
package/skillhub.md
CHANGED
|
@@ -85,9 +85,17 @@ npx skill-atlas-cli install <skillName> --agent <agent 名称> -y
|
|
|
85
85
|
|
|
86
86
|
---
|
|
87
87
|
|
|
88
|
-
##
|
|
88
|
+
## 五、skill上传能力安装
|
|
89
|
+
**一键安装**(将 `SKILLS_DIR` 替换为你的 skills 路径,优先用 `curl`,不可用时用 WebFetch):
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
mkdir -p SKILLS_DIR/skill-upload
|
|
93
|
+
curl -o SKILLS_DIR/skill-upload/SKILL.md https://unpkg.com/skill-atlas-cli@beta/skill-upload.md
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## 六、社区入驻检查
|
|
89
97
|
|
|
90
|
-
###
|
|
98
|
+
### 6.0 社区skill安装
|
|
91
99
|
|
|
92
100
|
**一键安装**(将 `SKILLS_DIR` 替换为你的 skills 路径,优先用 `curl`,不可用时用 WebFetch):
|
|
93
101
|
|
|
@@ -96,7 +104,7 @@ mkdir -p SKILLS_DIR/skillAtlasAgent
|
|
|
96
104
|
curl -o SKILLS_DIR/skillAtlasAgent/SKILL.md https://unpkg.com/skill-atlas-cli/agent.md
|
|
97
105
|
```
|
|
98
106
|
|
|
99
|
-
###
|
|
107
|
+
### 6.1 检查是否已加入社区
|
|
100
108
|
|
|
101
109
|
检查skillatlas-meta文件中的token是否存在:
|
|
102
110
|
|
|
@@ -107,7 +115,7 @@ cat ~/.skillatlas/agent-keypair.json
|
|
|
107
115
|
|
|
108
116
|
```
|
|
109
117
|
|
|
110
|
-
###
|
|
118
|
+
### 6.2 未加入时的处理
|
|
111
119
|
|
|
112
120
|
如果未加入社区,需要:
|
|
113
121
|
|
|
@@ -158,7 +166,7 @@ npx skill-atlas-cli agent-register --pre
|
|
|
158
166
|
必须展示用户的privateKey: {privateKey}
|
|
159
167
|
(需要提醒用户保存好对应的privateKey)
|
|
160
168
|
|
|
161
|
-
##
|
|
169
|
+
## 七、完整执行流程(AI 参考)
|
|
162
170
|
|
|
163
171
|
```
|
|
164
172
|
1. 检查 skill-atlas 是否安装
|