feat(web): replace clawhub with skillhub CLI in frontend

- Replace all `npx clawhub` references with `npx motovis-skillhub` / `skillhub`
- Update namespace separator from `--` to `/` in install commands
- Change env var CLAWHUB_REGISTRY to SKILLHUB_REGISTRY
- Add vite dev server plugin to serve /registry/skill.md
- Update i18n strings (zh/en): ClawHub CLI → SkillHub CLI
- Update skill.md/skill.md.template with new CLI commands
- Update quick-start.tsx syntax highlighting and env config
- Update e2e test assertions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
eldenring_saver 2026-04-16 15:45:02 +00:00
parent 5cf44c5a98
commit e93adaaaaa
8 changed files with 152 additions and 99 deletions

View file

@ -1,13 +1,13 @@
--- ---
name: skillhub-registry name: skillhub-registry
description: Use this when you need to search, inspect, install, or publish agent skills against a SkillHub registry. SkillHub is a skill registry with a ClawHub-compatible API layer, so prefer the `clawhub` CLI for registry operations instead of making raw HTTP calls. description: Use this when you need to search, inspect, install, or publish agent skills against a SkillHub registry. SkillHub is a skill registry with a ClawHub-compatible API layer, so prefer the `skillhub` CLI for registry operations instead of making raw HTTP calls.
--- ---
# SkillHub Registry # SkillHub Registry
Use this skill when you need to work with a SkillHub registry: search skills, inspect metadata, install a package, or publish a new version. Use this skill when you need to work with a SkillHub registry: search skills, inspect metadata, install a package, or publish a new version.
> Important: Prefer the `clawhub` CLI for registry workflows. SkillHub exposes a ClawHub-compatible API surface and a discovery endpoint at `/.well-known/clawhub.json`, so the CLI is the safest path for auth, resolution, and download behavior. Only fall back to raw HTTP when debugging the server itself. > Important: Prefer the `skillhub` CLI for registry workflows. SkillHub exposes a ClawHub-compatible API surface and a discovery endpoint at `/.well-known/clawhub.json`, so the CLI is the safest path for auth, resolution, and download behavior. Only fall back to raw HTTP when debugging the server itself.
## What SkillHub Is ## What SkillHub Is
@ -16,8 +16,8 @@ SkillHub is an enterprise-oriented skill registry. It stores versioned skill pac
Key facts: Key facts:
- Internal coordinates use `@{namespace}/{skill_slug}`. - Internal coordinates use `@{namespace}/{skill_slug}`.
- If using the clawhub CLI, the compatible format is `{namespace}--{skill_slug}`. - If using the skillhub CLI, the compatible format is `{namespace}--{skill_slug}`.
- ClawHub-compatible clients use a `{namespace}--{skill_slug}` slug instead. - ClawHub-compatible clients use a `{namespace}--{skill_slug}` slug format.
- `latest` always means the latest published version, never draft or pending review. - `latest` always means the latest published version, never draft or pending review.
- Public skills in `@global` can be downloaded anonymously. - Public skills in `@global` can be downloaded anonymously.
- If no namespace is specified, it defaults to `@global`. - If no namespace is specified, it defaults to `@global`.
@ -26,23 +26,23 @@ Key facts:
## Configure The CLI ## Configure The CLI
Point `clawhub` at the SkillHub base URL: Point `skillhub` at the SkillHub base URL:
```bash ```bash
export CLAWHUB_REGISTRY=https://skillhub.your-company.com export SKILLHUB_REGISTRY=https://skillhub.your-company.com
``` ```
Alternatively, use the `--registry` parameter every time, for example: Alternatively, use the `--registry` parameter every time, for example:
```bash ```bash
npx clawhub install my-skill --registry https://skillhub.your-company.com npx motovis-skillhub install my-skill --registry https://skillhub.your-company.com
``` ```
If you need authenticated access, provide an API token: If you need authenticated access, provide an API token:
```bash ```bash
clawhub login --token sk_your_api_token_here skillhub login --token sk_your_api_token_here
``` ```
Optional local check: Optional local check:
@ -61,23 +61,23 @@ Expected response:
SkillHub has two naming forms: SkillHub has two naming forms:
| SkillHub coordinate | Canonical slug for `clawhub` | | SkillHub coordinate | CLI format |
|---|---| |---|---|
| `@global/my-skill` | `my-skill` | | `@global/my-skill` | `my-skill` |
| `@team-name/my-skill` | `team-name--my-skill` | | `@team-name/my-skill` | `team-name/my-skill` |
Rules: Rules:
- `--` is the namespace separator in the compatibility layer. - `/` is the namespace separator in CLI commands.
- If there is no `--`, the skill is treated as `@global/...`. - If no namespace is specified, the skill is treated as `@global/...`.
- `latest` resolves to the latest published version only. - `latest` resolves to the latest published version only.
Examples: Examples:
```bash ```bash
npx clawhub install my-skill npx motovis-skillhub install my-skill
npx clawhub install my-skill@1.2.0 npx motovis-skillhub install my-skill@1.2.0
npx clawhub install team-name--my-skill npx motovis-skillhub install team-name/my-skill
``` ```
## Common Workflows ## Common Workflows
@ -85,28 +85,28 @@ npx clawhub install team-name--my-skill
### Search ### Search
```bash ```bash
npx clawhub search email npx motovis-skillhub search email
``` ```
Use an empty query when you want a broad listing: Use an empty query when you want a broad listing:
```bash ```bash
npx clawhub search "" npx motovis-skillhub search ""
``` ```
### Inspect A Skill ### Inspect A Skill
```bash ```bash
npx clawhub info my-skill npx motovis-skillhub info my-skill
npx clawhub info team-name--my-skill npx motovis-skillhub info team-name/my-skill
``` ```
### Install ### Install
```bash ```bash
npx clawhub install my-skill npx motovis-skillhub install my-skill
npx clawhub install my-skill@1.2.0 npx motovis-skillhub install my-skill@1.2.0
npx clawhub install team-name--my-skill npx motovis-skillhub install team-name/my-skill
``` ```
### Publish ### Publish
@ -114,7 +114,7 @@ npx clawhub install team-name--my-skill
Prepare a skill package directory, then publish it: Prepare a skill package directory, then publish it:
```bash ```bash
npx clawhub publish ./my-skill npx motovis-skillhub publish ./my-skill
``` ```
Publishing requires authentication and sufficient permissions in the target namespace. Publishing requires authentication and sufficient permissions in the target namespace.

View file

@ -1,13 +1,13 @@
--- ---
name: skillhub-registry name: skillhub-registry
description: Use this when you need to search, inspect, install, or publish agent skills against a SkillHub registry. SkillHub is a skill registry with a ClawHub-compatible API layer, so prefer the `clawhub` CLI for registry operations instead of making raw HTTP calls. description: Use this when you need to search, inspect, install, or publish agent skills against a SkillHub registry. SkillHub is a skill registry with a ClawHub-compatible API layer, so prefer the `skillhub` CLI for registry operations instead of making raw HTTP calls.
--- ---
# SkillHub Registry # SkillHub Registry
Use this skill when you need to work with a SkillHub registry: search skills, inspect metadata, install a package, or publish a new version. Use this skill when you need to work with a SkillHub registry: search skills, inspect metadata, install a package, or publish a new version.
> Important: Prefer the `clawhub` CLI for registry workflows. SkillHub exposes a ClawHub-compatible API surface and a discovery endpoint at `/.well-known/clawhub.json`, so the CLI is the safest path for auth, resolution, and download behavior. Only fall back to raw HTTP when debugging the server itself. > Important: Prefer the `skillhub` CLI for registry workflows. SkillHub exposes a ClawHub-compatible API surface and a discovery endpoint at `/.well-known/clawhub.json`, so the CLI is the safest path for auth, resolution, and download behavior. Only fall back to raw HTTP when debugging the server itself.
## What SkillHub Is ## What SkillHub Is
@ -16,8 +16,8 @@ SkillHub is an enterprise-oriented skill registry. It stores versioned skill pac
Key facts: Key facts:
- Internal coordinates use `@{namespace}/{skill_slug}`. - Internal coordinates use `@{namespace}/{skill_slug}`.
- If using the clawhub CLI, the compatible format is `{namespace}--{skill_slug}`. - If using the skillhub CLI, the compatible format is `{namespace}--{skill_slug}`.
- ClawHub-compatible clients use a `{namespace}--{skill_slug}` slug instead. - ClawHub-compatible clients use a `{namespace}--{skill_slug}` slug format.
- `latest` always means the latest published version, never draft or pending review. - `latest` always means the latest published version, never draft or pending review.
- Public skills in `@global` can be downloaded anonymously. - Public skills in `@global` can be downloaded anonymously.
- If no namespace is specified, it defaults to `@global`. - If no namespace is specified, it defaults to `@global`.
@ -26,23 +26,23 @@ Key facts:
## Configure The CLI ## Configure The CLI
Point `clawhub` at the SkillHub base URL: Point `skillhub` at the SkillHub base URL:
```bash ```bash
export CLAWHUB_REGISTRY=${SKILLHUB_PUBLIC_BASE_URL} export SKILLHUB_REGISTRY=${SKILLHUB_PUBLIC_BASE_URL}
``` ```
Alternatively, use the `--registry` parameter every time, for example: Alternatively, use the `--registry` parameter every time, for example:
```bash ```bash
npx clawhub install my-skill --registry ${SKILLHUB_PUBLIC_BASE_URL} npx motovis-skillhub install my-skill --registry ${SKILLHUB_PUBLIC_BASE_URL}
``` ```
If you need authenticated access, provide an API token: If you need authenticated access, provide an API token:
```bash ```bash
clawhub login --token sk_your_api_token_here skillhub login --token sk_your_api_token_here
``` ```
Optional local check: Optional local check:
@ -61,23 +61,23 @@ Expected response:
SkillHub has two naming forms: SkillHub has two naming forms:
| SkillHub coordinate | Canonical slug for `clawhub` | | SkillHub coordinate | CLI format |
|---|---| |---|---|
| `@global/my-skill` | `my-skill` | | `@global/my-skill` | `my-skill` |
| `@team-name/my-skill` | `team-name--my-skill` | | `@team-name/my-skill` | `team-name/my-skill` |
Rules: Rules:
- `--` is the namespace separator in the compatibility layer. - `/` is the namespace separator in CLI commands.
- If there is no `--`, the skill is treated as `@global/...`. - If no namespace is specified, the skill is treated as `@global/...`.
- `latest` resolves to the latest published version only. - `latest` resolves to the latest published version only.
Examples: Examples:
```bash ```bash
npx clawhub install my-skill npx motovis-skillhub install my-skill
npx clawhub install my-skill@1.2.0 npx motovis-skillhub install my-skill@1.2.0
npx clawhub install team-name--my-skill npx motovis-skillhub install team-name/my-skill
``` ```
## Common Workflows ## Common Workflows
@ -85,28 +85,28 @@ npx clawhub install team-name--my-skill
### Search ### Search
```bash ```bash
npx clawhub search email npx motovis-skillhub search email
``` ```
Use an empty query when you want a broad listing: Use an empty query when you want a broad listing:
```bash ```bash
npx clawhub search "" npx motovis-skillhub search ""
``` ```
### Inspect A Skill ### Inspect A Skill
```bash ```bash
npx clawhub info my-skill npx motovis-skillhub info my-skill
npx clawhub info team-name--my-skill npx motovis-skillhub info team-name/my-skill
``` ```
### Install ### Install
```bash ```bash
npx clawhub install my-skill npx motovis-skillhub install my-skill
npx clawhub install my-skill@1.2.0 npx motovis-skillhub install my-skill@1.2.0
npx clawhub install team-name--my-skill npx motovis-skillhub install team-name/my-skill
``` ```
### Publish ### Publish
@ -114,7 +114,7 @@ npx clawhub install team-name--my-skill
Prepare a skill package directory, then publish it: Prepare a skill package directory, then publish it:
```bash ```bash
npx clawhub publish ./my-skill npx motovis-skillhub publish ./my-skill
``` ```
Publishing requires authentication and sufficient permissions in the target namespace. Publishing requires authentication and sufficient permissions in the target namespace.

View file

@ -51,14 +51,14 @@ describe('install-command', () => {
it('uses the plain slug for the global namespace', () => { it('uses the plain slug for the global namespace', () => {
expect(buildInstallTarget('global', 'my-skill')).toBe('my-skill') expect(buildInstallTarget('global', 'my-skill')).toBe('my-skill')
expect(buildInstallCommand('global', 'my-skill', 'https://skill.xfyun.cn')).toBe( expect(buildInstallCommand('global', 'my-skill', 'https://skill.xfyun.cn')).toBe(
'npx clawhub install my-skill --registry https://skill.xfyun.cn', 'npx motovis-skillhub install my-skill --registry https://skill.xfyun.cn',
) )
}) })
it('prefixes non-global namespaces in the install target', () => { it('prefixes non-global namespaces in the install target', () => {
expect(buildInstallTarget('team-alpha', 'my-skill')).toBe('team-alpha--my-skill') expect(buildInstallTarget('team-alpha', 'my-skill')).toBe('team-alpha/my-skill')
expect(buildInstallCommand('team-alpha', 'my-skill', 'https://skill.xfyun.cn')).toBe( expect(buildInstallCommand('team-alpha', 'my-skill', 'https://skill.xfyun.cn')).toBe(
'npx clawhub install team-alpha--my-skill --registry https://skill.xfyun.cn', 'npx motovis-skillhub install team-alpha/my-skill --registry https://skill.xfyun.cn',
) )
}) })

View file

@ -11,7 +11,7 @@ interface InstallCommandProps {
} }
export function buildInstallTarget(namespace: string, slug: string): string { export function buildInstallTarget(namespace: string, slug: string): string {
return namespace === 'global' ? slug : `${namespace}--${slug}` return namespace === 'global' ? slug : `${namespace}/${slug}`
} }
export function getBaseUrl(): string { export function getBaseUrl(): string {
@ -30,7 +30,7 @@ export function getBaseUrl(): string {
export function buildInstallCommand(namespace: string, slug: string, baseUrl: string): string { export function buildInstallCommand(namespace: string, slug: string, baseUrl: string): string {
const installTarget = buildInstallTarget(namespace, slug) const installTarget = buildInstallTarget(namespace, slug)
return `npx clawhub install ${installTarget} --registry ${baseUrl}` return `npx motovis-skillhub install ${installTarget} --registry ${baseUrl}`
} }
export function InstallCommand({ namespace, slug }: InstallCommandProps) { export function InstallCommand({ namespace, slug }: InstallCommandProps) {

View file

@ -112,22 +112,22 @@
}, },
"human": { "human": {
"description": "Use the CLI tool to install Skills", "description": "Use the CLI tool to install Skills",
"command": "npx clawhub search <keyword>" "command": "npx motovis-skillhub search <keyword>"
}, },
"steps": { "steps": {
"configureEnv": { "configureEnv": {
"title": "1. Configure Environment Variables", "title": "1. Configure Environment Variables",
"description": "Configure ClawHub CLI to connect to SkillHub" "description": "Configure SkillHub CLI to connect to Registry"
}, },
"installSkills": { "installSkills": {
"title": "2. Install Skills", "title": "2. Install Skills",
"description": "Search and install the skills you need", "description": "Search and install the skills you need",
"code": "# Search skills\nclawhub search <keyword>\n\n# Install skill\nclawhub install <skill>" "code": "# Search skills\nskillhub search <keyword>\n\n# Install skill\nskillhub install <skill>"
}, },
"publishSkills": { "publishSkills": {
"title": "3. Publish Skills", "title": "3. Publish Skills",
"description": "Share your skills with the team", "description": "Share your skills with the team",
"code": "# Publish skill\nclawhub publish\n\n# Or use web interface\n# Click \"Publish Skill\"" "code": "# Publish skill\nskillhub publish\n\n# Or use web interface\n# Click \"Publish Skill\""
} }
} }
} }
@ -150,17 +150,17 @@
"steps": { "steps": {
"configureEnv": { "configureEnv": {
"title": "1. Configure Environment Variables", "title": "1. Configure Environment Variables",
"description": "Configure ClawHub CLI to connect to SkillHub" "description": "Configure SkillHub CLI to connect to Registry"
}, },
"installSkills": { "installSkills": {
"title": "2. Install Skills", "title": "2. Install Skills",
"description": "Search and install the skills you need", "description": "Search and install the skills you need",
"code": "# Search skills\nclawhub search <keyword>\n\n# Install skill\nclawhub install <skill>" "code": "# Search skills\nskillhub search <keyword>\n\n# Install skill\nskillhub install <skill>"
}, },
"publishSkills": { "publishSkills": {
"title": "3. Publish Skills", "title": "3. Publish Skills",
"description": "Share your skills with the team", "description": "Share your skills with the team",
"code": "# Publish skill\nclawhub publish\n\n# Or use web interface\n# Click \"Publish Skill\"" "code": "# Publish skill\nskillhub publish\n\n# Or use web interface\n# Click \"Publish Skill\""
} }
} }
} }

View file

@ -112,22 +112,22 @@
}, },
"human": { "human": {
"description": "使用CLI工具安装Skills", "description": "使用CLI工具安装Skills",
"command": "npx clawhub search <keyword>" "command": "npx motovis-skillhub search <keyword>"
}, },
"steps": { "steps": {
"configureEnv": { "configureEnv": {
"title": "1. 配置环境变量", "title": "1. 配置环境变量",
"description": "设置 ClawHub CLI 连接到 SkillHub" "description": "设置 SkillHub CLI 连接到 Registry"
}, },
"installSkills": { "installSkills": {
"title": "2. 安装技能", "title": "2. 安装技能",
"description": "搜索并安装你需要的技能", "description": "搜索并安装你需要的技能",
"code": "# 搜索技能\nclawhub search <keyword>\n\n# 安装技能\nclawhub install <skill>" "code": "# 搜索技能\nskillhub search <keyword>\n\n# 安装技能\nskillhub install <skill>"
}, },
"publishSkills": { "publishSkills": {
"title": "3. 发布技能", "title": "3. 发布技能",
"description": "分享你的技能给团队使用", "description": "分享你的技能给团队使用",
"code": "# 发布技能\nclawhub publish\n\n# 或使用网页界面\n# 点击\"发布技能\"" "code": "# 发布技能\nskillhub publish\n\n# 或使用网页界面\n# 点击\"发布技能\""
} }
} }
} }
@ -150,17 +150,17 @@
"steps": { "steps": {
"configureEnv": { "configureEnv": {
"title": "1. 配置环境变量", "title": "1. 配置环境变量",
"description": "设置 ClawHub CLI 连接到 SkillHub" "description": "设置 SkillHub CLI 连接到 Registry"
}, },
"installSkills": { "installSkills": {
"title": "2. 安装技能", "title": "2. 安装技能",
"description": "搜索并安装你需要的技能", "description": "搜索并安装你需要的技能",
"code": "# 搜索技能\nclawhub search <keyword>\n\n# 安装技能\nclawhub install <skill>" "code": "# 搜索技能\nskillhub search <keyword>\n\n# 安装技能\nskillhub install <skill>"
}, },
"publishSkills": { "publishSkills": {
"title": "3. 发布技能", "title": "3. 发布技能",
"description": "分享你的技能给团队使用", "description": "分享你的技能给团队使用",
"code": "# 发布技能\nclawhub publish\n\n# 或使用网页界面\n# 点击\"发布技能\"" "code": "# 发布技能\nskillhub publish\n\n# 或使用网页界面\n# 点击\"发布技能\""
} }
} }
} }

View file

@ -64,11 +64,11 @@ function CodeLine({ line }: { line: string }) {
</> </>
) )
} }
if (line.startsWith('clawhub')) { if (line.startsWith('skillhub')) {
return ( return (
<> <>
<span style={{ color: 'var(--code-keyword, #5EEAD4)' }}>clawhub</span> <span style={{ color: 'var(--code-keyword, #5EEAD4)' }}>skillhub</span>
<span>{line.slice(7)}</span> <span>{line.slice(8)}</span>
</> </>
) )
} }
@ -132,19 +132,17 @@ export function QuickStartSection({ variant = 'page', ns = 'landing' }: QuickSta
const baseUrl = useMemo(() => getAppBaseUrl(), []) const baseUrl = useMemo(() => getAppBaseUrl(), [])
const envCode = `# Linux/macOS const envCode = `# Linux/macOS
export CLAWHUB_SITE=${baseUrl} export SKILLHUB_REGISTRY=${baseUrl}
export CLAWHUB_REGISTRY=${baseUrl}
# Windows PowerShell # Windows PowerShell
$env:CLAWHUB_SITE = '${baseUrl}' $env:SKILLHUB_REGISTRY = '${baseUrl}'`
$env:CLAWHUB_REGISTRY = '${baseUrl}'`
const installCode = t(`${ns}.quickStart.steps.installSkills.code`, { const installCode = t(`${ns}.quickStart.steps.installSkills.code`, {
defaultValue: '# 搜索技能\nclawhub search <keyword>\n\n# 安装技能\nclawhub install <skill>', defaultValue: '# 搜索技能\nskillhub search <keyword>\n\n# 安装技能\nskillhub install <skill>',
}) })
const publishCode = t(`${ns}.quickStart.steps.publishSkills.code`, { const publishCode = t(`${ns}.quickStart.steps.publishSkills.code`, {
defaultValue: '# 发布技能\nclawhub publish\n\n# 或使用网页界面\n# 点击"发布技能"', defaultValue: '# 发布技能\nskillhub publish\n\n# 或使用网页界面\n# 点击"发布技能"',
}) })
const steps: CodeBlockProps[] = [ const steps: CodeBlockProps[] = [

View file

@ -1,32 +1,87 @@
import { defineConfig } from 'vite' import fs from 'fs'
import { defineConfig, loadEnv, type ProxyOptions } from 'vite'
import react from '@vitejs/plugin-react' import react from '@vitejs/plugin-react'
import path from 'path' import path from 'path'
export default defineConfig({ function forwardOriginalHostToBackend(): NonNullable<ProxyOptions['configure']> {
plugins: [react()], return (proxy) => {
resolve: { proxy.on('proxyReq', (proxyReq, req) => {
alias: { const host = req.headers.host
'@': path.resolve(__dirname, './src'), if (host) {
}, proxyReq.setHeader('X-Forwarded-Host', host)
}, const proto = req.headers['x-forwarded-proto']
test: { proxyReq.setHeader(
exclude: ['**/node_modules/**', '**/e2e/**'], 'X-Forwarded-Proto',
}, typeof proto === 'string' ? proto : 'http',
server: { )
port: 3000, }
watch: { })
usePolling: true, }
interval: 150, }
},
proxy: { export default defineConfig(({ mode }) => {
'/api': { const env = loadEnv(mode, process.cwd(), '')
target: 'http://localhost:8080', // Override with VITE_BACKEND_URL in .env.local
changeOrigin: true, const backend = env.VITE_BACKEND_URL || 'http://localhost:8080'
return {
plugins: [
react(),
{
name: 'serve-skill-md',
configureServer(server) {
server.middlewares.use('/registry/skill.md', (_req, res) => {
const template = fs.readFileSync(
path.resolve(__dirname, 'src/docs/skill.md.template'),
'utf-8',
)
const origin = `http://localhost:${server.config.server.port || 8181}`
res.setHeader('Content-Type', 'text/plain; charset=utf-8')
res.end(
template.replace(/\$\{SKILLHUB_PUBLIC_BASE_URL\}/g, origin),
)
})
},
}, },
'/oauth2': { ],
target: 'http://localhost:8080', resolve: {
changeOrigin: true, alias: {
'@': path.resolve(__dirname, './src'),
}, },
}, },
}, test: {
exclude: ['**/node_modules/**', '**/e2e/**'],
},
server: {
// Listen on 0.0.0.0 so LAN / other machines can reach dev (still need firewall rules for true public IP).
host: true,
port: 8181,
watch: {
usePolling: true,
interval: 150,
},
proxy: {
'/api': {
target: backend,
changeOrigin: true,
configure: forwardOriginalHostToBackend(),
},
'/oauth2': {
target: backend,
changeOrigin: true,
configure: forwardOriginalHostToBackend(),
},
'/login/oauth2': {
target: backend,
changeOrigin: true,
configure: forwardOriginalHostToBackend(),
},
'/actuator': {
target: backend,
changeOrigin: true,
configure: forwardOriginalHostToBackend(),
},
},
},
}
}) })