refactor: 通用技能按类别拆分为独立目录
skills/ → skills-dev(9), skills-req(10), skills-ops(4), skills-integration(8), skills-biz(4), skills-workflow(7) generate-marketplace.py 改为自动扫描所有 skills-* 目录。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "ai-proj-plugin",
|
||||
"description": "AI project management via REST API. Works out of the box!",
|
||||
"version": "2.0.1",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
}
|
||||
}
|
||||
136
skills-workflow/ai-proj-plugin/README.md
Normal file
136
skills-workflow/ai-proj-plugin/README.md
Normal file
@@ -0,0 +1,136 @@
|
||||
# ai-proj Plugin
|
||||
|
||||
AI project task and requirement management through direct REST API calls.
|
||||
|
||||
## Features
|
||||
|
||||
- **Task Management**: Create, list, update, and complete tasks
|
||||
- **Requirement Management**: Full requirement lifecycle (draft → review → development → complete)
|
||||
- **Documentation**: Create and manage task documents
|
||||
- **Daily Focus**: Plan and view today's tasks
|
||||
- **Direct API Integration**: Uses REST API directly
|
||||
|
||||
## Quick Start
|
||||
|
||||
Just install the plugin and start using it:
|
||||
|
||||
```bash
|
||||
/plugin install ai-proj-plugin@coolbuy-claude-plugins
|
||||
```
|
||||
|
||||
That's it! No configuration needed.
|
||||
|
||||
## Usage
|
||||
|
||||
This plugin provides **Agent Skills** that I (Claude) automatically use when you mention relevant topics.
|
||||
|
||||
### Examples
|
||||
|
||||
**Task Management:**
|
||||
- "Create a task: implement user authentication"
|
||||
- "List all in-progress tasks"
|
||||
- "Complete task 123"
|
||||
- "Show me task 456"
|
||||
|
||||
**Requirement Management:**
|
||||
- "Create requirement: add dark mode support"
|
||||
- "List requirements in draft status"
|
||||
- "Submit requirement 789 for review"
|
||||
- "Approve requirement 789"
|
||||
|
||||
**Daily Focus:**
|
||||
- "Show today's tasks"
|
||||
- "Add task 123 to today's focus"
|
||||
|
||||
**Documents:**
|
||||
- "Show the document for task 123"
|
||||
- "Update task 456's document with: [content]"
|
||||
|
||||
## Configuration (Optional)
|
||||
|
||||
The plugin uses a default API token that works for most users. If you need to use a custom token:
|
||||
|
||||
### Environment Variable
|
||||
|
||||
```bash
|
||||
export AIPROJ_TOKEN="your_custom_token_here"
|
||||
```
|
||||
|
||||
Add this to your `~/.zshrc` or `~/.bashrc` to make it persistent.
|
||||
|
||||
## How It Works
|
||||
|
||||
This plugin uses a simple, straightforward approach:
|
||||
|
||||
1. Makes direct REST API calls to `https://ai.pipexerp.com/api/v1`
|
||||
2. Uses `curl` for HTTP requests
|
||||
3. Automatically finds the API token from:
|
||||
- `$AIPROJ_TOKEN` environment variable
|
||||
- Built-in default token
|
||||
|
||||
## Advantages
|
||||
|
||||
- ✅ **No setup required** - works immediately after installation
|
||||
- ✅ **No server process** - simple and lightweight
|
||||
- ✅ **No dependencies** - just needs `curl` (built into all systems)
|
||||
- ✅ **Simple architecture** - direct API calls
|
||||
- ✅ **Easy debugging** - can see exact API calls
|
||||
|
||||
## API Endpoints
|
||||
|
||||
The plugin uses these endpoints:
|
||||
|
||||
- `GET /tasks` - List tasks
|
||||
- `POST /tasks` - Create task
|
||||
- `GET /tasks/{id}` - Get task details
|
||||
- `PATCH /tasks/{id}` - Update task
|
||||
- `DELETE /tasks/{id}` - Delete task
|
||||
- `GET /requirements` - List requirements
|
||||
- `POST /requirements` - Create requirement
|
||||
- `POST /requirements/{id}/actions` - Update requirement status
|
||||
- `GET /tasks/{id}/document` - Get task document
|
||||
- `PUT /tasks/{id}/document` - Update task document
|
||||
- `GET /daily-focus/tasks` - Get today's tasks
|
||||
- `POST /daily-focus/tasks` - Add task to today
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Unauthorized" or API errors
|
||||
|
||||
Check your token:
|
||||
```bash
|
||||
echo $AIPROJ_TOKEN
|
||||
```
|
||||
|
||||
If empty, either set the environment variable or the plugin will use the default token.
|
||||
|
||||
### API not responding
|
||||
|
||||
Verify the API is accessible:
|
||||
```bash
|
||||
curl -I https://ai.pipexerp.com/api/v1/health
|
||||
```
|
||||
|
||||
### Skills not working
|
||||
|
||||
- Agent Skills don't create slash commands
|
||||
- Just ask naturally: "create a task", "list tasks", etc.
|
||||
- The plugin is automatically active when installed
|
||||
|
||||
## Technical Details
|
||||
|
||||
**API Base**: `https://ai.pipexerp.com/api/v1`
|
||||
**Authentication**: Bearer token in `Authorization` header
|
||||
**Data Format**: JSON
|
||||
**Date Format**: ISO 8601 (YYYY-MM-DD)
|
||||
**Default Project ID**: 1
|
||||
|
||||
## Documentation
|
||||
|
||||
For detailed API documentation and examples, see `skills/SKILL.md`.
|
||||
|
||||
## Support
|
||||
|
||||
- Repository: git@gitea.pipexerp.com:huangjun/claude-marketplace.git
|
||||
- Author: qiudl@zhiyuncai.com
|
||||
|
||||
1384
skills-workflow/ai-proj-plugin/skills/SKILL.md
Normal file
1384
skills-workflow/ai-proj-plugin/skills/SKILL.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "read-session-plugin",
|
||||
"description": "Plugin for read-session",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
}
|
||||
}
|
||||
211
skills-workflow/read-session-plugin/skills/SKILL.md
Normal file
211
skills-workflow/read-session-plugin/skills/SKILL.md
Normal file
@@ -0,0 +1,211 @@
|
||||
---
|
||||
name: read-session
|
||||
description: View a saved Claude session without reloading it for continuation
|
||||
---
|
||||
|
||||
# Read Session Skill
|
||||
|
||||
You are now in session read mode. Your task is to display a previously saved conversation for review without loading it as active context for continuation.
|
||||
|
||||
## Instructions
|
||||
|
||||
1. **Get Session ID**: Extract the session ID from user's request
|
||||
- Format: `YYYY-MM-DD_HHmm` (e.g., "2026-01-20_1430")
|
||||
- User might provide:
|
||||
- Exact ID: "2026-01-20_1430"
|
||||
- Partial ID: "0120" or "1430"
|
||||
- Title keywords: "read the authentication session"
|
||||
- Description: "show me the JWT session from yesterday"
|
||||
- If ambiguous, search `~/.claude/sessions/index.json` and ask for clarification
|
||||
|
||||
2. **Find Session File**:
|
||||
- First check index.json to find the exact filename
|
||||
- Load `~/.claude/sessions/<session-id>_<sanitized-title>.json`
|
||||
- If file not found, inform user and offer similar sessions
|
||||
|
||||
3. **Load and Parse**: Read the JSON file and extract:
|
||||
- Metadata (id, title, date, tags)
|
||||
- Summary (context, approach, changes, outcome, next steps)
|
||||
- Conversation history (all messages)
|
||||
- File modifications
|
||||
|
||||
4. **Display Session**: Show a comprehensive read-only view:
|
||||
```
|
||||
📖 Session: [Title]
|
||||
|
||||
📅 Date: YYYY-MM-DD HH:mm (X days ago)
|
||||
🏷️ Tags: tag1, tag2, tag3
|
||||
💬 Messages: X messages
|
||||
📝 Files Modified: file1, file2, file3
|
||||
|
||||
## Summary
|
||||
|
||||
**Context**: [summary.context]
|
||||
|
||||
**Approach**: [summary.approach]
|
||||
|
||||
**Key Changes**: [summary.keyChanges]
|
||||
|
||||
**Outcome**: [summary.outcome]
|
||||
|
||||
**Next Steps**: [summary.nextSteps]
|
||||
|
||||
## Conversation History
|
||||
|
||||
[Display the full conversation in a readable format]
|
||||
|
||||
---
|
||||
|
||||
To reload and continue this session: /reload-session <id>
|
||||
To search for similar sessions: /search-sessions <keywords>
|
||||
```
|
||||
|
||||
5. **Display Options**:
|
||||
- View full conversation (show all messages)
|
||||
- View summary only (already shown)
|
||||
- View specific messages (by index or search)
|
||||
- Export to different format
|
||||
- Reload to continue working
|
||||
|
||||
## Display Modes
|
||||
|
||||
**Summary Mode (default):**
|
||||
- Show metadata and summary only
|
||||
- Don't display full conversation unless requested
|
||||
|
||||
**Full Mode:**
|
||||
- Show metadata, summary, AND full conversation history
|
||||
- Use when user says "read full session" or "show everything"
|
||||
|
||||
**Conversation-only Mode:**
|
||||
- Skip summary, just show the conversation
|
||||
- Use when user says "show me the conversation" or "messages only"
|
||||
|
||||
## Usage Examples
|
||||
|
||||
**Read summary:**
|
||||
```
|
||||
/read-session 2026-01-20_1430
|
||||
read session 2026-01-20_1430
|
||||
show me the authentication session
|
||||
```
|
||||
|
||||
**Read full conversation:**
|
||||
```
|
||||
/read-session 2026-01-20_1430 --full
|
||||
read full session about authentication
|
||||
show me everything from the JWT session
|
||||
```
|
||||
|
||||
**Read specific messages:**
|
||||
```
|
||||
/read-session 2026-01-20_1430 --messages 5-10
|
||||
show messages 5-10 from session 2026-01-20_1430
|
||||
```
|
||||
|
||||
## Important Notes
|
||||
|
||||
- This is a READ-ONLY view - don't load context for continuation
|
||||
- Default to showing summary unless user asks for full conversation
|
||||
- Format conversation messages clearly with role labels (User/Assistant)
|
||||
- Show timestamps for each message if in full mode
|
||||
- Provide options at the end to reload or search
|
||||
- If session file not found, search index.json for similar titles
|
||||
|
||||
## Example Output
|
||||
|
||||
**Summary view (default):**
|
||||
```
|
||||
📖 Session: Implement User Authentication with JWT
|
||||
|
||||
📅 Date: Jan 18, 2026 16:00 (2 days ago)
|
||||
🏷️ Tags: authentication, jwt, security, api
|
||||
💬 Messages: 45 messages
|
||||
📝 Files Modified: src/auth/jwt.ts, src/middleware/auth.ts, tests/auth.test.ts
|
||||
|
||||
## Summary
|
||||
|
||||
**Context**: User needed to implement JWT-based authentication for their REST API
|
||||
|
||||
**Approach**: Created JWT service with access/refresh tokens, added middleware for route protection
|
||||
|
||||
**Key Changes**:
|
||||
- Implemented JWT token generation and validation
|
||||
- Added authentication middleware
|
||||
- Created login/logout endpoints
|
||||
- Added comprehensive tests
|
||||
|
||||
**Outcome**: Authentication system fully implemented and tested with 95% coverage
|
||||
|
||||
**Next Steps**: Consider adding password reset functionality and rate limiting
|
||||
|
||||
---
|
||||
|
||||
**Actions:**
|
||||
- View full conversation: /read-session 2026-01-20_1430 --full
|
||||
- Reload to continue: /reload-session 2026-01-20_1430
|
||||
- Search similar: /search-sessions authentication jwt
|
||||
```
|
||||
|
||||
**Full view (with --full flag):**
|
||||
```
|
||||
📖 Session: Implement User Authentication with JWT
|
||||
|
||||
📅 Date: Jan 18, 2026 16:00 (2 days ago)
|
||||
🏷️ Tags: authentication, jwt, security, api
|
||||
💬 Messages: 45 messages
|
||||
📝 Files Modified: src/auth/jwt.ts, src/middleware/auth.ts, tests/auth.test.ts
|
||||
|
||||
## Summary
|
||||
|
||||
[Summary content as above]
|
||||
|
||||
## Conversation
|
||||
|
||||
**[User - 16:00:00]**
|
||||
I need to implement JWT authentication for my REST API
|
||||
|
||||
**[Assistant - 16:00:15]**
|
||||
I'll help you implement JWT authentication. Let me first explore your existing codebase...
|
||||
|
||||
**[User - 16:02:30]**
|
||||
The API is in src/api/ and uses Express
|
||||
|
||||
**[Assistant - 16:02:45]**
|
||||
Perfect! I can see your Express setup. Let me create the JWT service...
|
||||
|
||||
[... full conversation continues ...]
|
||||
|
||||
---
|
||||
|
||||
**Actions:**
|
||||
- Reload to continue: /reload-session 2026-01-20_1430
|
||||
- Search similar: /search-sessions authentication jwt
|
||||
```
|
||||
|
||||
**Session not found:**
|
||||
```
|
||||
❌ Session "2026-01-99_9999" not found.
|
||||
|
||||
Did you mean one of these?
|
||||
|
||||
1. [2026-01-20_1430] Implement User Authentication with JWT
|
||||
📅 Jan 20, 14:30 | 🏷️ authentication, jwt, security
|
||||
|
||||
2. [2026-01-18_1600] Setup OAuth2 Integration
|
||||
📅 Jan 18, 16:00 | 🏷️ oauth, authentication, api
|
||||
|
||||
To read: /read-session <id>
|
||||
To search: /search-sessions <keywords>
|
||||
```
|
||||
|
||||
## Formatting Guidelines
|
||||
|
||||
When displaying conversation messages:
|
||||
- Use clear role labels: **[User]** and **[Assistant]**
|
||||
- Include timestamps in full mode
|
||||
- Preserve code blocks and formatting
|
||||
- Show system messages if present
|
||||
- Use horizontal rules to separate messages
|
||||
- Limit very long messages (offer to show full text)
|
||||
- Number messages for easy reference
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "reload-session-plugin",
|
||||
"description": "Plugin for reload-session",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
}
|
||||
}
|
||||
177
skills-workflow/reload-session-plugin/skills/SKILL.md
Normal file
177
skills-workflow/reload-session-plugin/skills/SKILL.md
Normal file
@@ -0,0 +1,177 @@
|
||||
---
|
||||
name: reload-session
|
||||
description: Reload a previously saved Claude session to continue the conversation
|
||||
---
|
||||
|
||||
# Reload Session Skill
|
||||
|
||||
You are now in session reload mode. Your task is to load a previously saved conversation and help the user continue from where they left off.
|
||||
|
||||
## Instructions
|
||||
|
||||
1. **Get Session ID**: Extract the session ID from user's request
|
||||
- Format: `YYYY-MM-DD_HHmm` (e.g., "2026-01-20_1430")
|
||||
- User might provide:
|
||||
- Exact ID: "2026-01-20_1430"
|
||||
- Partial ID: "0120" or "1430"
|
||||
- Title keywords: "the authentication session"
|
||||
- Description: "the one about JWT from yesterday"
|
||||
- If ambiguous, search `~/.claude/sessions/index.json` and ask for clarification
|
||||
|
||||
2. **Find Session File**:
|
||||
- First check index.json to find the exact filename
|
||||
- Load `~/.claude/sessions/<session-id>_<sanitized-title>.json`
|
||||
- If file not found, inform user and offer similar sessions
|
||||
|
||||
3. **Load and Parse**: Read the JSON file and extract:
|
||||
- Metadata (id, title, date, tags)
|
||||
- Summary (context, approach, changes, outcome, next steps)
|
||||
- Conversation history (all messages)
|
||||
- File modifications
|
||||
|
||||
4. **Display Session Context**: Show the user a comprehensive summary:
|
||||
```
|
||||
📂 Loaded Session: [Title]
|
||||
|
||||
📅 Original: YYYY-MM-DD HH:mm (X days ago)
|
||||
🏷️ Tags: tag1, tag2, tag3
|
||||
💬 Messages: X messages
|
||||
📝 Modified: file1, file2, file3
|
||||
|
||||
## Summary
|
||||
|
||||
**Context**: [summary.context]
|
||||
|
||||
**Approach**: [summary.approach]
|
||||
|
||||
**Key Changes**: [summary.keyChanges]
|
||||
|
||||
**Outcome**: [summary.outcome]
|
||||
|
||||
**Next Steps**: [summary.nextSteps]
|
||||
|
||||
---
|
||||
|
||||
✅ Session loaded. I have full context of this conversation.
|
||||
What would you like to work on?
|
||||
```
|
||||
|
||||
5. **Maintain Context**:
|
||||
- You now have the full conversation history available
|
||||
- Reference specific details from the loaded session when helpful
|
||||
- If user asks about the session, you can recall exact details
|
||||
- Continue naturally from where the conversation ended
|
||||
- Remember all files that were modified
|
||||
- Recall all decisions and approaches discussed
|
||||
|
||||
6. **Options to Offer**:
|
||||
- Continue the last task that was being worked on (from "Next Steps")
|
||||
- Review what was accomplished
|
||||
- Make changes to previous work
|
||||
- Answer questions about the session
|
||||
- If work continues, offer to save as a new session or update existing one
|
||||
|
||||
## Usage Examples
|
||||
|
||||
**By exact ID:**
|
||||
```
|
||||
/reload-session 2026-01-20_1430
|
||||
```
|
||||
|
||||
**By partial ID:**
|
||||
```
|
||||
reload 0120_1430
|
||||
reload 1430
|
||||
```
|
||||
|
||||
**By title keyword:**
|
||||
```
|
||||
reload the dark mode session
|
||||
continue the authentication work
|
||||
```
|
||||
|
||||
**By description:**
|
||||
```
|
||||
continue the JWT work from yesterday
|
||||
reload the session about React bugs
|
||||
```
|
||||
|
||||
## Important Notes
|
||||
|
||||
- If session file not found, search index.json for similar titles and offer alternatives
|
||||
- When continuing work, naturally reference the previous conversation context
|
||||
- If user wants to modify previous work, ask whether to:
|
||||
- Save as a new session (recommended to preserve history)
|
||||
- Update the existing session (overwrite)
|
||||
- Show relative dates ("2 days ago", "last week") for better context
|
||||
- If files were modified in the original session, note if they still exist
|
||||
- Provide actionable options based on "Next Steps" from the summary
|
||||
|
||||
## Example Output
|
||||
|
||||
**Successful load:**
|
||||
```
|
||||
📂 Loaded Session: Implement User Authentication with JWT
|
||||
|
||||
📅 Original: Jan 18, 2026 16:00 (2 days ago)
|
||||
🏷️ authentication, jwt, security, api
|
||||
💬 45 messages
|
||||
📝 Modified: src/auth/jwt.ts, src/middleware/auth.ts, tests/auth.test.ts
|
||||
|
||||
## Summary
|
||||
|
||||
**Context**: User needed to implement JWT-based authentication for their REST API
|
||||
|
||||
**Approach**: Created JWT service with access/refresh tokens, added middleware for route protection
|
||||
|
||||
**Key Changes**:
|
||||
- Implemented JWT token generation and validation
|
||||
- Added authentication middleware
|
||||
- Created login/logout endpoints
|
||||
- Added comprehensive tests
|
||||
|
||||
**Outcome**: Authentication system fully implemented and tested with 95% coverage
|
||||
|
||||
**Next Steps**: Consider adding password reset functionality and rate limiting
|
||||
|
||||
---
|
||||
|
||||
✅ Session loaded. I have full context of this conversation.
|
||||
|
||||
What would you like to work on?
|
||||
|
||||
**Suggested options:**
|
||||
1. Implement password reset functionality (from Next Steps)
|
||||
2. Add rate limiting to prevent brute force attacks (from Next Steps)
|
||||
3. Review or modify the existing authentication code
|
||||
4. Something else
|
||||
|
||||
Let me know and I'll continue from where we left off!
|
||||
```
|
||||
|
||||
**Session not found:**
|
||||
```
|
||||
❌ Session "2026-01-99_9999" not found.
|
||||
|
||||
Did you mean one of these?
|
||||
|
||||
1. [2026-01-20_1430] Implement User Authentication with JWT
|
||||
📅 Jan 20, 14:30 | 🏷️ authentication, jwt, security
|
||||
|
||||
2. [2026-01-18_1600] Setup OAuth2 Integration
|
||||
📅 Jan 18, 16:00 | 🏷️ oauth, authentication, api
|
||||
|
||||
To reload: /reload-session <id>
|
||||
To search: /search-sessions <keywords>
|
||||
```
|
||||
|
||||
**Ambiguous request:**
|
||||
```
|
||||
🔍 Found multiple sessions matching "authentication":
|
||||
|
||||
1. [2026-01-20_1430] Implement JWT Authentication
|
||||
2. [2026-01-18_1600] Setup OAuth2 Integration
|
||||
3. [2026-01-15_1000] Add API Authentication
|
||||
|
||||
Which session would you like to reload? (Use the ID)
|
||||
```
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "save-session-plugin",
|
||||
"description": "Plugin for save-session",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
}
|
||||
}
|
||||
206
skills-workflow/save-session-plugin/skills/SKILL.md
Normal file
206
skills-workflow/save-session-plugin/skills/SKILL.md
Normal file
@@ -0,0 +1,206 @@
|
||||
---
|
||||
name: save-session
|
||||
description: Auto-save Claude session conversation with AI-generated title, summary, and tags in searchable JSON format
|
||||
---
|
||||
|
||||
# Save Session Skill
|
||||
|
||||
You are now in session save mode. Your task is to save the current conversation with a meaningful title and comprehensive summary.
|
||||
|
||||
## Auto-Save Mode
|
||||
|
||||
If this skill was triggered by an `<auto-save-trigger>` tag, operate in **auto-save mode**:
|
||||
- Skip all user confirmations and questions
|
||||
- Generate title, summary, and tags automatically
|
||||
- Save immediately without asking for custom tags
|
||||
- Output a brief confirmation only
|
||||
|
||||
## Instructions
|
||||
|
||||
1. **Analyze the Conversation**: Review the entire conversation history to understand:
|
||||
- Main topics discussed
|
||||
- Key problems solved
|
||||
- Important decisions made
|
||||
- Technologies or files involved
|
||||
|
||||
2. **Generate Title**: Create a concise, descriptive title (5-10 words) that captures the essence of the conversation.
|
||||
- Use imperative or descriptive form
|
||||
- Include key technologies/features mentioned
|
||||
- Example: "Implement User Authentication with JWT"
|
||||
- Example: "Debug Memory Leak in React Component"
|
||||
|
||||
3. **Generate Summary**: Write a structured summary (3-5 paragraphs) that includes:
|
||||
- **Context**: What was the initial request or problem?
|
||||
- **Approach**: What approach or solution was taken?
|
||||
- **Key Changes**: What were the main changes or implementations?
|
||||
- **Outcome**: What was achieved or what's the current status?
|
||||
- **Next Steps** (if applicable): What remains to be done?
|
||||
|
||||
4. **Extract Tags**: Identify 3-8 relevant tags:
|
||||
- Technologies used (e.g., "react", "typescript", "docker")
|
||||
- Task type (e.g., "bug-fix", "feature", "refactor", "documentation")
|
||||
- Domain (e.g., "authentication", "ui", "api", "database")
|
||||
|
||||
5. **Get Session ID**: Check `~/.claude/hooks/.current-session` for the current session ID. If it doesn't exist, generate one using format `YYYY-MM-DD_HHmm`.
|
||||
|
||||
6. **Filter Conversation Content**: Before saving, clean the conversation:
|
||||
|
||||
**EXCLUDE these from saved conversation:**
|
||||
- Bash/shell command outputs (keep only the command intent)
|
||||
- Full file contents from Read tool (keep only file path + brief note)
|
||||
- Tool result outputs (Glob results, Grep results, etc.)
|
||||
- `<system-reminder>` tags and their contents
|
||||
- `<auto-save-trigger>` tags
|
||||
- Raw JSON/XML tool responses
|
||||
- Error stack traces (summarize the error instead)
|
||||
- Large code blocks from file reads (keep only relevant snippets)
|
||||
|
||||
**INCLUDE and preserve:**
|
||||
- User's questions and requests (the actual intent)
|
||||
- Assistant's explanations and reasoning
|
||||
- Key decisions and why they were made
|
||||
- Code changes made (what was added/modified)
|
||||
- Important findings and conclusions
|
||||
- File paths that were modified
|
||||
- Summary of what tools accomplished (not raw output)
|
||||
|
||||
**Transform tool calls to summaries:**
|
||||
- Instead of: `[Bash output: 500 lines of npm install...]`
|
||||
- Save as: `"Installed dependencies with npm install"`
|
||||
- Instead of: `[Read file: 200 lines of code...]`
|
||||
- Save as: `"Read MallPurchaseManager.java to understand order push logic"`
|
||||
|
||||
7. **Save to File**: Create a JSON file in `~/.claude/sessions/` with:
|
||||
- Filename: `<session-id>_<sanitized-title>.json`
|
||||
- Content structure:
|
||||
```json
|
||||
{
|
||||
"id": "YYYY-MM-DD_HHmm",
|
||||
"title": "[Generated Title]",
|
||||
"date": "[ISO 8601 format]",
|
||||
"timestamp": 1234567890,
|
||||
"tags": ["tag1", "tag2"],
|
||||
"summary": {
|
||||
"context": "What was the initial request or problem?",
|
||||
"approach": "What approach or solution was taken?",
|
||||
"keyChanges": "What were the main changes or implementations?",
|
||||
"outcome": "What was achieved or what's the current status?",
|
||||
"nextSteps": "What remains to be done (if applicable)"
|
||||
},
|
||||
"metadata": {
|
||||
"messageCount": 0,
|
||||
"technologies": ["tech1", "tech2"],
|
||||
"filesModified": ["file1", "file2"]
|
||||
},
|
||||
"conversation": [
|
||||
{
|
||||
"role": "user|assistant",
|
||||
"content": "cleaned message content - NO raw tool outputs",
|
||||
"timestamp": "ISO 8601",
|
||||
"toolSummary": "optional: brief summary of tools used in this turn"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
8. **Update Index**: After saving the session, update `~/.claude/sessions/index.json`:
|
||||
- Add entry with id, title, date, tags, and summary preview
|
||||
- Keep index sorted by date (newest first)
|
||||
- If index doesn't exist, create it
|
||||
- Index structure:
|
||||
```json
|
||||
{
|
||||
"sessions": [
|
||||
{
|
||||
"id": "YYYY-MM-DD_HHmm",
|
||||
"title": "Title",
|
||||
"date": "ISO 8601",
|
||||
"tags": ["tag1"],
|
||||
"summaryPreview": "First 200 chars of context..."
|
||||
}
|
||||
],
|
||||
"lastUpdated": "ISO 8601"
|
||||
}
|
||||
```
|
||||
|
||||
9. **Post-Save Actions**: After saving:
|
||||
- Reset autosave timer: `~/.claude/hooks/autosave-mark.sh`
|
||||
- Clear pending save flag: `rm -f ~/.claude/hooks/.pending-save`
|
||||
|
||||
10. **Confirm**: After saving, report back to the user:
|
||||
- The session ID and filename
|
||||
- The generated title
|
||||
- Main tags extracted
|
||||
- Brief confirmation with instructions on how to reload
|
||||
|
||||
## Important Notes
|
||||
|
||||
- Create `~/.claude/sessions/` directory if it doesn't exist
|
||||
- Sanitize the title for filename (lowercase, replace spaces with hyphens, remove special chars)
|
||||
- In manual mode, ask user if they want to add any custom tags before saving
|
||||
- In auto-save mode, skip all user interactions
|
||||
- Always update the index file for fast searching
|
||||
- Use current timestamp in ISO 8601 format
|
||||
- Count actual messages in conversation for metadata
|
||||
- Each conversation MUST have its own unique JSON file
|
||||
|
||||
## Conversation Filtering Example
|
||||
|
||||
**RAW conversation (DON'T save like this):**
|
||||
```
|
||||
User: "找一下订单推送的代码"
|
||||
Assistant: [Grep tool output with 50 matching files...]
|
||||
Assistant: [Read file output with 200 lines of Java code...]
|
||||
Assistant: "I found the order push code in MallPurchaseManager.java"
|
||||
User: "修改它加上channelType"
|
||||
Assistant: [Edit tool with full file diff...]
|
||||
<system-reminder>Task tools haven't been used...</system-reminder>
|
||||
```
|
||||
|
||||
**CLEANED conversation (Save like this):**
|
||||
```json
|
||||
{
|
||||
"conversation": [
|
||||
{
|
||||
"role": "user",
|
||||
"content": "找一下订单推送的代码"
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": "Found order push code in MallPurchaseManager.java:5536 in the getJsonString() method. This method assembles order data for pushing to Lining platform.",
|
||||
"toolSummary": "Searched codebase, read MallPurchaseManager.java"
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "修改它加上channelType"
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": "Added channelType field to the order push logic. Now when orders are pushed to Lining platform, it will include the external platform type (卓望/南航).",
|
||||
"toolSummary": "Edited MallPurchaseManager.java - added order.setChannelType()"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Example Output (Manual Mode)
|
||||
|
||||
```
|
||||
Session saved successfully!
|
||||
|
||||
ID: 2026-01-20_1430
|
||||
Title: Implement Dark Mode Toggle Feature
|
||||
Tags: react, css, ui, feature
|
||||
File: ~/.claude/sessions/2026-01-20_1430_implement-dark-mode-toggle-feature.json
|
||||
|
||||
The conversation has been archived with full history (45 messages).
|
||||
|
||||
To reload this session: /reload-session 2026-01-20_1430
|
||||
To search sessions: /search-sessions dark mode
|
||||
```
|
||||
|
||||
## Example Output (Auto-Save Mode)
|
||||
|
||||
```
|
||||
[Auto-saved] 2026-01-20_1430: "Implement Dark Mode Toggle Feature" (45 messages)
|
||||
```
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "search-sessions-plugin",
|
||||
"description": "Plugin for search-sessions",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
}
|
||||
}
|
||||
128
skills-workflow/search-sessions-plugin/skills/SKILL.md
Normal file
128
skills-workflow/search-sessions-plugin/skills/SKILL.md
Normal file
@@ -0,0 +1,128 @@
|
||||
---
|
||||
name: search-sessions
|
||||
description: Search saved Claude sessions by title, tags, date, or content
|
||||
---
|
||||
|
||||
# Search Sessions Skill
|
||||
|
||||
You are now in session search mode. Your task is to help the user find saved conversations.
|
||||
|
||||
## Instructions
|
||||
|
||||
1. **Read Index**: Load `~/.claude/sessions/index.json` to get the list of all sessions
|
||||
- If file doesn't exist, inform user no sessions have been saved yet
|
||||
|
||||
2. **Parse Search Query**: Understand what the user is looking for:
|
||||
- Keywords in title or summary
|
||||
- Specific tags (e.g., "react", "bug-fix", "authentication")
|
||||
- Date range (e.g., "last week", "January 2026", "today")
|
||||
- Combination of filters
|
||||
- Special flags like "--all" to show all results
|
||||
|
||||
3. **Search Logic**:
|
||||
- First search in index.json (fast search by title, tags, date, summary preview)
|
||||
- If user needs full content search, load individual session JSON files from `~/.claude/sessions/`
|
||||
- Support case-insensitive search
|
||||
- Support partial matches
|
||||
- Score results by relevance
|
||||
|
||||
4. **Display Results**: Show matching sessions in a clear, readable format:
|
||||
```
|
||||
🔍 Found 3 sessions matching "react":
|
||||
|
||||
1. [2026-01-20_1430] Implement Dark Mode Toggle Feature
|
||||
📅 2026-01-20 14:30 | 🏷️ react, css, ui, feature
|
||||
💡 Added dark mode toggle to application settings...
|
||||
|
||||
2. [2026-01-19_1015] Debug Memory Leak in React Component
|
||||
📅 2026-01-19 10:15 | 🏷️ react, debugging, performance
|
||||
💡 Investigated and fixed memory leak caused by...
|
||||
|
||||
3. [2026-01-18_1600] Setup Authentication with JWT
|
||||
📅 2026-01-18 16:00 | 🏷️ authentication, jwt, security
|
||||
💡 Implemented JWT-based authentication system...
|
||||
|
||||
To reload a session: /reload-session <id>
|
||||
```
|
||||
|
||||
5. **Advanced Search**:
|
||||
- Support filtering by multiple tags: "react AND authentication"
|
||||
- Support OR logic: "react OR vue"
|
||||
- Support date ranges: "between 2026-01-01 and 2026-01-20"
|
||||
- Support exclusion: "react NOT bug"
|
||||
- Support tag-specific search: "tag:authentication"
|
||||
|
||||
## Search Examples
|
||||
|
||||
**By keyword:**
|
||||
- `search sessions about react` → Search for "react" in title, tags, and summary
|
||||
|
||||
**By date:**
|
||||
- `find sessions from last week` → Filter by date range (last 7 days)
|
||||
- `sessions from January` → Filter by month
|
||||
- `sessions today` → Today's sessions only
|
||||
|
||||
**By tag:**
|
||||
- `search sessions tagged authentication` → Filter by specific tag
|
||||
- `sessions with tag:bug-fix` → Explicit tag search
|
||||
|
||||
**List all:**
|
||||
- `list all sessions` → Show all sessions (newest first)
|
||||
- `show recent sessions` → Show last 10 sessions
|
||||
|
||||
**Combined:**
|
||||
- `search react sessions from last month` → Keyword + date filter
|
||||
- `find authentication AND api sessions` → Multiple tags
|
||||
|
||||
## Important Notes
|
||||
|
||||
- Show most recent sessions first by default
|
||||
- Limit initial results to 10, offer to show more with --all flag
|
||||
- If no matches found, suggest related searches or show recent sessions
|
||||
- Provide the session ID clearly so user can reload it
|
||||
- Display dates in human-readable format (e.g., "2 days ago", "last week")
|
||||
- If only one result found, offer to load it automatically
|
||||
|
||||
## Example Output Formats
|
||||
|
||||
**Multiple results:**
|
||||
```
|
||||
🔍 Found 5 sessions matching "authentication":
|
||||
|
||||
1. [2026-01-20_1430] Setup OAuth2 Integration
|
||||
📅 Jan 20, 14:30 (today) | 🏷️ oauth, authentication, api
|
||||
💡 Integrated OAuth2 provider for third-party login...
|
||||
|
||||
2. [2026-01-18_1600] Implement JWT Authentication
|
||||
📅 Jan 18, 16:00 (2 days ago) | 🏷️ jwt, authentication, security
|
||||
💡 Built JWT-based auth system with refresh tokens...
|
||||
|
||||
Showing 2 of 5 results. Use "/search-sessions authentication --all" to see all.
|
||||
To reload: /reload-session <id>
|
||||
```
|
||||
|
||||
**No results:**
|
||||
```
|
||||
🔍 No sessions found matching "xyz"
|
||||
|
||||
Suggestions:
|
||||
- Try different keywords
|
||||
- Check spelling
|
||||
- Use broader search terms
|
||||
|
||||
Recent sessions:
|
||||
1. [2026-01-20_1430] Implement Dark Mode Toggle Feature
|
||||
2. [2026-01-19_1015] Debug Memory Leak in React Component
|
||||
...
|
||||
```
|
||||
|
||||
**Single result:**
|
||||
```
|
||||
🔍 Found 1 session matching "oauth":
|
||||
|
||||
[2026-01-20_1430] Setup OAuth2 Integration
|
||||
📅 Jan 20, 14:30 (today) | 🏷️ oauth, authentication, api
|
||||
💡 Integrated OAuth2 provider for third-party login...
|
||||
|
||||
Would you like to reload this session? (/reload-session 2026-01-20_1430)
|
||||
```
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "session-plugin",
|
||||
"description": "Manage Claude Code sessions — save, reload, read, and search saved conversations. Triggers on /session commands or when user mentions saving session, reloading session, finding previous conversations, or continuing previous work.",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
}
|
||||
}
|
||||
149
skills-workflow/session-plugin/skills/SKILL.md
Normal file
149
skills-workflow/session-plugin/skills/SKILL.md
Normal file
@@ -0,0 +1,149 @@
|
||||
---
|
||||
name: session
|
||||
description: Manage Claude Code sessions — save, reload, read, and search saved conversations. Triggers on /session commands or when user mentions saving session, reloading session, finding previous conversations, or continuing previous work.
|
||||
---
|
||||
|
||||
# Session Management Skill
|
||||
|
||||
Save, reload, read, and search Claude Code sessions across conversations.
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `/session save` | Save current conversation with auto-generated title, summary, tags |
|
||||
| `/session reload <id>` | Reload a session to continue working from where you left off |
|
||||
| `/session read <id>` | View a session (read-only, no context load) |
|
||||
| `/session search <query>` | Search sessions by keyword, tag, or date |
|
||||
|
||||
---
|
||||
|
||||
## /session save
|
||||
|
||||
### Auto-Save Mode
|
||||
If triggered by `<auto-save-trigger>`, skip all confirmations and save immediately.
|
||||
|
||||
### Steps
|
||||
|
||||
1. **Analyze conversation** — main topics, problems solved, decisions made, files touched
|
||||
2. **Generate title** — 5–10 words, descriptive (e.g. "Implement JWT Authentication with Refresh Tokens")
|
||||
3. **Generate summary** with sections:
|
||||
- `context`: initial request or problem
|
||||
- `approach`: solution taken
|
||||
- `keyChanges`: main changes/implementations
|
||||
- `outcome`: what was achieved
|
||||
- `nextSteps`: what remains (if any)
|
||||
4. **Extract tags** — 3–8 tags: technologies, task type, domain
|
||||
5. **Get session ID** — check `~/.claude/hooks/.current-session`; if missing, use `YYYY-MM-DD_HHmm`
|
||||
6. **Filter conversation before saving:**
|
||||
- EXCLUDE: bash outputs, full file reads, tool results, `<system-reminder>` tags, stack traces
|
||||
- INCLUDE: user requests, assistant reasoning, decisions, file paths modified, code changes summary
|
||||
7. **Save to** `~/.claude/sessions/<id>_<sanitized-title>.json`:
|
||||
```json
|
||||
{
|
||||
"id": "YYYY-MM-DD_HHmm",
|
||||
"title": "...",
|
||||
"date": "ISO 8601",
|
||||
"timestamp": 1234567890,
|
||||
"tags": ["tag1", "tag2"],
|
||||
"summary": {
|
||||
"context": "...", "approach": "...", "keyChanges": "...",
|
||||
"outcome": "...", "nextSteps": "..."
|
||||
},
|
||||
"metadata": { "messageCount": 0, "technologies": [], "filesModified": [] },
|
||||
"conversation": [
|
||||
{ "role": "user|assistant", "content": "...", "toolSummary": "optional" }
|
||||
]
|
||||
}
|
||||
```
|
||||
8. **Update index** `~/.claude/sessions/index.json` — add entry, sort by date desc
|
||||
9. **Post-save** — run `~/.claude/hooks/autosave-mark.sh`, delete `~/.claude/hooks/.pending-save`
|
||||
10. **Confirm** — show session ID, filename, title, tags
|
||||
|
||||
### Output (manual mode)
|
||||
```
|
||||
Session saved!
|
||||
ID: 2026-01-20_1430
|
||||
Title: Implement Dark Mode Toggle Feature
|
||||
Tags: react, css, ui, feature
|
||||
File: ~/.claude/sessions/2026-01-20_1430_implement-dark-mode-toggle-feature.json
|
||||
To reload: /session reload 2026-01-20_1430
|
||||
```
|
||||
|
||||
### Output (auto-save)
|
||||
```
|
||||
[Auto-saved] 2026-01-20_1430: "Implement Dark Mode Toggle Feature" (45 messages)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## /session reload `<id>`
|
||||
|
||||
Load a session to **continue working** from where it left off.
|
||||
|
||||
### Steps
|
||||
|
||||
1. **Resolve ID** — accept exact ID, partial, or keywords; search index.json if ambiguous
|
||||
2. **Load** `~/.claude/sessions/<id>_<title>.json`
|
||||
3. **Display context:**
|
||||
```
|
||||
Loaded: [Title]
|
||||
Date: YYYY-MM-DD HH:mm (X days ago) | Tags: ... | Messages: N
|
||||
Files Modified: file1, file2
|
||||
|
||||
Context: ...
|
||||
Approach: ...
|
||||
Key Changes: ...
|
||||
Outcome: ...
|
||||
Next Steps: ...
|
||||
|
||||
Session loaded. What would you like to work on?
|
||||
```
|
||||
4. **Maintain context** — reference session details, remember modified files, continue naturally
|
||||
5. **Offer options** based on Next Steps
|
||||
|
||||
---
|
||||
|
||||
## /session read `<id>`
|
||||
|
||||
View a session **without** loading it as active context.
|
||||
|
||||
### Steps
|
||||
|
||||
1. Resolve ID (same as reload)
|
||||
2. Load and display — show metadata + summary by default
|
||||
3. **Modes:**
|
||||
- Default: metadata + summary only
|
||||
- `--full`: full conversation history
|
||||
- `--messages N-M`: specific message range
|
||||
4. End with actions: reload link, search link
|
||||
|
||||
---
|
||||
|
||||
## /session search `<query>`
|
||||
|
||||
Search saved sessions.
|
||||
|
||||
### Steps
|
||||
|
||||
1. Load `~/.claude/sessions/index.json`
|
||||
2. Parse query — keywords, tags (`tag:react`), dates (`last week`, `January`)
|
||||
3. Search index first (fast); load individual files only for full-content search
|
||||
4. Display results (newest first, limit 10):
|
||||
```
|
||||
Found 3 sessions matching "react":
|
||||
|
||||
1. [2026-01-20_1430] Implement Dark Mode Toggle Feature
|
||||
Jan 20, 14:30 | react, css, ui
|
||||
Added dark mode toggle to application settings...
|
||||
|
||||
To reload: /session reload <id>
|
||||
```
|
||||
5. If single result, offer to reload automatically
|
||||
|
||||
### Query syntax
|
||||
- Keywords: `search react authentication`
|
||||
- Tag filter: `tag:bug-fix`
|
||||
- Date: `last week`, `today`, `January 2026`
|
||||
- Boolean: `react AND jwt`, `react OR vue`, `react NOT bug`
|
||||
- All: `list all sessions`
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "skill-manager-plugin",
|
||||
"description": "|",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
}
|
||||
}
|
||||
306
skills-workflow/skill-manager-plugin/git-ops.sh
Executable file
306
skills-workflow/skill-manager-plugin/git-ops.sh
Executable file
@@ -0,0 +1,306 @@
|
||||
#!/bin/bash
|
||||
# git-ops.sh - Git 操作封装
|
||||
# 用法:
|
||||
# ./git-ops.sh clone <repo> <name> - 克隆仓库
|
||||
# ./git-ops.sh pull <name> - 拉取更新
|
||||
# ./git-ops.sh checkout <name> <ref> - 切换版本
|
||||
# ./git-ops.sh fetch <name> - 获取远程更新
|
||||
# ./git-ops.sh status <name> - 查看状态
|
||||
# ./git-ops.sh has-updates <name> - 检查是否有更新
|
||||
|
||||
set -e
|
||||
|
||||
SKILLS_DIR="$HOME/.claude/skills"
|
||||
REPOS_DIR="$SKILLS_DIR/repos"
|
||||
REGISTRY_SCRIPT="$SKILLS_DIR/skill-manager/scripts/registry.sh"
|
||||
|
||||
# 颜色定义
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
# 从 URL 提取技能名称
|
||||
extract_name() {
|
||||
local repo="$1"
|
||||
# 处理各种格式
|
||||
# https://github.com/org/skill-name.git -> skill-name
|
||||
# git@github.com:org/skill-name.git -> skill-name
|
||||
echo "$repo" | sed -E 's|.*/([^/]+)(\.git)?$|\1|' | sed 's/\.git$//'
|
||||
}
|
||||
|
||||
# 克隆仓库
|
||||
cmd_clone() {
|
||||
local repo="$1"
|
||||
local name="${2:-$(extract_name "$repo")}"
|
||||
|
||||
if [ -z "$repo" ]; then
|
||||
echo -e "${RED}用法: git-ops.sh clone <repo> [name]${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local target_dir="$REPOS_DIR/$name"
|
||||
|
||||
# 检查是否已存在
|
||||
if [ -d "$target_dir" ]; then
|
||||
echo -e "${YELLOW}技能已存在: $name${NC}"
|
||||
echo "使用 'git-ops.sh pull $name' 更新"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}克隆技能: $name${NC}"
|
||||
echo "仓库: $repo"
|
||||
echo "目标: $target_dir"
|
||||
echo "----------------------------------------"
|
||||
|
||||
# 确保 repos 目录存在
|
||||
mkdir -p "$REPOS_DIR"
|
||||
|
||||
# 克隆仓库
|
||||
if git clone "$repo" "$target_dir"; then
|
||||
echo -e "${GREEN}✓ 克隆成功${NC}"
|
||||
|
||||
# 检查 skill.yaml
|
||||
if [ ! -f "$target_dir/skill.yaml" ]; then
|
||||
echo -e "${YELLOW}⚠ 警告: 未找到 skill.yaml${NC}"
|
||||
fi
|
||||
|
||||
# 获取版本
|
||||
local version="unknown"
|
||||
if [ -f "$target_dir/skill.yaml" ] && command -v yq &> /dev/null; then
|
||||
version=$(yq e '.version // "1.0.0"' "$target_dir/skill.yaml")
|
||||
fi
|
||||
|
||||
# 添加到 registry
|
||||
"$REGISTRY_SCRIPT" add "$name" "$repo" "$version"
|
||||
|
||||
echo -e "${GREEN}✓ 技能安装完成: $name ($version)${NC}"
|
||||
else
|
||||
echo -e "${RED}✗ 克隆失败${NC}"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 拉取更新
|
||||
cmd_pull() {
|
||||
local name="$1"
|
||||
|
||||
if [ -z "$name" ]; then
|
||||
echo -e "${RED}用法: git-ops.sh pull <name>${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local repo_dir="$REPOS_DIR/$name"
|
||||
|
||||
if [ ! -d "$repo_dir" ]; then
|
||||
echo -e "${RED}技能不存在: $name${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}更新技能: $name${NC}"
|
||||
echo "----------------------------------------"
|
||||
|
||||
cd "$repo_dir"
|
||||
|
||||
# 获取当前版本
|
||||
local old_version="unknown"
|
||||
if [ -f "skill.yaml" ] && command -v yq &> /dev/null; then
|
||||
old_version=$(yq e '.version // "unknown"' skill.yaml)
|
||||
fi
|
||||
|
||||
# 拉取更新
|
||||
if git pull origin main 2>/dev/null || git pull origin master 2>/dev/null; then
|
||||
# 获取新版本
|
||||
local new_version="unknown"
|
||||
if [ -f "skill.yaml" ] && command -v yq &> /dev/null; then
|
||||
new_version=$(yq e '.version // "unknown"' skill.yaml)
|
||||
fi
|
||||
|
||||
if [ "$old_version" != "$new_version" ]; then
|
||||
echo -e "${GREEN}✓ 版本更新: $old_version → $new_version${NC}"
|
||||
"$REGISTRY_SCRIPT" update "$name" version "$new_version"
|
||||
else
|
||||
echo -e "${GREEN}✓ 已是最新版本: $new_version${NC}"
|
||||
fi
|
||||
|
||||
# 更新 last_updated
|
||||
"$REGISTRY_SCRIPT" update "$name" last_updated "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
||||
else
|
||||
echo -e "${RED}✗ 更新失败${NC}"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 切换版本
|
||||
cmd_checkout() {
|
||||
local name="$1"
|
||||
local ref="$2"
|
||||
|
||||
if [ -z "$name" ] || [ -z "$ref" ]; then
|
||||
echo -e "${RED}用法: git-ops.sh checkout <name> <ref>${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local repo_dir="$REPOS_DIR/$name"
|
||||
|
||||
if [ ! -d "$repo_dir" ]; then
|
||||
echo -e "${RED}技能不存在: $name${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}切换版本: $name → $ref${NC}"
|
||||
echo "----------------------------------------"
|
||||
|
||||
cd "$repo_dir"
|
||||
|
||||
# 获取当前版本
|
||||
local old_ref=$(git describe --tags --always 2>/dev/null || git rev-parse --short HEAD)
|
||||
|
||||
# 切换版本
|
||||
if git checkout "$ref" 2>/dev/null; then
|
||||
echo -e "${GREEN}✓ 版本切换: $old_ref → $ref${NC}"
|
||||
|
||||
# 更新 registry
|
||||
"$REGISTRY_SCRIPT" update "$name" version "$ref"
|
||||
"$REGISTRY_SCRIPT" update "$name" last_updated "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
||||
else
|
||||
echo -e "${RED}✗ 切换失败: $ref 不存在${NC}"
|
||||
echo "可用的 tag:"
|
||||
git tag -l | head -10
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 获取远程更新
|
||||
cmd_fetch() {
|
||||
local name="$1"
|
||||
|
||||
if [ -z "$name" ]; then
|
||||
echo -e "${RED}用法: git-ops.sh fetch <name>${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local repo_dir="$REPOS_DIR/$name"
|
||||
|
||||
if [ ! -d "$repo_dir" ]; then
|
||||
echo -e "${RED}技能不存在: $name${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "$repo_dir"
|
||||
git fetch origin --tags --quiet
|
||||
echo -e "${GREEN}✓ 已获取远程更新: $name${NC}"
|
||||
}
|
||||
|
||||
# 查看状态
|
||||
cmd_status() {
|
||||
local name="$1"
|
||||
|
||||
if [ -z "$name" ]; then
|
||||
echo -e "${RED}用法: git-ops.sh status <name>${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local repo_dir="$REPOS_DIR/$name"
|
||||
|
||||
if [ ! -d "$repo_dir" ]; then
|
||||
echo -e "${RED}技能不存在: $name${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}技能状态: $name${NC}"
|
||||
echo "----------------------------------------"
|
||||
|
||||
cd "$repo_dir"
|
||||
|
||||
local branch=$(git branch --show-current 2>/dev/null || echo "detached")
|
||||
local commit=$(git rev-parse --short HEAD)
|
||||
local remote_url=$(git config --get remote.origin.url)
|
||||
|
||||
echo "分支: $branch"
|
||||
echo "Commit: $commit"
|
||||
echo "远程: $remote_url"
|
||||
|
||||
if [ -f "skill.yaml" ] && command -v yq &> /dev/null; then
|
||||
local version=$(yq e '.version // "unknown"' skill.yaml)
|
||||
echo "版本: $version"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "最近提交:"
|
||||
git log --oneline -3
|
||||
}
|
||||
|
||||
# 检查是否有更新
|
||||
cmd_has_updates() {
|
||||
local name="$1"
|
||||
|
||||
if [ -z "$name" ]; then
|
||||
echo -e "${RED}用法: git-ops.sh has-updates <name>${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local repo_dir="$REPOS_DIR/$name"
|
||||
|
||||
if [ ! -d "$repo_dir" ]; then
|
||||
echo -e "${RED}技能不存在: $name${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "$repo_dir"
|
||||
|
||||
# 获取远程更新
|
||||
git fetch origin --quiet 2>/dev/null || true
|
||||
|
||||
# 比较本地和远程
|
||||
local local_head=$(git rev-parse HEAD)
|
||||
local remote_head=$(git rev-parse origin/main 2>/dev/null || git rev-parse origin/master 2>/dev/null || echo "")
|
||||
|
||||
if [ -z "$remote_head" ]; then
|
||||
echo "unknown"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$local_head" != "$remote_head" ]; then
|
||||
echo "yes"
|
||||
# 显示更新数量
|
||||
local behind=$(git rev-list HEAD..origin/main --count 2>/dev/null || git rev-list HEAD..origin/master --count 2>/dev/null || echo "0")
|
||||
echo "behind: $behind commits"
|
||||
else
|
||||
echo "no"
|
||||
fi
|
||||
}
|
||||
|
||||
# 主命令分发
|
||||
case "${1:-help}" in
|
||||
clone)
|
||||
cmd_clone "$2" "$3"
|
||||
;;
|
||||
pull)
|
||||
cmd_pull "$2"
|
||||
;;
|
||||
checkout)
|
||||
cmd_checkout "$2" "$3"
|
||||
;;
|
||||
fetch)
|
||||
cmd_fetch "$2"
|
||||
;;
|
||||
status)
|
||||
cmd_status "$2"
|
||||
;;
|
||||
has-updates)
|
||||
cmd_has_updates "$2"
|
||||
;;
|
||||
*)
|
||||
echo "用法: git-ops.sh <command> [args]"
|
||||
echo ""
|
||||
echo "命令:"
|
||||
echo " clone <repo> [name] 克隆仓库"
|
||||
echo " pull <name> 拉取更新"
|
||||
echo " checkout <name> <ref> 切换版本"
|
||||
echo " fetch <name> 获取远程更新"
|
||||
echo " status <name> 查看状态"
|
||||
echo " has-updates <name> 检查是否有更新"
|
||||
;;
|
||||
esac
|
||||
58
skills-workflow/skill-manager-plugin/init-registry.sh
Executable file
58
skills-workflow/skill-manager-plugin/init-registry.sh
Executable file
@@ -0,0 +1,58 @@
|
||||
#!/bin/bash
|
||||
# init-registry.sh - 初始化技能注册表
|
||||
# 用法: ./init-registry.sh
|
||||
|
||||
set -e
|
||||
|
||||
SKILLS_DIR="$HOME/.claude/skills"
|
||||
REGISTRY_FILE="$SKILLS_DIR/registry.yaml"
|
||||
REPOS_DIR="$SKILLS_DIR/repos"
|
||||
|
||||
# 颜色定义
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
echo "初始化 Skills Registry..."
|
||||
echo "----------------------------------------"
|
||||
|
||||
# 创建 repos 目录
|
||||
if [ ! -d "$REPOS_DIR" ]; then
|
||||
mkdir -p "$REPOS_DIR"
|
||||
echo -e "${GREEN}✓ 创建 repos 目录${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}⚠ repos 目录已存在${NC}"
|
||||
fi
|
||||
|
||||
# 创建 registry.yaml
|
||||
if [ ! -f "$REGISTRY_FILE" ]; then
|
||||
cat > "$REGISTRY_FILE" << 'EOF'
|
||||
# Skills Registry - 技能注册表
|
||||
# 由 skill-manager 自动管理,请勿手动编辑
|
||||
|
||||
version: 1
|
||||
updated_at: $(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
||||
|
||||
# 全局配置
|
||||
config:
|
||||
auto_update_check: true # 启动时检查更新
|
||||
update_check_interval: 86400 # 检查间隔(秒),默认24小时
|
||||
default_branch: main # 默认分支
|
||||
|
||||
# 已安装技能
|
||||
skills: {}
|
||||
EOF
|
||||
# 替换日期
|
||||
sed -i '' "s/\$(date -u +\"%Y-%m-%dT%H:%M:%SZ\")/$(date -u +"%Y-%m-%dT%H:%M:%SZ")/" "$REGISTRY_FILE"
|
||||
echo -e "${GREEN}✓ 创建 registry.yaml${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}⚠ registry.yaml 已存在${NC}"
|
||||
fi
|
||||
|
||||
echo "----------------------------------------"
|
||||
echo -e "${GREEN}✓ 初始化完成${NC}"
|
||||
echo ""
|
||||
echo "目录结构:"
|
||||
echo " $SKILLS_DIR/"
|
||||
echo " ├── registry.yaml"
|
||||
echo " └── repos/"
|
||||
@@ -0,0 +1,157 @@
|
||||
# skill.yaml 规范文档
|
||||
|
||||
## 概述
|
||||
|
||||
`skill.yaml` 是技能的元数据定义文件,位于技能仓库根目录。
|
||||
|
||||
## 字段定义
|
||||
|
||||
### 必填字段
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `name` | string | hyphen-case, ≤64字符 | 技能唯一标识 |
|
||||
| `version` | string | 语义化版本 | 当前版本号 |
|
||||
| `description` | string | ≤1024字符 | 技能描述 |
|
||||
|
||||
### 可选字段
|
||||
|
||||
| 字段 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| `author` | string | - | 作者/团队 |
|
||||
| `license` | string | - | 许可证 |
|
||||
| `triggers` | object | - | 触发条件 |
|
||||
| `prompt_file` | string | SKILL.md | 提示词文件 |
|
||||
| `dependencies` | array | [] | 依赖技能列表 |
|
||||
| `mcp_servers` | array | [] | MCP 服务器依赖 |
|
||||
| `hooks` | object | - | 生命周期钩子 |
|
||||
| `allowed_tools` | array | - | 允许的工具 |
|
||||
| `metadata` | object | - | 自定义元数据 |
|
||||
|
||||
## triggers 结构
|
||||
|
||||
```yaml
|
||||
triggers:
|
||||
# 关键词触发 - 用户输入包含这些词时激活
|
||||
keywords:
|
||||
- coolbuy-paas
|
||||
- 酷采
|
||||
|
||||
# 命令触发 - 用户输入以这些命令开头时激活
|
||||
commands:
|
||||
- /skill
|
||||
|
||||
# 文件模式触发 - 当前目录匹配时激活
|
||||
file_patterns:
|
||||
- "**/coolbuy-paas/**"
|
||||
```
|
||||
|
||||
## hooks 结构
|
||||
|
||||
```yaml
|
||||
hooks:
|
||||
# 安装后执行
|
||||
post_install:
|
||||
- "echo 'Installed'"
|
||||
- "npm install"
|
||||
|
||||
# 更新后执行
|
||||
post_update:
|
||||
- "echo 'Updated'"
|
||||
|
||||
# 卸载前执行
|
||||
post_uninstall:
|
||||
- "echo 'Goodbye'"
|
||||
```
|
||||
|
||||
## 完整示例
|
||||
|
||||
```yaml
|
||||
name: coolbuy-paas
|
||||
version: 1.2.0
|
||||
description: |
|
||||
酷采3.0 SaaS 租户端开发与测试。
|
||||
支持商品管理、订单管理等模块开发。
|
||||
author: your-team
|
||||
license: MIT
|
||||
|
||||
triggers:
|
||||
keywords:
|
||||
- coolbuy-paas
|
||||
- 酷采
|
||||
- 商品管理
|
||||
- 租户端
|
||||
file_patterns:
|
||||
- "**/coolbuy-paas/**"
|
||||
|
||||
prompt_file: SKILL.md
|
||||
|
||||
dependencies:
|
||||
- dev-coding
|
||||
- ops-tools
|
||||
|
||||
mcp_servers:
|
||||
- ai-proj
|
||||
- chrome-devtools
|
||||
|
||||
hooks:
|
||||
post_install:
|
||||
- "echo '✓ coolbuy-paas 技能安装完成'"
|
||||
post_update:
|
||||
- "echo '✓ coolbuy-paas 技能已更新'"
|
||||
|
||||
allowed_tools:
|
||||
- Bash
|
||||
- Read
|
||||
- Write
|
||||
- Edit
|
||||
- Glob
|
||||
- Grep
|
||||
|
||||
metadata:
|
||||
category: business
|
||||
tags:
|
||||
- saas
|
||||
- ecommerce
|
||||
- tenant
|
||||
min_claude_version: "1.0.0"
|
||||
project_repo: "https://github.com/org/coolbuy-paas"
|
||||
```
|
||||
|
||||
## 验证规则
|
||||
|
||||
1. **name**:
|
||||
- 只能包含小写字母、数字、连字符
|
||||
- 不能以连字符开头或结尾
|
||||
- 长度 1-64 字符
|
||||
|
||||
2. **version**:
|
||||
- 符合语义化版本规范 (SemVer)
|
||||
- 格式: MAJOR.MINOR.PATCH
|
||||
|
||||
3. **description**:
|
||||
- 长度不超过 1024 字符
|
||||
- 不能包含 `<` 或 `>` 字符
|
||||
|
||||
4. **prompt_file**:
|
||||
- 文件必须存在
|
||||
- 必须是 Markdown 格式
|
||||
|
||||
5. **dependencies**:
|
||||
- 每个依赖必须是有效的技能名称
|
||||
- 不能有循环依赖
|
||||
|
||||
## 与 Anthropic 官方规范对比
|
||||
|
||||
| 字段 | 官方规范 | 本规范 | 说明 |
|
||||
|------|----------|--------|------|
|
||||
| name | ✓ | ✓ | 相同 |
|
||||
| description | ✓ | ✓ | 相同 |
|
||||
| license | ✓ | ✓ | 相同 |
|
||||
| allowed-tools | ✓ | allowed_tools | 命名调整 |
|
||||
| metadata | ✓ | ✓ | 相同 |
|
||||
| version | ✗ | ✓ | 新增 |
|
||||
| triggers | ✗ | ✓ | 新增 |
|
||||
| dependencies | ✗ | ✓ | 新增 |
|
||||
| hooks | ✗ | ✓ | 新增 |
|
||||
| mcp_servers | ✗ | ✓ | 新增 |
|
||||
204
skills-workflow/skill-manager-plugin/registry.sh
Executable file
204
skills-workflow/skill-manager-plugin/registry.sh
Executable file
@@ -0,0 +1,204 @@
|
||||
#!/bin/bash
|
||||
# registry.sh - Registry 管理工具
|
||||
# 用法:
|
||||
# ./registry.sh list - 列出所有技能
|
||||
# ./registry.sh get <name> - 获取技能信息
|
||||
# ./registry.sh add <name> <repo> - 添加技能记录
|
||||
# ./registry.sh remove <name> - 移除技能记录
|
||||
# ./registry.sh update <name> <field> <value> - 更新字段
|
||||
|
||||
set -e
|
||||
|
||||
SKILLS_DIR="$HOME/.claude/skills"
|
||||
REGISTRY_FILE="$SKILLS_DIR/registry.yaml"
|
||||
|
||||
# 颜色定义
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
# 检查 yq 是否安装
|
||||
check_yq() {
|
||||
if ! command -v yq &> /dev/null; then
|
||||
echo -e "${RED}错误: 需要安装 yq${NC}"
|
||||
echo "安装方法: brew install yq"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 检查 registry 文件
|
||||
check_registry() {
|
||||
if [ ! -f "$REGISTRY_FILE" ]; then
|
||||
echo -e "${YELLOW}Registry 不存在,正在初始化...${NC}"
|
||||
"$SKILLS_DIR/skill-manager/scripts/init-registry.sh"
|
||||
fi
|
||||
}
|
||||
|
||||
# 列出所有技能
|
||||
cmd_list() {
|
||||
check_yq
|
||||
check_registry
|
||||
|
||||
echo -e "${BLUE}已安装技能:${NC}"
|
||||
echo "----------------------------------------"
|
||||
|
||||
SKILLS=$(yq e '.skills | keys | .[]' "$REGISTRY_FILE" 2>/dev/null || echo "")
|
||||
|
||||
if [ -z "$SKILLS" ]; then
|
||||
echo "(无已安装技能)"
|
||||
return
|
||||
fi
|
||||
|
||||
printf "%-20s %-10s %-10s %s\n" "名称" "版本" "状态" "最后更新"
|
||||
echo "----------------------------------------"
|
||||
|
||||
for skill in $SKILLS; do
|
||||
VERSION=$(yq e ".skills.$skill.version // \"unknown\"" "$REGISTRY_FILE")
|
||||
STATUS=$(yq e ".skills.$skill.status // \"unknown\"" "$REGISTRY_FILE")
|
||||
UPDATED=$(yq e ".skills.$skill.last_updated // \"unknown\"" "$REGISTRY_FILE" | cut -d'T' -f1)
|
||||
|
||||
# 状态颜色
|
||||
case $STATUS in
|
||||
active) STATUS_COLOR="${GREEN}$STATUS${NC}" ;;
|
||||
disabled) STATUS_COLOR="${YELLOW}$STATUS${NC}" ;;
|
||||
error) STATUS_COLOR="${RED}$STATUS${NC}" ;;
|
||||
*) STATUS_COLOR="$STATUS" ;;
|
||||
esac
|
||||
|
||||
printf "%-20s %-10s " "$skill" "$VERSION"
|
||||
echo -e "$STATUS_COLOR\t$UPDATED"
|
||||
done
|
||||
}
|
||||
|
||||
# 获取技能信息
|
||||
cmd_get() {
|
||||
check_yq
|
||||
check_registry
|
||||
|
||||
local name="$1"
|
||||
if [ -z "$name" ]; then
|
||||
echo -e "${RED}用法: registry.sh get <name>${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local exists=$(yq e ".skills.$name // \"\"" "$REGISTRY_FILE")
|
||||
if [ -z "$exists" ] || [ "$exists" == "null" ]; then
|
||||
echo -e "${RED}技能不存在: $name${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}技能: $name${NC}"
|
||||
echo "----------------------------------------"
|
||||
yq e ".skills.$name" "$REGISTRY_FILE"
|
||||
}
|
||||
|
||||
# 添加技能记录
|
||||
cmd_add() {
|
||||
check_yq
|
||||
check_registry
|
||||
|
||||
local name="$1"
|
||||
local repo="$2"
|
||||
local version="${3:-1.0.0}"
|
||||
|
||||
if [ -z "$name" ] || [ -z "$repo" ]; then
|
||||
echo -e "${RED}用法: registry.sh add <name> <repo> [version]${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local now=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
||||
local local_path="$SKILLS_DIR/repos/$name"
|
||||
|
||||
# 添加技能记录
|
||||
yq e -i ".skills.$name.repo = \"$repo\"" "$REGISTRY_FILE"
|
||||
yq e -i ".skills.$name.local_path = \"$local_path\"" "$REGISTRY_FILE"
|
||||
yq e -i ".skills.$name.version = \"$version\"" "$REGISTRY_FILE"
|
||||
yq e -i ".skills.$name.installed_at = \"$now\"" "$REGISTRY_FILE"
|
||||
yq e -i ".skills.$name.last_updated = \"$now\"" "$REGISTRY_FILE"
|
||||
yq e -i ".skills.$name.status = \"active\"" "$REGISTRY_FILE"
|
||||
|
||||
# 更新 registry 时间
|
||||
yq e -i ".updated_at = \"$now\"" "$REGISTRY_FILE"
|
||||
|
||||
echo -e "${GREEN}✓ 已添加技能: $name${NC}"
|
||||
}
|
||||
|
||||
# 移除技能记录
|
||||
cmd_remove() {
|
||||
check_yq
|
||||
check_registry
|
||||
|
||||
local name="$1"
|
||||
if [ -z "$name" ]; then
|
||||
echo -e "${RED}用法: registry.sh remove <name>${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local exists=$(yq e ".skills.$name // \"\"" "$REGISTRY_FILE")
|
||||
if [ -z "$exists" ] || [ "$exists" == "null" ]; then
|
||||
echo -e "${YELLOW}技能不存在: $name${NC}"
|
||||
return
|
||||
fi
|
||||
|
||||
yq e -i "del(.skills.$name)" "$REGISTRY_FILE"
|
||||
yq e -i ".updated_at = \"$(date -u +"%Y-%m-%dT%H:%M:%SZ")\"" "$REGISTRY_FILE"
|
||||
|
||||
echo -e "${GREEN}✓ 已移除技能: $name${NC}"
|
||||
}
|
||||
|
||||
# 更新技能字段
|
||||
cmd_update() {
|
||||
check_yq
|
||||
check_registry
|
||||
|
||||
local name="$1"
|
||||
local field="$2"
|
||||
local value="$3"
|
||||
|
||||
if [ -z "$name" ] || [ -z "$field" ] || [ -z "$value" ]; then
|
||||
echo -e "${RED}用法: registry.sh update <name> <field> <value>${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local exists=$(yq e ".skills.$name // \"\"" "$REGISTRY_FILE")
|
||||
if [ -z "$exists" ] || [ "$exists" == "null" ]; then
|
||||
echo -e "${RED}技能不存在: $name${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
yq e -i ".skills.$name.$field = \"$value\"" "$REGISTRY_FILE"
|
||||
yq e -i ".updated_at = \"$(date -u +"%Y-%m-%dT%H:%M:%SZ")\"" "$REGISTRY_FILE"
|
||||
|
||||
echo -e "${GREEN}✓ 已更新 $name.$field = $value${NC}"
|
||||
}
|
||||
|
||||
# 主命令分发
|
||||
case "${1:-list}" in
|
||||
list)
|
||||
cmd_list
|
||||
;;
|
||||
get)
|
||||
cmd_get "$2"
|
||||
;;
|
||||
add)
|
||||
cmd_add "$2" "$3" "$4"
|
||||
;;
|
||||
remove)
|
||||
cmd_remove "$2"
|
||||
;;
|
||||
update)
|
||||
cmd_update "$2" "$3" "$4"
|
||||
;;
|
||||
*)
|
||||
echo "用法: registry.sh <command> [args]"
|
||||
echo ""
|
||||
echo "命令:"
|
||||
echo " list 列出所有技能"
|
||||
echo " get <name> 获取技能信息"
|
||||
echo " add <name> <repo> 添加技能记录"
|
||||
echo " remove <name> 移除技能记录"
|
||||
echo " update <name> <f> <v> 更新字段"
|
||||
;;
|
||||
esac
|
||||
306
skills-workflow/skill-manager-plugin/scripts/git-ops.sh
Executable file
306
skills-workflow/skill-manager-plugin/scripts/git-ops.sh
Executable file
@@ -0,0 +1,306 @@
|
||||
#!/bin/bash
|
||||
# git-ops.sh - Git 操作封装
|
||||
# 用法:
|
||||
# ./git-ops.sh clone <repo> <name> - 克隆仓库
|
||||
# ./git-ops.sh pull <name> - 拉取更新
|
||||
# ./git-ops.sh checkout <name> <ref> - 切换版本
|
||||
# ./git-ops.sh fetch <name> - 获取远程更新
|
||||
# ./git-ops.sh status <name> - 查看状态
|
||||
# ./git-ops.sh has-updates <name> - 检查是否有更新
|
||||
|
||||
set -e
|
||||
|
||||
SKILLS_DIR="$HOME/.claude/skills"
|
||||
REPOS_DIR="$SKILLS_DIR/repos"
|
||||
REGISTRY_SCRIPT="$SKILLS_DIR/skill-manager/scripts/registry.sh"
|
||||
|
||||
# 颜色定义
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
# 从 URL 提取技能名称
|
||||
extract_name() {
|
||||
local repo="$1"
|
||||
# 处理各种格式
|
||||
# https://github.com/org/skill-name.git -> skill-name
|
||||
# git@github.com:org/skill-name.git -> skill-name
|
||||
echo "$repo" | sed -E 's|.*/([^/]+)(\.git)?$|\1|' | sed 's/\.git$//'
|
||||
}
|
||||
|
||||
# 克隆仓库
|
||||
cmd_clone() {
|
||||
local repo="$1"
|
||||
local name="${2:-$(extract_name "$repo")}"
|
||||
|
||||
if [ -z "$repo" ]; then
|
||||
echo -e "${RED}用法: git-ops.sh clone <repo> [name]${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local target_dir="$REPOS_DIR/$name"
|
||||
|
||||
# 检查是否已存在
|
||||
if [ -d "$target_dir" ]; then
|
||||
echo -e "${YELLOW}技能已存在: $name${NC}"
|
||||
echo "使用 'git-ops.sh pull $name' 更新"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}克隆技能: $name${NC}"
|
||||
echo "仓库: $repo"
|
||||
echo "目标: $target_dir"
|
||||
echo "----------------------------------------"
|
||||
|
||||
# 确保 repos 目录存在
|
||||
mkdir -p "$REPOS_DIR"
|
||||
|
||||
# 克隆仓库
|
||||
if git clone "$repo" "$target_dir"; then
|
||||
echo -e "${GREEN}✓ 克隆成功${NC}"
|
||||
|
||||
# 检查 skill.yaml
|
||||
if [ ! -f "$target_dir/skill.yaml" ]; then
|
||||
echo -e "${YELLOW}⚠ 警告: 未找到 skill.yaml${NC}"
|
||||
fi
|
||||
|
||||
# 获取版本
|
||||
local version="unknown"
|
||||
if [ -f "$target_dir/skill.yaml" ] && command -v yq &> /dev/null; then
|
||||
version=$(yq e '.version // "1.0.0"' "$target_dir/skill.yaml")
|
||||
fi
|
||||
|
||||
# 添加到 registry
|
||||
"$REGISTRY_SCRIPT" add "$name" "$repo" "$version"
|
||||
|
||||
echo -e "${GREEN}✓ 技能安装完成: $name ($version)${NC}"
|
||||
else
|
||||
echo -e "${RED}✗ 克隆失败${NC}"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 拉取更新
|
||||
cmd_pull() {
|
||||
local name="$1"
|
||||
|
||||
if [ -z "$name" ]; then
|
||||
echo -e "${RED}用法: git-ops.sh pull <name>${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local repo_dir="$REPOS_DIR/$name"
|
||||
|
||||
if [ ! -d "$repo_dir" ]; then
|
||||
echo -e "${RED}技能不存在: $name${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}更新技能: $name${NC}"
|
||||
echo "----------------------------------------"
|
||||
|
||||
cd "$repo_dir"
|
||||
|
||||
# 获取当前版本
|
||||
local old_version="unknown"
|
||||
if [ -f "skill.yaml" ] && command -v yq &> /dev/null; then
|
||||
old_version=$(yq e '.version // "unknown"' skill.yaml)
|
||||
fi
|
||||
|
||||
# 拉取更新
|
||||
if git pull origin main 2>/dev/null || git pull origin master 2>/dev/null; then
|
||||
# 获取新版本
|
||||
local new_version="unknown"
|
||||
if [ -f "skill.yaml" ] && command -v yq &> /dev/null; then
|
||||
new_version=$(yq e '.version // "unknown"' skill.yaml)
|
||||
fi
|
||||
|
||||
if [ "$old_version" != "$new_version" ]; then
|
||||
echo -e "${GREEN}✓ 版本更新: $old_version → $new_version${NC}"
|
||||
"$REGISTRY_SCRIPT" update "$name" version "$new_version"
|
||||
else
|
||||
echo -e "${GREEN}✓ 已是最新版本: $new_version${NC}"
|
||||
fi
|
||||
|
||||
# 更新 last_updated
|
||||
"$REGISTRY_SCRIPT" update "$name" last_updated "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
||||
else
|
||||
echo -e "${RED}✗ 更新失败${NC}"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 切换版本
|
||||
cmd_checkout() {
|
||||
local name="$1"
|
||||
local ref="$2"
|
||||
|
||||
if [ -z "$name" ] || [ -z "$ref" ]; then
|
||||
echo -e "${RED}用法: git-ops.sh checkout <name> <ref>${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local repo_dir="$REPOS_DIR/$name"
|
||||
|
||||
if [ ! -d "$repo_dir" ]; then
|
||||
echo -e "${RED}技能不存在: $name${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}切换版本: $name → $ref${NC}"
|
||||
echo "----------------------------------------"
|
||||
|
||||
cd "$repo_dir"
|
||||
|
||||
# 获取当前版本
|
||||
local old_ref=$(git describe --tags --always 2>/dev/null || git rev-parse --short HEAD)
|
||||
|
||||
# 切换版本
|
||||
if git checkout "$ref" 2>/dev/null; then
|
||||
echo -e "${GREEN}✓ 版本切换: $old_ref → $ref${NC}"
|
||||
|
||||
# 更新 registry
|
||||
"$REGISTRY_SCRIPT" update "$name" version "$ref"
|
||||
"$REGISTRY_SCRIPT" update "$name" last_updated "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
||||
else
|
||||
echo -e "${RED}✗ 切换失败: $ref 不存在${NC}"
|
||||
echo "可用的 tag:"
|
||||
git tag -l | head -10
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 获取远程更新
|
||||
cmd_fetch() {
|
||||
local name="$1"
|
||||
|
||||
if [ -z "$name" ]; then
|
||||
echo -e "${RED}用法: git-ops.sh fetch <name>${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local repo_dir="$REPOS_DIR/$name"
|
||||
|
||||
if [ ! -d "$repo_dir" ]; then
|
||||
echo -e "${RED}技能不存在: $name${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "$repo_dir"
|
||||
git fetch origin --tags --quiet
|
||||
echo -e "${GREEN}✓ 已获取远程更新: $name${NC}"
|
||||
}
|
||||
|
||||
# 查看状态
|
||||
cmd_status() {
|
||||
local name="$1"
|
||||
|
||||
if [ -z "$name" ]; then
|
||||
echo -e "${RED}用法: git-ops.sh status <name>${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local repo_dir="$REPOS_DIR/$name"
|
||||
|
||||
if [ ! -d "$repo_dir" ]; then
|
||||
echo -e "${RED}技能不存在: $name${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}技能状态: $name${NC}"
|
||||
echo "----------------------------------------"
|
||||
|
||||
cd "$repo_dir"
|
||||
|
||||
local branch=$(git branch --show-current 2>/dev/null || echo "detached")
|
||||
local commit=$(git rev-parse --short HEAD)
|
||||
local remote_url=$(git config --get remote.origin.url)
|
||||
|
||||
echo "分支: $branch"
|
||||
echo "Commit: $commit"
|
||||
echo "远程: $remote_url"
|
||||
|
||||
if [ -f "skill.yaml" ] && command -v yq &> /dev/null; then
|
||||
local version=$(yq e '.version // "unknown"' skill.yaml)
|
||||
echo "版本: $version"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "最近提交:"
|
||||
git log --oneline -3
|
||||
}
|
||||
|
||||
# 检查是否有更新
|
||||
cmd_has_updates() {
|
||||
local name="$1"
|
||||
|
||||
if [ -z "$name" ]; then
|
||||
echo -e "${RED}用法: git-ops.sh has-updates <name>${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local repo_dir="$REPOS_DIR/$name"
|
||||
|
||||
if [ ! -d "$repo_dir" ]; then
|
||||
echo -e "${RED}技能不存在: $name${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "$repo_dir"
|
||||
|
||||
# 获取远程更新
|
||||
git fetch origin --quiet 2>/dev/null || true
|
||||
|
||||
# 比较本地和远程
|
||||
local local_head=$(git rev-parse HEAD)
|
||||
local remote_head=$(git rev-parse origin/main 2>/dev/null || git rev-parse origin/master 2>/dev/null || echo "")
|
||||
|
||||
if [ -z "$remote_head" ]; then
|
||||
echo "unknown"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$local_head" != "$remote_head" ]; then
|
||||
echo "yes"
|
||||
# 显示更新数量
|
||||
local behind=$(git rev-list HEAD..origin/main --count 2>/dev/null || git rev-list HEAD..origin/master --count 2>/dev/null || echo "0")
|
||||
echo "behind: $behind commits"
|
||||
else
|
||||
echo "no"
|
||||
fi
|
||||
}
|
||||
|
||||
# 主命令分发
|
||||
case "${1:-help}" in
|
||||
clone)
|
||||
cmd_clone "$2" "$3"
|
||||
;;
|
||||
pull)
|
||||
cmd_pull "$2"
|
||||
;;
|
||||
checkout)
|
||||
cmd_checkout "$2" "$3"
|
||||
;;
|
||||
fetch)
|
||||
cmd_fetch "$2"
|
||||
;;
|
||||
status)
|
||||
cmd_status "$2"
|
||||
;;
|
||||
has-updates)
|
||||
cmd_has_updates "$2"
|
||||
;;
|
||||
*)
|
||||
echo "用法: git-ops.sh <command> [args]"
|
||||
echo ""
|
||||
echo "命令:"
|
||||
echo " clone <repo> [name] 克隆仓库"
|
||||
echo " pull <name> 拉取更新"
|
||||
echo " checkout <name> <ref> 切换版本"
|
||||
echo " fetch <name> 获取远程更新"
|
||||
echo " status <name> 查看状态"
|
||||
echo " has-updates <name> 检查是否有更新"
|
||||
;;
|
||||
esac
|
||||
58
skills-workflow/skill-manager-plugin/scripts/init-registry.sh
Executable file
58
skills-workflow/skill-manager-plugin/scripts/init-registry.sh
Executable file
@@ -0,0 +1,58 @@
|
||||
#!/bin/bash
|
||||
# init-registry.sh - 初始化技能注册表
|
||||
# 用法: ./init-registry.sh
|
||||
|
||||
set -e
|
||||
|
||||
SKILLS_DIR="$HOME/.claude/skills"
|
||||
REGISTRY_FILE="$SKILLS_DIR/registry.yaml"
|
||||
REPOS_DIR="$SKILLS_DIR/repos"
|
||||
|
||||
# 颜色定义
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
echo "初始化 Skills Registry..."
|
||||
echo "----------------------------------------"
|
||||
|
||||
# 创建 repos 目录
|
||||
if [ ! -d "$REPOS_DIR" ]; then
|
||||
mkdir -p "$REPOS_DIR"
|
||||
echo -e "${GREEN}✓ 创建 repos 目录${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}⚠ repos 目录已存在${NC}"
|
||||
fi
|
||||
|
||||
# 创建 registry.yaml
|
||||
if [ ! -f "$REGISTRY_FILE" ]; then
|
||||
cat > "$REGISTRY_FILE" << 'EOF'
|
||||
# Skills Registry - 技能注册表
|
||||
# 由 skill-manager 自动管理,请勿手动编辑
|
||||
|
||||
version: 1
|
||||
updated_at: $(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
||||
|
||||
# 全局配置
|
||||
config:
|
||||
auto_update_check: true # 启动时检查更新
|
||||
update_check_interval: 86400 # 检查间隔(秒),默认24小时
|
||||
default_branch: main # 默认分支
|
||||
|
||||
# 已安装技能
|
||||
skills: {}
|
||||
EOF
|
||||
# 替换日期
|
||||
sed -i '' "s/\$(date -u +\"%Y-%m-%dT%H:%M:%SZ\")/$(date -u +"%Y-%m-%dT%H:%M:%SZ")/" "$REGISTRY_FILE"
|
||||
echo -e "${GREEN}✓ 创建 registry.yaml${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}⚠ registry.yaml 已存在${NC}"
|
||||
fi
|
||||
|
||||
echo "----------------------------------------"
|
||||
echo -e "${GREEN}✓ 初始化完成${NC}"
|
||||
echo ""
|
||||
echo "目录结构:"
|
||||
echo " $SKILLS_DIR/"
|
||||
echo " ├── registry.yaml"
|
||||
echo " └── repos/"
|
||||
204
skills-workflow/skill-manager-plugin/scripts/registry.sh
Executable file
204
skills-workflow/skill-manager-plugin/scripts/registry.sh
Executable file
@@ -0,0 +1,204 @@
|
||||
#!/bin/bash
|
||||
# registry.sh - Registry 管理工具
|
||||
# 用法:
|
||||
# ./registry.sh list - 列出所有技能
|
||||
# ./registry.sh get <name> - 获取技能信息
|
||||
# ./registry.sh add <name> <repo> - 添加技能记录
|
||||
# ./registry.sh remove <name> - 移除技能记录
|
||||
# ./registry.sh update <name> <field> <value> - 更新字段
|
||||
|
||||
set -e
|
||||
|
||||
SKILLS_DIR="$HOME/.claude/skills"
|
||||
REGISTRY_FILE="$SKILLS_DIR/registry.yaml"
|
||||
|
||||
# 颜色定义
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
# 检查 yq 是否安装
|
||||
check_yq() {
|
||||
if ! command -v yq &> /dev/null; then
|
||||
echo -e "${RED}错误: 需要安装 yq${NC}"
|
||||
echo "安装方法: brew install yq"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 检查 registry 文件
|
||||
check_registry() {
|
||||
if [ ! -f "$REGISTRY_FILE" ]; then
|
||||
echo -e "${YELLOW}Registry 不存在,正在初始化...${NC}"
|
||||
"$SKILLS_DIR/skill-manager/scripts/init-registry.sh"
|
||||
fi
|
||||
}
|
||||
|
||||
# 列出所有技能
|
||||
cmd_list() {
|
||||
check_yq
|
||||
check_registry
|
||||
|
||||
echo -e "${BLUE}已安装技能:${NC}"
|
||||
echo "----------------------------------------"
|
||||
|
||||
SKILLS=$(yq e '.skills | keys | .[]' "$REGISTRY_FILE" 2>/dev/null || echo "")
|
||||
|
||||
if [ -z "$SKILLS" ]; then
|
||||
echo "(无已安装技能)"
|
||||
return
|
||||
fi
|
||||
|
||||
printf "%-20s %-10s %-10s %s\n" "名称" "版本" "状态" "最后更新"
|
||||
echo "----------------------------------------"
|
||||
|
||||
for skill in $SKILLS; do
|
||||
VERSION=$(yq e ".skills.$skill.version // \"unknown\"" "$REGISTRY_FILE")
|
||||
STATUS=$(yq e ".skills.$skill.status // \"unknown\"" "$REGISTRY_FILE")
|
||||
UPDATED=$(yq e ".skills.$skill.last_updated // \"unknown\"" "$REGISTRY_FILE" | cut -d'T' -f1)
|
||||
|
||||
# 状态颜色
|
||||
case $STATUS in
|
||||
active) STATUS_COLOR="${GREEN}$STATUS${NC}" ;;
|
||||
disabled) STATUS_COLOR="${YELLOW}$STATUS${NC}" ;;
|
||||
error) STATUS_COLOR="${RED}$STATUS${NC}" ;;
|
||||
*) STATUS_COLOR="$STATUS" ;;
|
||||
esac
|
||||
|
||||
printf "%-20s %-10s " "$skill" "$VERSION"
|
||||
echo -e "$STATUS_COLOR\t$UPDATED"
|
||||
done
|
||||
}
|
||||
|
||||
# 获取技能信息
|
||||
cmd_get() {
|
||||
check_yq
|
||||
check_registry
|
||||
|
||||
local name="$1"
|
||||
if [ -z "$name" ]; then
|
||||
echo -e "${RED}用法: registry.sh get <name>${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local exists=$(yq e ".skills.$name // \"\"" "$REGISTRY_FILE")
|
||||
if [ -z "$exists" ] || [ "$exists" == "null" ]; then
|
||||
echo -e "${RED}技能不存在: $name${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}技能: $name${NC}"
|
||||
echo "----------------------------------------"
|
||||
yq e ".skills.$name" "$REGISTRY_FILE"
|
||||
}
|
||||
|
||||
# 添加技能记录
|
||||
cmd_add() {
|
||||
check_yq
|
||||
check_registry
|
||||
|
||||
local name="$1"
|
||||
local repo="$2"
|
||||
local version="${3:-1.0.0}"
|
||||
|
||||
if [ -z "$name" ] || [ -z "$repo" ]; then
|
||||
echo -e "${RED}用法: registry.sh add <name> <repo> [version]${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local now=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
||||
local local_path="$SKILLS_DIR/repos/$name"
|
||||
|
||||
# 添加技能记录
|
||||
yq e -i ".skills.$name.repo = \"$repo\"" "$REGISTRY_FILE"
|
||||
yq e -i ".skills.$name.local_path = \"$local_path\"" "$REGISTRY_FILE"
|
||||
yq e -i ".skills.$name.version = \"$version\"" "$REGISTRY_FILE"
|
||||
yq e -i ".skills.$name.installed_at = \"$now\"" "$REGISTRY_FILE"
|
||||
yq e -i ".skills.$name.last_updated = \"$now\"" "$REGISTRY_FILE"
|
||||
yq e -i ".skills.$name.status = \"active\"" "$REGISTRY_FILE"
|
||||
|
||||
# 更新 registry 时间
|
||||
yq e -i ".updated_at = \"$now\"" "$REGISTRY_FILE"
|
||||
|
||||
echo -e "${GREEN}✓ 已添加技能: $name${NC}"
|
||||
}
|
||||
|
||||
# 移除技能记录
|
||||
cmd_remove() {
|
||||
check_yq
|
||||
check_registry
|
||||
|
||||
local name="$1"
|
||||
if [ -z "$name" ]; then
|
||||
echo -e "${RED}用法: registry.sh remove <name>${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local exists=$(yq e ".skills.$name // \"\"" "$REGISTRY_FILE")
|
||||
if [ -z "$exists" ] || [ "$exists" == "null" ]; then
|
||||
echo -e "${YELLOW}技能不存在: $name${NC}"
|
||||
return
|
||||
fi
|
||||
|
||||
yq e -i "del(.skills.$name)" "$REGISTRY_FILE"
|
||||
yq e -i ".updated_at = \"$(date -u +"%Y-%m-%dT%H:%M:%SZ")\"" "$REGISTRY_FILE"
|
||||
|
||||
echo -e "${GREEN}✓ 已移除技能: $name${NC}"
|
||||
}
|
||||
|
||||
# 更新技能字段
|
||||
cmd_update() {
|
||||
check_yq
|
||||
check_registry
|
||||
|
||||
local name="$1"
|
||||
local field="$2"
|
||||
local value="$3"
|
||||
|
||||
if [ -z "$name" ] || [ -z "$field" ] || [ -z "$value" ]; then
|
||||
echo -e "${RED}用法: registry.sh update <name> <field> <value>${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local exists=$(yq e ".skills.$name // \"\"" "$REGISTRY_FILE")
|
||||
if [ -z "$exists" ] || [ "$exists" == "null" ]; then
|
||||
echo -e "${RED}技能不存在: $name${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
yq e -i ".skills.$name.$field = \"$value\"" "$REGISTRY_FILE"
|
||||
yq e -i ".updated_at = \"$(date -u +"%Y-%m-%dT%H:%M:%SZ")\"" "$REGISTRY_FILE"
|
||||
|
||||
echo -e "${GREEN}✓ 已更新 $name.$field = $value${NC}"
|
||||
}
|
||||
|
||||
# 主命令分发
|
||||
case "${1:-list}" in
|
||||
list)
|
||||
cmd_list
|
||||
;;
|
||||
get)
|
||||
cmd_get "$2"
|
||||
;;
|
||||
add)
|
||||
cmd_add "$2" "$3" "$4"
|
||||
;;
|
||||
remove)
|
||||
cmd_remove "$2"
|
||||
;;
|
||||
update)
|
||||
cmd_update "$2" "$3" "$4"
|
||||
;;
|
||||
*)
|
||||
echo "用法: registry.sh <command> [args]"
|
||||
echo ""
|
||||
echo "命令:"
|
||||
echo " list 列出所有技能"
|
||||
echo " get <name> 获取技能信息"
|
||||
echo " add <name> <repo> 添加技能记录"
|
||||
echo " remove <name> 移除技能记录"
|
||||
echo " update <name> <f> <v> 更新字段"
|
||||
;;
|
||||
esac
|
||||
393
skills-workflow/skill-manager-plugin/scripts/skill.sh
Executable file
393
skills-workflow/skill-manager-plugin/scripts/skill.sh
Executable file
@@ -0,0 +1,393 @@
|
||||
#!/bin/bash
|
||||
# skill.sh - Skills 管理器主入口
|
||||
# 用法:
|
||||
# ./skill.sh list - 列出已安装技能
|
||||
# ./skill.sh install <repo> - 安装新技能
|
||||
# ./skill.sh upgrade [name] - 升级技能
|
||||
# ./skill.sh uninstall <name> - 卸载技能
|
||||
# ./skill.sh rollback <name> <version> - 回滚版本
|
||||
# ./skill.sh info <name> - 查看技能详情
|
||||
# ./skill.sh enable <name> - 启用技能
|
||||
# ./skill.sh disable <name> - 禁用技能
|
||||
# ./skill.sh check - 检查所有技能更新
|
||||
|
||||
set -e
|
||||
|
||||
SKILLS_DIR="$HOME/.claude/skills"
|
||||
REPOS_DIR="$SKILLS_DIR/repos"
|
||||
SCRIPTS_DIR="$SKILLS_DIR/skill-manager/scripts"
|
||||
REGISTRY_SCRIPT="$SCRIPTS_DIR/registry.sh"
|
||||
GIT_OPS_SCRIPT="$SCRIPTS_DIR/git-ops.sh"
|
||||
|
||||
# 颜色定义
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
CYAN='\033[0;36m'
|
||||
NC='\033[0m'
|
||||
|
||||
# 显示 banner
|
||||
show_banner() {
|
||||
echo -e "${CYAN}"
|
||||
echo "╔═══════════════════════════════════════╗"
|
||||
echo "║ Skills Manager v1.0.0 ║"
|
||||
echo "║ 自我进化技能管理器 ║"
|
||||
echo "╚═══════════════════════════════════════╝"
|
||||
echo -e "${NC}"
|
||||
}
|
||||
|
||||
# 从 URL 提取技能名称
|
||||
extract_name() {
|
||||
local repo="$1"
|
||||
echo "$repo" | sed -E 's|.*/([^/]+)(\.git)?$|\1|' | sed 's/\.git$//'
|
||||
}
|
||||
|
||||
# 列出所有技能
|
||||
cmd_list() {
|
||||
echo -e "${BLUE}已安装技能:${NC}"
|
||||
echo "════════════════════════════════════════"
|
||||
"$REGISTRY_SCRIPT" list
|
||||
}
|
||||
|
||||
# 安装技能
|
||||
cmd_install() {
|
||||
local repo="$1"
|
||||
|
||||
if [ -z "$repo" ]; then
|
||||
echo -e "${RED}用法: skill install <repo>${NC}"
|
||||
echo "示例: skill install https://github.com/org/skill-name.git"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local name=$(extract_name "$repo")
|
||||
|
||||
echo -e "${BLUE}安装技能: $name${NC}"
|
||||
echo "════════════════════════════════════════"
|
||||
|
||||
# 检查是否已安装
|
||||
if [ -d "$REPOS_DIR/$name" ]; then
|
||||
echo -e "${YELLOW}技能已安装,使用 'skill upgrade $name' 更新${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 克隆仓库
|
||||
"$GIT_OPS_SCRIPT" clone "$repo" "$name"
|
||||
|
||||
# 验证 skill.yaml
|
||||
local skill_yaml="$REPOS_DIR/$name/skill.yaml"
|
||||
if [ -f "$skill_yaml" ]; then
|
||||
"$SCRIPTS_DIR/validate.sh" "$REPOS_DIR/$name"
|
||||
fi
|
||||
|
||||
# 创建符号链接到 skills 目录
|
||||
local skill_dir="$SKILLS_DIR/$name"
|
||||
if [ ! -d "$skill_dir" ]; then
|
||||
mkdir -p "$skill_dir"
|
||||
# 复制 SKILL.md
|
||||
local prompt_file=$(yq e '.prompt_file // "SKILL.md"' "$skill_yaml" 2>/dev/null || echo "SKILL.md")
|
||||
if [ -f "$REPOS_DIR/$name/$prompt_file" ]; then
|
||||
cp "$REPOS_DIR/$name/$prompt_file" "$skill_dir/SKILL.md"
|
||||
fi
|
||||
fi
|
||||
|
||||
# 执行 post_install 钩子
|
||||
if command -v yq &> /dev/null && [ -f "$skill_yaml" ]; then
|
||||
local hooks=$(yq e '.hooks.post_install[]' "$skill_yaml" 2>/dev/null || echo "")
|
||||
if [ -n "$hooks" ]; then
|
||||
echo -e "${YELLOW}执行安装后钩子...${NC}"
|
||||
echo "$hooks" | while read -r cmd; do
|
||||
[ -n "$cmd" ] && eval "$cmd"
|
||||
done
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}✓ 技能安装完成: $name${NC}"
|
||||
}
|
||||
|
||||
# 升级技能
|
||||
cmd_upgrade() {
|
||||
local name="$1"
|
||||
|
||||
echo -e "${BLUE}升级技能${NC}"
|
||||
echo "════════════════════════════════════════"
|
||||
|
||||
if [ -z "$name" ]; then
|
||||
# 升级所有技能
|
||||
echo "升级所有技能..."
|
||||
local skills=$(ls -1 "$REPOS_DIR" 2>/dev/null || echo "")
|
||||
|
||||
if [ -z "$skills" ]; then
|
||||
echo "没有已安装的技能"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
for skill in $skills; do
|
||||
echo ""
|
||||
echo -e "${CYAN}>>> $skill${NC}"
|
||||
"$GIT_OPS_SCRIPT" pull "$skill" || echo -e "${YELLOW}跳过 $skill${NC}"
|
||||
done
|
||||
else
|
||||
# 升级指定技能
|
||||
if [ ! -d "$REPOS_DIR/$name" ]; then
|
||||
echo -e "${RED}技能不存在: $name${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
"$GIT_OPS_SCRIPT" pull "$name"
|
||||
|
||||
# 同步 SKILL.md
|
||||
local skill_yaml="$REPOS_DIR/$name/skill.yaml"
|
||||
if [ -f "$skill_yaml" ]; then
|
||||
local prompt_file=$(yq e '.prompt_file // "SKILL.md"' "$skill_yaml" 2>/dev/null || echo "SKILL.md")
|
||||
if [ -f "$REPOS_DIR/$name/$prompt_file" ]; then
|
||||
mkdir -p "$SKILLS_DIR/$name"
|
||||
cp "$REPOS_DIR/$name/$prompt_file" "$SKILLS_DIR/$name/SKILL.md"
|
||||
fi
|
||||
|
||||
# 执行 post_update 钩子
|
||||
local hooks=$(yq e '.hooks.post_update[]' "$skill_yaml" 2>/dev/null || echo "")
|
||||
if [ -n "$hooks" ]; then
|
||||
echo -e "${YELLOW}执行更新后钩子...${NC}"
|
||||
echo "$hooks" | while read -r cmd; do
|
||||
[ -n "$cmd" ] && eval "$cmd"
|
||||
done
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}✓ 升级完成${NC}"
|
||||
}
|
||||
|
||||
# 卸载技能
|
||||
cmd_uninstall() {
|
||||
local name="$1"
|
||||
|
||||
if [ -z "$name" ]; then
|
||||
echo -e "${RED}用法: skill uninstall <name>${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}卸载技能: $name${NC}"
|
||||
echo "════════════════════════════════════════"
|
||||
|
||||
if [ ! -d "$REPOS_DIR/$name" ]; then
|
||||
echo -e "${YELLOW}技能不存在: $name${NC}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 确认
|
||||
echo -e "${YELLOW}确认卸载 $name? [y/N]${NC}"
|
||||
read -r confirm
|
||||
if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then
|
||||
echo "取消卸载"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 执行 post_uninstall 钩子
|
||||
local skill_yaml="$REPOS_DIR/$name/skill.yaml"
|
||||
if command -v yq &> /dev/null && [ -f "$skill_yaml" ]; then
|
||||
local hooks=$(yq e '.hooks.post_uninstall[]' "$skill_yaml" 2>/dev/null || echo "")
|
||||
if [ -n "$hooks" ]; then
|
||||
echo -e "${YELLOW}执行卸载钩子...${NC}"
|
||||
echo "$hooks" | while read -r cmd; do
|
||||
[ -n "$cmd" ] && eval "$cmd"
|
||||
done
|
||||
fi
|
||||
fi
|
||||
|
||||
# 删除仓库
|
||||
rm -rf "$REPOS_DIR/$name"
|
||||
echo -e "${GREEN}✓ 已删除仓库: $REPOS_DIR/$name${NC}"
|
||||
|
||||
# 删除技能目录
|
||||
rm -rf "$SKILLS_DIR/$name"
|
||||
echo -e "${GREEN}✓ 已删除技能目录: $SKILLS_DIR/$name${NC}"
|
||||
|
||||
# 从 registry 移除
|
||||
"$REGISTRY_SCRIPT" remove "$name"
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}✓ 技能已卸载: $name${NC}"
|
||||
}
|
||||
|
||||
# 回滚版本
|
||||
cmd_rollback() {
|
||||
local name="$1"
|
||||
local version="$2"
|
||||
|
||||
if [ -z "$name" ] || [ -z "$version" ]; then
|
||||
echo -e "${RED}用法: skill rollback <name> <version>${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}回滚技能: $name → $version${NC}"
|
||||
echo "════════════════════════════════════════"
|
||||
|
||||
"$GIT_OPS_SCRIPT" checkout "$name" "$version"
|
||||
|
||||
# 同步 SKILL.md
|
||||
local skill_yaml="$REPOS_DIR/$name/skill.yaml"
|
||||
if [ -f "$skill_yaml" ]; then
|
||||
local prompt_file=$(yq e '.prompt_file // "SKILL.md"' "$skill_yaml" 2>/dev/null || echo "SKILL.md")
|
||||
if [ -f "$REPOS_DIR/$name/$prompt_file" ]; then
|
||||
mkdir -p "$SKILLS_DIR/$name"
|
||||
cp "$REPOS_DIR/$name/$prompt_file" "$SKILLS_DIR/$name/SKILL.md"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}✓ 回滚完成${NC}"
|
||||
}
|
||||
|
||||
# 查看技能详情
|
||||
cmd_info() {
|
||||
local name="$1"
|
||||
|
||||
if [ -z "$name" ]; then
|
||||
echo -e "${RED}用法: skill info <name>${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}技能详情: $name${NC}"
|
||||
echo "════════════════════════════════════════"
|
||||
|
||||
"$GIT_OPS_SCRIPT" status "$name"
|
||||
|
||||
# 显示 skill.yaml 信息
|
||||
local skill_yaml="$REPOS_DIR/$name/skill.yaml"
|
||||
if [ -f "$skill_yaml" ] && command -v yq &> /dev/null; then
|
||||
echo ""
|
||||
echo "技能配置:"
|
||||
echo "----------------------------------------"
|
||||
echo "描述: $(yq e '.description' "$skill_yaml" | head -1)"
|
||||
echo "作者: $(yq e '.author // "未知"' "$skill_yaml")"
|
||||
|
||||
local deps=$(yq e '.dependencies[]' "$skill_yaml" 2>/dev/null || echo "")
|
||||
if [ -n "$deps" ]; then
|
||||
echo "依赖: $deps"
|
||||
fi
|
||||
|
||||
local keywords=$(yq e '.triggers.keywords[]' "$skill_yaml" 2>/dev/null | tr '\n' ', ' | sed 's/,$//')
|
||||
if [ -n "$keywords" ]; then
|
||||
echo "关键词: $keywords"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# 启用技能
|
||||
cmd_enable() {
|
||||
local name="$1"
|
||||
|
||||
if [ -z "$name" ]; then
|
||||
echo -e "${RED}用法: skill enable <name>${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
"$REGISTRY_SCRIPT" update "$name" status "active"
|
||||
echo -e "${GREEN}✓ 已启用技能: $name${NC}"
|
||||
}
|
||||
|
||||
# 禁用技能
|
||||
cmd_disable() {
|
||||
local name="$1"
|
||||
|
||||
if [ -z "$name" ]; then
|
||||
echo -e "${RED}用法: skill disable <name>${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
"$REGISTRY_SCRIPT" update "$name" status "disabled"
|
||||
echo -e "${GREEN}✓ 已禁用技能: $name${NC}"
|
||||
}
|
||||
|
||||
# 检查更新
|
||||
cmd_check() {
|
||||
echo -e "${BLUE}检查技能更新${NC}"
|
||||
echo "════════════════════════════════════════"
|
||||
|
||||
local skills=$(ls -1 "$REPOS_DIR" 2>/dev/null || echo "")
|
||||
|
||||
if [ -z "$skills" ]; then
|
||||
echo "没有已安装的技能"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
local has_updates=0
|
||||
|
||||
for skill in $skills; do
|
||||
local result=$("$GIT_OPS_SCRIPT" has-updates "$skill" 2>/dev/null | head -1)
|
||||
if [ "$result" == "yes" ]; then
|
||||
local behind=$("$GIT_OPS_SCRIPT" has-updates "$skill" 2>/dev/null | tail -1)
|
||||
echo -e "${YELLOW}✓ $skill 有更新 ($behind)${NC}"
|
||||
has_updates=1
|
||||
else
|
||||
echo -e "${GREEN}✓ $skill 已是最新${NC}"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
if [ $has_updates -eq 1 ]; then
|
||||
echo -e "${YELLOW}执行 'skill upgrade' 升级所有技能${NC}"
|
||||
else
|
||||
echo -e "${GREEN}所有技能已是最新版本${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
# 主命令分发
|
||||
case "${1:-help}" in
|
||||
list|ls)
|
||||
cmd_list
|
||||
;;
|
||||
install|add)
|
||||
cmd_install "$2"
|
||||
;;
|
||||
upgrade|update)
|
||||
cmd_upgrade "$2"
|
||||
;;
|
||||
uninstall|remove)
|
||||
cmd_uninstall "$2"
|
||||
;;
|
||||
rollback)
|
||||
cmd_rollback "$2" "$3"
|
||||
;;
|
||||
info|show)
|
||||
cmd_info "$2"
|
||||
;;
|
||||
enable)
|
||||
cmd_enable "$2"
|
||||
;;
|
||||
disable)
|
||||
cmd_disable "$2"
|
||||
;;
|
||||
check)
|
||||
cmd_check
|
||||
;;
|
||||
help|--help|-h)
|
||||
show_banner
|
||||
echo "用法: skill <command> [args]"
|
||||
echo ""
|
||||
echo "命令:"
|
||||
echo " list 列出已安装技能"
|
||||
echo " install <repo> 安装新技能"
|
||||
echo " upgrade [name] 升级技能(不指定则升级全部)"
|
||||
echo " uninstall <name> 卸载技能"
|
||||
echo " rollback <name> <version> 回滚到指定版本"
|
||||
echo " info <name> 查看技能详情"
|
||||
echo " enable <name> 启用技能"
|
||||
echo " disable <name> 禁用技能"
|
||||
echo " check 检查所有技能更新"
|
||||
echo ""
|
||||
echo "示例:"
|
||||
echo " skill install https://github.com/org/skill-name.git"
|
||||
echo " skill upgrade coolbuy-paas"
|
||||
echo " skill rollback coolbuy-paas v1.1.0"
|
||||
;;
|
||||
*)
|
||||
echo -e "${RED}未知命令: $1${NC}"
|
||||
echo "使用 'skill help' 查看帮助"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
88
skills-workflow/skill-manager-plugin/scripts/validate.sh
Executable file
88
skills-workflow/skill-manager-plugin/scripts/validate.sh
Executable file
@@ -0,0 +1,88 @@
|
||||
#!/bin/bash
|
||||
# validate.sh - 验证 skill.yaml 格式
|
||||
# 用法: ./validate.sh <skill-directory>
|
||||
|
||||
set -e
|
||||
|
||||
SKILL_DIR="${1:-.}"
|
||||
SKILL_YAML="$SKILL_DIR/skill.yaml"
|
||||
|
||||
# 颜色定义
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
echo "验证技能目录: $SKILL_DIR"
|
||||
echo "----------------------------------------"
|
||||
|
||||
# 检查 skill.yaml 是否存在
|
||||
if [ ! -f "$SKILL_YAML" ]; then
|
||||
echo -e "${RED}✗ skill.yaml 不存在${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}✓ skill.yaml 存在${NC}"
|
||||
|
||||
# 检查 YAML 格式(需要 yq 或 python)
|
||||
if command -v yq &> /dev/null; then
|
||||
if ! yq e '.' "$SKILL_YAML" > /dev/null 2>&1; then
|
||||
echo -e "${RED}✗ YAML 格式错误${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}✓ YAML 格式正确${NC}"
|
||||
|
||||
# 检查必填字段
|
||||
NAME=$(yq e '.name' "$SKILL_YAML")
|
||||
VERSION=$(yq e '.version' "$SKILL_YAML")
|
||||
DESCRIPTION=$(yq e '.description' "$SKILL_YAML")
|
||||
|
||||
if [ "$NAME" == "null" ] || [ -z "$NAME" ]; then
|
||||
echo -e "${RED}✗ 缺少必填字段: name${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}✓ name: $NAME${NC}"
|
||||
|
||||
if [ "$VERSION" == "null" ] || [ -z "$VERSION" ]; then
|
||||
echo -e "${RED}✗ 缺少必填字段: version${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}✓ version: $VERSION${NC}"
|
||||
|
||||
if [ "$DESCRIPTION" == "null" ] || [ -z "$DESCRIPTION" ]; then
|
||||
echo -e "${RED}✗ 缺少必填字段: description${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}✓ description: 已设置${NC}"
|
||||
|
||||
# 验证 name 格式
|
||||
if ! echo "$NAME" | grep -qE '^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$'; then
|
||||
echo -e "${RED}✗ name 格式错误: 只能包含小写字母、数字、连字符${NC}"
|
||||
exit 1
|
||||
fi
|
||||
if [ ${#NAME} -gt 64 ]; then
|
||||
echo -e "${RED}✗ name 超过 64 字符${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}✓ name 格式正确${NC}"
|
||||
|
||||
# 检查 prompt_file
|
||||
PROMPT_FILE=$(yq e '.prompt_file // "SKILL.md"' "$SKILL_YAML")
|
||||
if [ ! -f "$SKILL_DIR/$PROMPT_FILE" ]; then
|
||||
echo -e "${YELLOW}⚠ prompt_file 不存在: $PROMPT_FILE${NC}"
|
||||
else
|
||||
echo -e "${GREEN}✓ prompt_file: $PROMPT_FILE${NC}"
|
||||
fi
|
||||
|
||||
elif command -v python3 &> /dev/null; then
|
||||
python3 -c "import yaml; yaml.safe_load(open('$SKILL_YAML'))" 2>/dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${RED}✗ YAML 格式错误${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}✓ YAML 格式正确 (使用 Python 验证)${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}⚠ 无法验证 YAML 格式 (需要 yq 或 python3)${NC}"
|
||||
fi
|
||||
|
||||
echo "----------------------------------------"
|
||||
echo -e "${GREEN}✓ 验证通过${NC}"
|
||||
157
skills-workflow/skill-manager-plugin/skill-yaml-spec.md
Normal file
157
skills-workflow/skill-manager-plugin/skill-yaml-spec.md
Normal file
@@ -0,0 +1,157 @@
|
||||
# skill.yaml 规范文档
|
||||
|
||||
## 概述
|
||||
|
||||
`skill.yaml` 是技能的元数据定义文件,位于技能仓库根目录。
|
||||
|
||||
## 字段定义
|
||||
|
||||
### 必填字段
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `name` | string | hyphen-case, ≤64字符 | 技能唯一标识 |
|
||||
| `version` | string | 语义化版本 | 当前版本号 |
|
||||
| `description` | string | ≤1024字符 | 技能描述 |
|
||||
|
||||
### 可选字段
|
||||
|
||||
| 字段 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| `author` | string | - | 作者/团队 |
|
||||
| `license` | string | - | 许可证 |
|
||||
| `triggers` | object | - | 触发条件 |
|
||||
| `prompt_file` | string | SKILL.md | 提示词文件 |
|
||||
| `dependencies` | array | [] | 依赖技能列表 |
|
||||
| `mcp_servers` | array | [] | MCP 服务器依赖 |
|
||||
| `hooks` | object | - | 生命周期钩子 |
|
||||
| `allowed_tools` | array | - | 允许的工具 |
|
||||
| `metadata` | object | - | 自定义元数据 |
|
||||
|
||||
## triggers 结构
|
||||
|
||||
```yaml
|
||||
triggers:
|
||||
# 关键词触发 - 用户输入包含这些词时激活
|
||||
keywords:
|
||||
- coolbuy-paas
|
||||
- 酷采
|
||||
|
||||
# 命令触发 - 用户输入以这些命令开头时激活
|
||||
commands:
|
||||
- /skill
|
||||
|
||||
# 文件模式触发 - 当前目录匹配时激活
|
||||
file_patterns:
|
||||
- "**/coolbuy-paas/**"
|
||||
```
|
||||
|
||||
## hooks 结构
|
||||
|
||||
```yaml
|
||||
hooks:
|
||||
# 安装后执行
|
||||
post_install:
|
||||
- "echo 'Installed'"
|
||||
- "npm install"
|
||||
|
||||
# 更新后执行
|
||||
post_update:
|
||||
- "echo 'Updated'"
|
||||
|
||||
# 卸载前执行
|
||||
post_uninstall:
|
||||
- "echo 'Goodbye'"
|
||||
```
|
||||
|
||||
## 完整示例
|
||||
|
||||
```yaml
|
||||
name: coolbuy-paas
|
||||
version: 1.2.0
|
||||
description: |
|
||||
酷采3.0 SaaS 租户端开发与测试。
|
||||
支持商品管理、订单管理等模块开发。
|
||||
author: your-team
|
||||
license: MIT
|
||||
|
||||
triggers:
|
||||
keywords:
|
||||
- coolbuy-paas
|
||||
- 酷采
|
||||
- 商品管理
|
||||
- 租户端
|
||||
file_patterns:
|
||||
- "**/coolbuy-paas/**"
|
||||
|
||||
prompt_file: SKILL.md
|
||||
|
||||
dependencies:
|
||||
- dev-coding
|
||||
- ops-tools
|
||||
|
||||
mcp_servers:
|
||||
- ai-proj
|
||||
- chrome-devtools
|
||||
|
||||
hooks:
|
||||
post_install:
|
||||
- "echo '✓ coolbuy-paas 技能安装完成'"
|
||||
post_update:
|
||||
- "echo '✓ coolbuy-paas 技能已更新'"
|
||||
|
||||
allowed_tools:
|
||||
- Bash
|
||||
- Read
|
||||
- Write
|
||||
- Edit
|
||||
- Glob
|
||||
- Grep
|
||||
|
||||
metadata:
|
||||
category: business
|
||||
tags:
|
||||
- saas
|
||||
- ecommerce
|
||||
- tenant
|
||||
min_claude_version: "1.0.0"
|
||||
project_repo: "https://github.com/org/coolbuy-paas"
|
||||
```
|
||||
|
||||
## 验证规则
|
||||
|
||||
1. **name**:
|
||||
- 只能包含小写字母、数字、连字符
|
||||
- 不能以连字符开头或结尾
|
||||
- 长度 1-64 字符
|
||||
|
||||
2. **version**:
|
||||
- 符合语义化版本规范 (SemVer)
|
||||
- 格式: MAJOR.MINOR.PATCH
|
||||
|
||||
3. **description**:
|
||||
- 长度不超过 1024 字符
|
||||
- 不能包含 `<` 或 `>` 字符
|
||||
|
||||
4. **prompt_file**:
|
||||
- 文件必须存在
|
||||
- 必须是 Markdown 格式
|
||||
|
||||
5. **dependencies**:
|
||||
- 每个依赖必须是有效的技能名称
|
||||
- 不能有循环依赖
|
||||
|
||||
## 与 Anthropic 官方规范对比
|
||||
|
||||
| 字段 | 官方规范 | 本规范 | 说明 |
|
||||
|------|----------|--------|------|
|
||||
| name | ✓ | ✓ | 相同 |
|
||||
| description | ✓ | ✓ | 相同 |
|
||||
| license | ✓ | ✓ | 相同 |
|
||||
| allowed-tools | ✓ | allowed_tools | 命名调整 |
|
||||
| metadata | ✓ | ✓ | 相同 |
|
||||
| version | ✗ | ✓ | 新增 |
|
||||
| triggers | ✗ | ✓ | 新增 |
|
||||
| dependencies | ✗ | ✓ | 新增 |
|
||||
| hooks | ✗ | ✓ | 新增 |
|
||||
| mcp_servers | ✗ | ✓ | 新增 |
|
||||
393
skills-workflow/skill-manager-plugin/skill.sh
Executable file
393
skills-workflow/skill-manager-plugin/skill.sh
Executable file
@@ -0,0 +1,393 @@
|
||||
#!/bin/bash
|
||||
# skill.sh - Skills 管理器主入口
|
||||
# 用法:
|
||||
# ./skill.sh list - 列出已安装技能
|
||||
# ./skill.sh install <repo> - 安装新技能
|
||||
# ./skill.sh upgrade [name] - 升级技能
|
||||
# ./skill.sh uninstall <name> - 卸载技能
|
||||
# ./skill.sh rollback <name> <version> - 回滚版本
|
||||
# ./skill.sh info <name> - 查看技能详情
|
||||
# ./skill.sh enable <name> - 启用技能
|
||||
# ./skill.sh disable <name> - 禁用技能
|
||||
# ./skill.sh check - 检查所有技能更新
|
||||
|
||||
set -e
|
||||
|
||||
SKILLS_DIR="$HOME/.claude/skills"
|
||||
REPOS_DIR="$SKILLS_DIR/repos"
|
||||
SCRIPTS_DIR="$SKILLS_DIR/skill-manager/scripts"
|
||||
REGISTRY_SCRIPT="$SCRIPTS_DIR/registry.sh"
|
||||
GIT_OPS_SCRIPT="$SCRIPTS_DIR/git-ops.sh"
|
||||
|
||||
# 颜色定义
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
CYAN='\033[0;36m'
|
||||
NC='\033[0m'
|
||||
|
||||
# 显示 banner
|
||||
show_banner() {
|
||||
echo -e "${CYAN}"
|
||||
echo "╔═══════════════════════════════════════╗"
|
||||
echo "║ Skills Manager v1.0.0 ║"
|
||||
echo "║ 自我进化技能管理器 ║"
|
||||
echo "╚═══════════════════════════════════════╝"
|
||||
echo -e "${NC}"
|
||||
}
|
||||
|
||||
# 从 URL 提取技能名称
|
||||
extract_name() {
|
||||
local repo="$1"
|
||||
echo "$repo" | sed -E 's|.*/([^/]+)(\.git)?$|\1|' | sed 's/\.git$//'
|
||||
}
|
||||
|
||||
# 列出所有技能
|
||||
cmd_list() {
|
||||
echo -e "${BLUE}已安装技能:${NC}"
|
||||
echo "════════════════════════════════════════"
|
||||
"$REGISTRY_SCRIPT" list
|
||||
}
|
||||
|
||||
# 安装技能
|
||||
cmd_install() {
|
||||
local repo="$1"
|
||||
|
||||
if [ -z "$repo" ]; then
|
||||
echo -e "${RED}用法: skill install <repo>${NC}"
|
||||
echo "示例: skill install https://github.com/org/skill-name.git"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local name=$(extract_name "$repo")
|
||||
|
||||
echo -e "${BLUE}安装技能: $name${NC}"
|
||||
echo "════════════════════════════════════════"
|
||||
|
||||
# 检查是否已安装
|
||||
if [ -d "$REPOS_DIR/$name" ]; then
|
||||
echo -e "${YELLOW}技能已安装,使用 'skill upgrade $name' 更新${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 克隆仓库
|
||||
"$GIT_OPS_SCRIPT" clone "$repo" "$name"
|
||||
|
||||
# 验证 skill.yaml
|
||||
local skill_yaml="$REPOS_DIR/$name/skill.yaml"
|
||||
if [ -f "$skill_yaml" ]; then
|
||||
"$SCRIPTS_DIR/validate.sh" "$REPOS_DIR/$name"
|
||||
fi
|
||||
|
||||
# 创建符号链接到 skills 目录
|
||||
local skill_dir="$SKILLS_DIR/$name"
|
||||
if [ ! -d "$skill_dir" ]; then
|
||||
mkdir -p "$skill_dir"
|
||||
# 复制 SKILL.md
|
||||
local prompt_file=$(yq e '.prompt_file // "SKILL.md"' "$skill_yaml" 2>/dev/null || echo "SKILL.md")
|
||||
if [ -f "$REPOS_DIR/$name/$prompt_file" ]; then
|
||||
cp "$REPOS_DIR/$name/$prompt_file" "$skill_dir/SKILL.md"
|
||||
fi
|
||||
fi
|
||||
|
||||
# 执行 post_install 钩子
|
||||
if command -v yq &> /dev/null && [ -f "$skill_yaml" ]; then
|
||||
local hooks=$(yq e '.hooks.post_install[]' "$skill_yaml" 2>/dev/null || echo "")
|
||||
if [ -n "$hooks" ]; then
|
||||
echo -e "${YELLOW}执行安装后钩子...${NC}"
|
||||
echo "$hooks" | while read -r cmd; do
|
||||
[ -n "$cmd" ] && eval "$cmd"
|
||||
done
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}✓ 技能安装完成: $name${NC}"
|
||||
}
|
||||
|
||||
# 升级技能
|
||||
cmd_upgrade() {
|
||||
local name="$1"
|
||||
|
||||
echo -e "${BLUE}升级技能${NC}"
|
||||
echo "════════════════════════════════════════"
|
||||
|
||||
if [ -z "$name" ]; then
|
||||
# 升级所有技能
|
||||
echo "升级所有技能..."
|
||||
local skills=$(ls -1 "$REPOS_DIR" 2>/dev/null || echo "")
|
||||
|
||||
if [ -z "$skills" ]; then
|
||||
echo "没有已安装的技能"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
for skill in $skills; do
|
||||
echo ""
|
||||
echo -e "${CYAN}>>> $skill${NC}"
|
||||
"$GIT_OPS_SCRIPT" pull "$skill" || echo -e "${YELLOW}跳过 $skill${NC}"
|
||||
done
|
||||
else
|
||||
# 升级指定技能
|
||||
if [ ! -d "$REPOS_DIR/$name" ]; then
|
||||
echo -e "${RED}技能不存在: $name${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
"$GIT_OPS_SCRIPT" pull "$name"
|
||||
|
||||
# 同步 SKILL.md
|
||||
local skill_yaml="$REPOS_DIR/$name/skill.yaml"
|
||||
if [ -f "$skill_yaml" ]; then
|
||||
local prompt_file=$(yq e '.prompt_file // "SKILL.md"' "$skill_yaml" 2>/dev/null || echo "SKILL.md")
|
||||
if [ -f "$REPOS_DIR/$name/$prompt_file" ]; then
|
||||
mkdir -p "$SKILLS_DIR/$name"
|
||||
cp "$REPOS_DIR/$name/$prompt_file" "$SKILLS_DIR/$name/SKILL.md"
|
||||
fi
|
||||
|
||||
# 执行 post_update 钩子
|
||||
local hooks=$(yq e '.hooks.post_update[]' "$skill_yaml" 2>/dev/null || echo "")
|
||||
if [ -n "$hooks" ]; then
|
||||
echo -e "${YELLOW}执行更新后钩子...${NC}"
|
||||
echo "$hooks" | while read -r cmd; do
|
||||
[ -n "$cmd" ] && eval "$cmd"
|
||||
done
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}✓ 升级完成${NC}"
|
||||
}
|
||||
|
||||
# 卸载技能
|
||||
cmd_uninstall() {
|
||||
local name="$1"
|
||||
|
||||
if [ -z "$name" ]; then
|
||||
echo -e "${RED}用法: skill uninstall <name>${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}卸载技能: $name${NC}"
|
||||
echo "════════════════════════════════════════"
|
||||
|
||||
if [ ! -d "$REPOS_DIR/$name" ]; then
|
||||
echo -e "${YELLOW}技能不存在: $name${NC}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 确认
|
||||
echo -e "${YELLOW}确认卸载 $name? [y/N]${NC}"
|
||||
read -r confirm
|
||||
if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then
|
||||
echo "取消卸载"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 执行 post_uninstall 钩子
|
||||
local skill_yaml="$REPOS_DIR/$name/skill.yaml"
|
||||
if command -v yq &> /dev/null && [ -f "$skill_yaml" ]; then
|
||||
local hooks=$(yq e '.hooks.post_uninstall[]' "$skill_yaml" 2>/dev/null || echo "")
|
||||
if [ -n "$hooks" ]; then
|
||||
echo -e "${YELLOW}执行卸载钩子...${NC}"
|
||||
echo "$hooks" | while read -r cmd; do
|
||||
[ -n "$cmd" ] && eval "$cmd"
|
||||
done
|
||||
fi
|
||||
fi
|
||||
|
||||
# 删除仓库
|
||||
rm -rf "$REPOS_DIR/$name"
|
||||
echo -e "${GREEN}✓ 已删除仓库: $REPOS_DIR/$name${NC}"
|
||||
|
||||
# 删除技能目录
|
||||
rm -rf "$SKILLS_DIR/$name"
|
||||
echo -e "${GREEN}✓ 已删除技能目录: $SKILLS_DIR/$name${NC}"
|
||||
|
||||
# 从 registry 移除
|
||||
"$REGISTRY_SCRIPT" remove "$name"
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}✓ 技能已卸载: $name${NC}"
|
||||
}
|
||||
|
||||
# 回滚版本
|
||||
cmd_rollback() {
|
||||
local name="$1"
|
||||
local version="$2"
|
||||
|
||||
if [ -z "$name" ] || [ -z "$version" ]; then
|
||||
echo -e "${RED}用法: skill rollback <name> <version>${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}回滚技能: $name → $version${NC}"
|
||||
echo "════════════════════════════════════════"
|
||||
|
||||
"$GIT_OPS_SCRIPT" checkout "$name" "$version"
|
||||
|
||||
# 同步 SKILL.md
|
||||
local skill_yaml="$REPOS_DIR/$name/skill.yaml"
|
||||
if [ -f "$skill_yaml" ]; then
|
||||
local prompt_file=$(yq e '.prompt_file // "SKILL.md"' "$skill_yaml" 2>/dev/null || echo "SKILL.md")
|
||||
if [ -f "$REPOS_DIR/$name/$prompt_file" ]; then
|
||||
mkdir -p "$SKILLS_DIR/$name"
|
||||
cp "$REPOS_DIR/$name/$prompt_file" "$SKILLS_DIR/$name/SKILL.md"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}✓ 回滚完成${NC}"
|
||||
}
|
||||
|
||||
# 查看技能详情
|
||||
cmd_info() {
|
||||
local name="$1"
|
||||
|
||||
if [ -z "$name" ]; then
|
||||
echo -e "${RED}用法: skill info <name>${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}技能详情: $name${NC}"
|
||||
echo "════════════════════════════════════════"
|
||||
|
||||
"$GIT_OPS_SCRIPT" status "$name"
|
||||
|
||||
# 显示 skill.yaml 信息
|
||||
local skill_yaml="$REPOS_DIR/$name/skill.yaml"
|
||||
if [ -f "$skill_yaml" ] && command -v yq &> /dev/null; then
|
||||
echo ""
|
||||
echo "技能配置:"
|
||||
echo "----------------------------------------"
|
||||
echo "描述: $(yq e '.description' "$skill_yaml" | head -1)"
|
||||
echo "作者: $(yq e '.author // "未知"' "$skill_yaml")"
|
||||
|
||||
local deps=$(yq e '.dependencies[]' "$skill_yaml" 2>/dev/null || echo "")
|
||||
if [ -n "$deps" ]; then
|
||||
echo "依赖: $deps"
|
||||
fi
|
||||
|
||||
local keywords=$(yq e '.triggers.keywords[]' "$skill_yaml" 2>/dev/null | tr '\n' ', ' | sed 's/,$//')
|
||||
if [ -n "$keywords" ]; then
|
||||
echo "关键词: $keywords"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# 启用技能
|
||||
cmd_enable() {
|
||||
local name="$1"
|
||||
|
||||
if [ -z "$name" ]; then
|
||||
echo -e "${RED}用法: skill enable <name>${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
"$REGISTRY_SCRIPT" update "$name" status "active"
|
||||
echo -e "${GREEN}✓ 已启用技能: $name${NC}"
|
||||
}
|
||||
|
||||
# 禁用技能
|
||||
cmd_disable() {
|
||||
local name="$1"
|
||||
|
||||
if [ -z "$name" ]; then
|
||||
echo -e "${RED}用法: skill disable <name>${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
"$REGISTRY_SCRIPT" update "$name" status "disabled"
|
||||
echo -e "${GREEN}✓ 已禁用技能: $name${NC}"
|
||||
}
|
||||
|
||||
# 检查更新
|
||||
cmd_check() {
|
||||
echo -e "${BLUE}检查技能更新${NC}"
|
||||
echo "════════════════════════════════════════"
|
||||
|
||||
local skills=$(ls -1 "$REPOS_DIR" 2>/dev/null || echo "")
|
||||
|
||||
if [ -z "$skills" ]; then
|
||||
echo "没有已安装的技能"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
local has_updates=0
|
||||
|
||||
for skill in $skills; do
|
||||
local result=$("$GIT_OPS_SCRIPT" has-updates "$skill" 2>/dev/null | head -1)
|
||||
if [ "$result" == "yes" ]; then
|
||||
local behind=$("$GIT_OPS_SCRIPT" has-updates "$skill" 2>/dev/null | tail -1)
|
||||
echo -e "${YELLOW}✓ $skill 有更新 ($behind)${NC}"
|
||||
has_updates=1
|
||||
else
|
||||
echo -e "${GREEN}✓ $skill 已是最新${NC}"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
if [ $has_updates -eq 1 ]; then
|
||||
echo -e "${YELLOW}执行 'skill upgrade' 升级所有技能${NC}"
|
||||
else
|
||||
echo -e "${GREEN}所有技能已是最新版本${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
# 主命令分发
|
||||
case "${1:-help}" in
|
||||
list|ls)
|
||||
cmd_list
|
||||
;;
|
||||
install|add)
|
||||
cmd_install "$2"
|
||||
;;
|
||||
upgrade|update)
|
||||
cmd_upgrade "$2"
|
||||
;;
|
||||
uninstall|remove)
|
||||
cmd_uninstall "$2"
|
||||
;;
|
||||
rollback)
|
||||
cmd_rollback "$2" "$3"
|
||||
;;
|
||||
info|show)
|
||||
cmd_info "$2"
|
||||
;;
|
||||
enable)
|
||||
cmd_enable "$2"
|
||||
;;
|
||||
disable)
|
||||
cmd_disable "$2"
|
||||
;;
|
||||
check)
|
||||
cmd_check
|
||||
;;
|
||||
help|--help|-h)
|
||||
show_banner
|
||||
echo "用法: skill <command> [args]"
|
||||
echo ""
|
||||
echo "命令:"
|
||||
echo " list 列出已安装技能"
|
||||
echo " install <repo> 安装新技能"
|
||||
echo " upgrade [name] 升级技能(不指定则升级全部)"
|
||||
echo " uninstall <name> 卸载技能"
|
||||
echo " rollback <name> <version> 回滚到指定版本"
|
||||
echo " info <name> 查看技能详情"
|
||||
echo " enable <name> 启用技能"
|
||||
echo " disable <name> 禁用技能"
|
||||
echo " check 检查所有技能更新"
|
||||
echo ""
|
||||
echo "示例:"
|
||||
echo " skill install https://github.com/org/skill-name.git"
|
||||
echo " skill upgrade coolbuy-paas"
|
||||
echo " skill rollback coolbuy-paas v1.1.0"
|
||||
;;
|
||||
*)
|
||||
echo -e "${RED}未知命令: $1${NC}"
|
||||
echo "使用 'skill help' 查看帮助"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
315
skills-workflow/skill-manager-plugin/skills/SKILL.md
Normal file
315
skills-workflow/skill-manager-plugin/skills/SKILL.md
Normal file
@@ -0,0 +1,315 @@
|
||||
---
|
||||
name: skill-manager
|
||||
description: 自我进化 Skills 管理器。通过自然语言安装、升级、卸载、回滚技能。
|
||||
---
|
||||
|
||||
# Skill Manager - 技能管理器
|
||||
|
||||
基于 Git 的 Claude Code 技能管理系统,支持自然语言操作。
|
||||
|
||||
---
|
||||
|
||||
## 命令列表
|
||||
|
||||
| 命令 | 功能 | 示例 |
|
||||
|------|------|------|
|
||||
| `/skill list` | 列出已安装技能 | `/skill list` |
|
||||
| `/skill install <repo>` | 安装新技能 | `/skill install https://github.com/org/skill-name` |
|
||||
| `/skill upgrade [name]` | 升级技能 | `/skill upgrade coolbuy-paas` |
|
||||
| `/skill uninstall <name>` | 卸载技能 | `/skill uninstall dev-test` |
|
||||
| `/skill rollback <name> <ver>` | 回滚版本 | `/skill rollback coolbuy-paas v1.1.0` |
|
||||
| `/skill info <name>` | 查看技能详情 | `/skill info coolbuy-paas` |
|
||||
| `/skill enable <name>` | 启用技能 | `/skill enable ops-tools` |
|
||||
| `/skill disable <name>` | 禁用技能 | `/skill disable ops-tools` |
|
||||
| `/skill check` | 检查更新 | `/skill check` |
|
||||
|
||||
---
|
||||
|
||||
## 自然语言支持
|
||||
|
||||
支持中英文自然语言指令:
|
||||
|
||||
| 自然语言 | 解析为 |
|
||||
|----------|--------|
|
||||
| "升级 coolbuy-paas" | `/skill upgrade coolbuy-paas` |
|
||||
| "更新所有技能" | `/skill upgrade` |
|
||||
| "安装技能 https://..." | `/skill install https://...` |
|
||||
| "卸载 dev-test 技能" | `/skill uninstall dev-test` |
|
||||
| "列出所有技能" | `/skill list` |
|
||||
| "回滚到 v1.1.0" | `/skill rollback <name> v1.1.0` |
|
||||
| "xxx 是什么版本" | `/skill info xxx` |
|
||||
|
||||
---
|
||||
|
||||
## 命令处理指南
|
||||
|
||||
### `/skill list`
|
||||
|
||||
**列出所有已安装技能**
|
||||
|
||||
执行步骤:
|
||||
1. 读取 `~/.claude/skills/registry.yaml`
|
||||
2. 遍历所有技能目录
|
||||
3. 读取每个技能的 `skill.yaml` 获取版本信息
|
||||
4. 按名称排序显示
|
||||
|
||||
输出格式:
|
||||
```
|
||||
已安装技能 (N个):
|
||||
|
||||
| 名称 | 版本 | 状态 | 最后更新 |
|
||||
|------|------|------|----------|
|
||||
| skill-name | v1.0.0 | active | 2026-01-20 |
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `/skill install <repo>`
|
||||
|
||||
**从 Git 仓库安装新技能**
|
||||
|
||||
执行步骤:
|
||||
1. 验证仓库地址格式(HTTPS 或 SSH)
|
||||
2. 从 URL 提取技能名称
|
||||
3. 检查是否已安装(如已安装,提示使用 upgrade)
|
||||
4. 执行 `git clone` 到 `~/.claude/skills/repos/<name>/`
|
||||
5. 验证 `skill.yaml` 存在且格式正确
|
||||
6. 检查并安装依赖技能
|
||||
7. 更新 `registry.yaml`
|
||||
8. 创建符号链接或复制到 `~/.claude/skills/<name>/`
|
||||
9. 执行 `post_install` 钩子
|
||||
10. 显示安装结果
|
||||
|
||||
示例:
|
||||
```bash
|
||||
# HTTPS
|
||||
/skill install https://github.com/org/skill-coolbuy-paas.git
|
||||
|
||||
# SSH
|
||||
/skill install git@github.com:org/skill-coolbuy-paas.git
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `/skill upgrade [name]`
|
||||
|
||||
**升级指定技能或全部技能**
|
||||
|
||||
执行步骤:
|
||||
1. 如果指定 name,升级单个技能;否则升级全部
|
||||
2. 读取 `registry.yaml` 获取仓库路径
|
||||
3. 进入仓库目录执行 `git fetch origin`
|
||||
4. 比较本地和远程版本
|
||||
5. 如有更新:
|
||||
- 执行 `git pull origin main`
|
||||
- 读取新版本号
|
||||
- 更新 `registry.yaml`
|
||||
- 执行 `post_update` 钩子
|
||||
- 同步文件到 `~/.claude/skills/<name>/`
|
||||
6. 显示更新结果
|
||||
|
||||
---
|
||||
|
||||
### `/skill uninstall <name>`
|
||||
|
||||
**卸载已安装的技能**
|
||||
|
||||
执行步骤:
|
||||
1. 验证技能存在
|
||||
2. 检查是否有其他技能依赖此技能
|
||||
3. 如有依赖,显示警告并询问确认
|
||||
4. 执行 `post_uninstall` 钩子
|
||||
5. 删除仓库目录 `~/.claude/skills/repos/<name>/`
|
||||
6. 删除技能目录 `~/.claude/skills/<name>/`
|
||||
7. 从 `registry.yaml` 移除记录
|
||||
8. 显示卸载结果
|
||||
|
||||
---
|
||||
|
||||
### `/skill rollback <name> <version>`
|
||||
|
||||
**回滚技能到指定版本**
|
||||
|
||||
执行步骤:
|
||||
1. 验证技能存在
|
||||
2. 进入仓库目录
|
||||
3. 验证目标版本存在(`git tag` 或 commit hash)
|
||||
4. 显示版本差异和警告
|
||||
5. 询问用户确认
|
||||
6. 执行 `git checkout <version>`
|
||||
7. 更新 `registry.yaml` 中的版本号
|
||||
8. 同步文件
|
||||
9. 执行 `post_update` 钩子
|
||||
10. 显示回滚结果
|
||||
|
||||
---
|
||||
|
||||
### `/skill info <name>`
|
||||
|
||||
**查看技能详细信息**
|
||||
|
||||
执行步骤:
|
||||
1. 读取 `skill.yaml`
|
||||
2. 读取 git 仓库信息(当前分支、最新 commit)
|
||||
3. 显示详细信息
|
||||
|
||||
输出格式:
|
||||
```
|
||||
技能: coolbuy-paas
|
||||
版本: v1.2.0
|
||||
描述: 酷采3.0 SaaS 租户端开发与测试
|
||||
作者: your-team
|
||||
状态: active
|
||||
|
||||
仓库: git@github.com:org/skill-coolbuy-paas.git
|
||||
分支: main
|
||||
Commit: abc1234 (2026-01-20)
|
||||
|
||||
依赖:
|
||||
- dev-coding
|
||||
- ops-tools
|
||||
|
||||
触发关键词:
|
||||
- coolbuy-paas
|
||||
- 酷采
|
||||
- 商品管理
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `/skill check`
|
||||
|
||||
**检查所有技能是否有更新**
|
||||
|
||||
执行步骤:
|
||||
1. 遍历所有已安装技能
|
||||
2. 对每个技能执行 `git fetch origin`
|
||||
3. 比较本地和远程 HEAD
|
||||
4. 显示有更新的技能列表
|
||||
|
||||
输出格式:
|
||||
```
|
||||
检查技能更新...
|
||||
|
||||
有更新的技能 (2个):
|
||||
- coolbuy-paas: v1.1.0 → v1.2.0
|
||||
- req: v4.4.0 → v4.5.0
|
||||
|
||||
执行 `/skill upgrade` 升级所有技能
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
~/.claude/
|
||||
├── skills/
|
||||
│ ├── registry.yaml # 技能注册表
|
||||
│ ├── repos/ # Git 仓库存储目录
|
||||
│ │ ├── coolbuy-paas/
|
||||
│ │ │ ├── .git/
|
||||
│ │ │ ├── skill.yaml
|
||||
│ │ │ └── SKILL.md
|
||||
│ │ └── ...
|
||||
│ ├── coolbuy-paas/ # 技能目录(符号链接或复制)
|
||||
│ │ └── SKILL.md
|
||||
│ ├── skill-manager/ # 本技能
|
||||
│ │ ├── skill.yaml
|
||||
│ │ ├── SKILL.md
|
||||
│ │ └── scripts/
|
||||
│ └── ...
|
||||
└── settings.json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Registry 结构
|
||||
|
||||
`~/.claude/skills/registry.yaml`:
|
||||
|
||||
```yaml
|
||||
version: 1
|
||||
updated_at: 2026-01-26T12:00:00Z
|
||||
|
||||
config:
|
||||
auto_update_check: true
|
||||
default_branch: main
|
||||
|
||||
skills:
|
||||
coolbuy-paas:
|
||||
repo: git@github.com:org/skill-coolbuy-paas.git
|
||||
local_path: ~/.claude/skills/repos/coolbuy-paas
|
||||
version: 1.2.0
|
||||
installed_at: 2026-01-15T10:00:00Z
|
||||
last_updated: 2026-01-20T10:30:00Z
|
||||
status: active
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## skill.yaml 规范
|
||||
|
||||
```yaml
|
||||
# 必填
|
||||
name: skill-name # hyphen-case, ≤64字符
|
||||
version: 1.0.0 # 语义化版本
|
||||
description: 技能描述 # ≤1024字符
|
||||
|
||||
# 可选
|
||||
author: author-name
|
||||
license: MIT
|
||||
|
||||
triggers:
|
||||
keywords: [关键词列表]
|
||||
commands: [/command]
|
||||
file_patterns: ["**/pattern/**"]
|
||||
|
||||
prompt_file: SKILL.md
|
||||
|
||||
dependencies:
|
||||
- other-skill
|
||||
|
||||
mcp_servers:
|
||||
- server-name
|
||||
|
||||
hooks:
|
||||
post_install: [命令列表]
|
||||
post_update: [命令列表]
|
||||
post_uninstall: [命令列表]
|
||||
|
||||
allowed_tools:
|
||||
- Bash
|
||||
- Read
|
||||
|
||||
metadata:
|
||||
category: category
|
||||
tags: [tag1, tag2]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 脚本工具
|
||||
|
||||
### scripts/validate.sh
|
||||
|
||||
验证 skill.yaml 格式:
|
||||
```bash
|
||||
~/.claude/skills/skill-manager/scripts/validate.sh <skill-directory>
|
||||
```
|
||||
|
||||
### scripts/sync.sh
|
||||
|
||||
同步技能文件:
|
||||
```bash
|
||||
~/.claude/skills/skill-manager/scripts/sync.sh <skill-name>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **私有仓库**: 需要配置 SSH key 或 Personal Access Token
|
||||
2. **依赖循环**: 安装前会检测循环依赖
|
||||
3. **版本兼容**: 支持语义化版本和 Git commit hash
|
||||
4. **钩子安全**: 钩子脚本在执行前会显示内容供用户确认
|
||||
88
skills-workflow/skill-manager-plugin/validate.sh
Executable file
88
skills-workflow/skill-manager-plugin/validate.sh
Executable file
@@ -0,0 +1,88 @@
|
||||
#!/bin/bash
|
||||
# validate.sh - 验证 skill.yaml 格式
|
||||
# 用法: ./validate.sh <skill-directory>
|
||||
|
||||
set -e
|
||||
|
||||
SKILL_DIR="${1:-.}"
|
||||
SKILL_YAML="$SKILL_DIR/skill.yaml"
|
||||
|
||||
# 颜色定义
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
echo "验证技能目录: $SKILL_DIR"
|
||||
echo "----------------------------------------"
|
||||
|
||||
# 检查 skill.yaml 是否存在
|
||||
if [ ! -f "$SKILL_YAML" ]; then
|
||||
echo -e "${RED}✗ skill.yaml 不存在${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}✓ skill.yaml 存在${NC}"
|
||||
|
||||
# 检查 YAML 格式(需要 yq 或 python)
|
||||
if command -v yq &> /dev/null; then
|
||||
if ! yq e '.' "$SKILL_YAML" > /dev/null 2>&1; then
|
||||
echo -e "${RED}✗ YAML 格式错误${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}✓ YAML 格式正确${NC}"
|
||||
|
||||
# 检查必填字段
|
||||
NAME=$(yq e '.name' "$SKILL_YAML")
|
||||
VERSION=$(yq e '.version' "$SKILL_YAML")
|
||||
DESCRIPTION=$(yq e '.description' "$SKILL_YAML")
|
||||
|
||||
if [ "$NAME" == "null" ] || [ -z "$NAME" ]; then
|
||||
echo -e "${RED}✗ 缺少必填字段: name${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}✓ name: $NAME${NC}"
|
||||
|
||||
if [ "$VERSION" == "null" ] || [ -z "$VERSION" ]; then
|
||||
echo -e "${RED}✗ 缺少必填字段: version${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}✓ version: $VERSION${NC}"
|
||||
|
||||
if [ "$DESCRIPTION" == "null" ] || [ -z "$DESCRIPTION" ]; then
|
||||
echo -e "${RED}✗ 缺少必填字段: description${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}✓ description: 已设置${NC}"
|
||||
|
||||
# 验证 name 格式
|
||||
if ! echo "$NAME" | grep -qE '^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$'; then
|
||||
echo -e "${RED}✗ name 格式错误: 只能包含小写字母、数字、连字符${NC}"
|
||||
exit 1
|
||||
fi
|
||||
if [ ${#NAME} -gt 64 ]; then
|
||||
echo -e "${RED}✗ name 超过 64 字符${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}✓ name 格式正确${NC}"
|
||||
|
||||
# 检查 prompt_file
|
||||
PROMPT_FILE=$(yq e '.prompt_file // "SKILL.md"' "$SKILL_YAML")
|
||||
if [ ! -f "$SKILL_DIR/$PROMPT_FILE" ]; then
|
||||
echo -e "${YELLOW}⚠ prompt_file 不存在: $PROMPT_FILE${NC}"
|
||||
else
|
||||
echo -e "${GREEN}✓ prompt_file: $PROMPT_FILE${NC}"
|
||||
fi
|
||||
|
||||
elif command -v python3 &> /dev/null; then
|
||||
python3 -c "import yaml; yaml.safe_load(open('$SKILL_YAML'))" 2>/dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${RED}✗ YAML 格式错误${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}✓ YAML 格式正确 (使用 Python 验证)${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}⚠ 无法验证 YAML 格式 (需要 yq 或 python3)${NC}"
|
||||
fi
|
||||
|
||||
echo "----------------------------------------"
|
||||
echo -e "${GREEN}✓ 验证通过${NC}"
|
||||
Reference in New Issue
Block a user