Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ef0e9ca1f0 | ||
|
|
ad4e2b16a8 |
+31
-119
@@ -95,6 +95,32 @@
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "ai-proj-cicd-release-plugin",
|
||||
"source": "./skills-dev/ai-proj-cicd-release-plugin",
|
||||
"description": "执行和审计 AI-Proj 服务从 Gitea 门禁、不可变镜像、预发验证到生产发布和回滚的 CI/CD 流程。",
|
||||
"version": "1.0.0",
|
||||
"category": "productivity",
|
||||
"keywords": [
|
||||
"project-management",
|
||||
"tasks",
|
||||
"requirements"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "ai-proj-macos-release-plugin",
|
||||
"source": "./skills-dev/ai-proj-macos-release-plugin",
|
||||
"description": "构建、签名、公证、发布并验证 AI-Proj macOS Apple Silicon 安装包。",
|
||||
"version": "1.0.0",
|
||||
"category": "productivity",
|
||||
"keywords": [
|
||||
"project-management",
|
||||
"tasks",
|
||||
"requirements"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "db-migration-plugin",
|
||||
"source": "./skills-dev/db-migration-plugin",
|
||||
@@ -111,7 +137,7 @@
|
||||
"name": "defect-analysis-plugin",
|
||||
"source": "./skills-dev/defect-analysis-plugin",
|
||||
"description": "系统性设计缺陷分析。对需求方案/代码架构进行多维度检查,发现隐藏的技术风险和设计漏洞。当用户提到缺陷检查、方案审查、设计审计时自动激活。",
|
||||
"version": "1.0.0",
|
||||
"version": "1.1.0",
|
||||
"category": "utility",
|
||||
"keywords": [
|
||||
"utility",
|
||||
@@ -329,7 +355,7 @@
|
||||
"name": "frontend-design-plugin",
|
||||
"source": "./skills-dev/frontend-design-plugin",
|
||||
"description": "Create distinctive, production-grade frontend interfaces with high design quality. Generates creative, polished code that avoids generic AI aesthetics.",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"category": "development",
|
||||
"keywords": [
|
||||
"development",
|
||||
@@ -342,7 +368,7 @@
|
||||
"name": "karpathy-guidelines-plugin",
|
||||
"source": "./skills-dev/karpathy-guidelines-plugin",
|
||||
"description": "Karpathy 四原则编码行为守则(Think Before Coding / Simplicity First / Surgical Changes / Goal-Driven Execution)。已深度融合到 req 技能工作流各阶段,可独立激活用于任意编码场景。",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"category": "utility",
|
||||
"keywords": [
|
||||
"utility",
|
||||
@@ -367,7 +393,7 @@
|
||||
"name": "review-checklist-plugin",
|
||||
"source": "./skills-dev/review-checklist-plugin",
|
||||
"description": "项目级代码评审检查清单。按项目积累的特定检查项,挂载在 dev-review 下自动加载。",
|
||||
"version": "1.0.0",
|
||||
"version": "1.1.0",
|
||||
"category": "utility",
|
||||
"keywords": [
|
||||
"utility",
|
||||
@@ -560,7 +586,7 @@
|
||||
"name": "doubao-voice-plugin",
|
||||
"source": "./skills-integration/doubao-voice-plugin",
|
||||
"description": "Doubao (豆包) Voice API integration for TTS and ASR",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"category": "utility",
|
||||
"keywords": [
|
||||
"utility",
|
||||
@@ -696,120 +722,6 @@
|
||||
"tools"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "gitea-plugin",
|
||||
"source": "./skills-personal/gitea-plugin",
|
||||
"description": "Gitea 代码托管与 CI/CD 管理。用于 Gitea Actions workflow 管理、Runner 管理、PR 操作、仓库配置。",
|
||||
"version": "1.0.0",
|
||||
"category": "utility",
|
||||
"keywords": [
|
||||
"utility",
|
||||
"tools"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "openclaw-plugin",
|
||||
"source": "./skills-personal/openclaw-plugin",
|
||||
"description": "OpenClaw (龙虾) 远程 AI 计算调度系统 - 概念设计与运维管理",
|
||||
"version": "1.0.0",
|
||||
"category": "utility",
|
||||
"keywords": [
|
||||
"utility",
|
||||
"tools"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "ops-servers-plugin",
|
||||
"source": "./skills-personal/ops-servers-plugin",
|
||||
"description": "企业服务器管理。用于云服务器分组管理、系统监控、备份管理、故障排查。当用户提到云服务器、生产环境、腾讯云、阿里云相关任务时自动激活。",
|
||||
"version": "1.0.0",
|
||||
"category": "devops",
|
||||
"keywords": [
|
||||
"devops",
|
||||
"deployment",
|
||||
"operations"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "ops-tools-plugin",
|
||||
"source": "./skills-personal/ops-tools-plugin",
|
||||
"description": "Plugin for ops-tools",
|
||||
"version": "1.0.0",
|
||||
"category": "devops",
|
||||
"keywords": [
|
||||
"devops",
|
||||
"deployment",
|
||||
"operations"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "qiudl-personal-plugin",
|
||||
"source": "./skills-personal/qiudl-personal-plugin",
|
||||
"description": "Plugin for qiudl-personal",
|
||||
"version": "1.0.0",
|
||||
"category": "utility",
|
||||
"keywords": [
|
||||
"utility",
|
||||
"tools"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "reload-session-plugin",
|
||||
"source": "./skills-personal/reload-session-plugin",
|
||||
"description": "Reload a previously saved Claude session to continue the conversation.",
|
||||
"version": "1.0.0",
|
||||
"category": "workflow",
|
||||
"keywords": [
|
||||
"session",
|
||||
"workflow",
|
||||
"productivity"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "req-deploy-plugin",
|
||||
"source": "./skills-personal/req-deploy-plugin",
|
||||
"description": "Plugin for req-deploy",
|
||||
"version": "1.0.0",
|
||||
"category": "devops",
|
||||
"keywords": [
|
||||
"devops",
|
||||
"deployment",
|
||||
"operations"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "save-session-plugin",
|
||||
"source": "./skills-personal/save-session-plugin",
|
||||
"description": "Auto-save Claude session conversation with AI-generated title, summary, and tags in searchable JSON format.",
|
||||
"version": "1.0.0",
|
||||
"category": "workflow",
|
||||
"keywords": [
|
||||
"session",
|
||||
"workflow",
|
||||
"productivity"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "search-sessions-plugin",
|
||||
"source": "./skills-personal/search-sessions-plugin",
|
||||
"description": "Search saved Claude sessions by title, tags, date, or content.",
|
||||
"version": "1.0.0",
|
||||
"category": "workflow",
|
||||
"keywords": [
|
||||
"session",
|
||||
"workflow",
|
||||
"productivity"
|
||||
],
|
||||
"strict": false
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -18,11 +18,11 @@ Claude Code 技能市场 + MCP 配置管理工具。
|
||||
|
||||
```
|
||||
ai-proj-helper/
|
||||
├── skills-core/ # 基础设施 (1): ai-proj
|
||||
├── skills-dev/ # 开发 (4): dev-arch, dev-coding, dev-test, pull-request
|
||||
├── skills-req/ # 需求 (4): req, req-prd, req-dev, req-test-gate
|
||||
├── skills-integration/ # 集成 (8): feishu, feishu-bitable, feishu-docx, wecom, siyuan, siyuan-to-feishu, data-excel, doubao-voice
|
||||
├── skills-biz/ # 商务 (4): biz-contract, biz-ops, biz-plan, finance
|
||||
├── skills-core/ # 基础设施技能
|
||||
├── skills-dev/ # 开发与发布技能
|
||||
├── skills-req/ # 需求管理技能
|
||||
├── skills-integration/ # 第三方集成技能
|
||||
├── skills-biz/ # 商务技能
|
||||
├── skills-personal/ # 个人(.gitignore 排除)
|
||||
├── claude-config.yaml # 技能启用/禁用 + MCP 配置
|
||||
├── init.sh # MCP 初始化
|
||||
@@ -51,4 +51,4 @@ skills:
|
||||
|
||||
- `skills-personal/` 不被 Git 跟踪,用于存放个人配置和工具
|
||||
- 其余 `skills-*` 目录均由 Git 版本控制
|
||||
- 所有目录都会被 `generate-marketplace.py` 自动扫描并加入 marketplace.json
|
||||
- 只有受 Git 跟踪的分类目录会被 `generate-marketplace.py` 扫描并加入公开 marketplace;`skills-personal/` 始终排除
|
||||
|
||||
@@ -83,6 +83,7 @@ cd ai-proj-helper
|
||||
脚本会自动完成:
|
||||
- 配置 MCP 服务器连接(`~/.claude/.mcp.json`)
|
||||
- 注册技能市场到 Claude Code(`~/.claude/plugins/known_marketplaces.json`)
|
||||
- 安装完整技能目录到 `~/.claude/skills/`(包括 references、scripts 和 assets)
|
||||
|
||||
也支持命令行参数跳过交互:
|
||||
|
||||
@@ -163,7 +164,7 @@ skills:
|
||||
|
||||
- **mode**: MCP 连接模式。`sse` 直连远程服务器(推荐),`stdio` 在本地启动 Node.js 进程
|
||||
- **disabled**: 不需要的技能可以加到这里,重新运行 `./init.sh` 生效
|
||||
- **personal_dir**: 个人技能目录,默认不被 Git 跟踪
|
||||
- **personal_dir**: 本机个人技能目录,默认不被 Git 跟踪,也不会写入公开 marketplace
|
||||
|
||||
## 常见问题
|
||||
|
||||
|
||||
@@ -1,28 +1,21 @@
|
||||
# Setup Guide
|
||||
|
||||
## 1. Create Repository on Gitea
|
||||
|
||||
Go to https://gitea.pipexerp.com and create a new repository:
|
||||
- Name: `claude-marketplace`
|
||||
- Visibility: Private or Public (your choice)
|
||||
- **Do NOT** initialize with README (we already have one)
|
||||
|
||||
## 2. Push to Gitea
|
||||
## 1. Clone the Gitea Repository
|
||||
|
||||
```bash
|
||||
cd /Users/junhuang/coolbuy/claude-marketplace
|
||||
git push -u origin main
|
||||
git clone https://gitea.pipexerp.com/pipexerp/ai-proj-helper.git
|
||||
cd ai-proj-helper
|
||||
```
|
||||
|
||||
## 3. Test Installation
|
||||
## 2. Test Installation
|
||||
|
||||
### Add the marketplace
|
||||
```bash
|
||||
# SSH (recommended)
|
||||
/plugin marketplace add git@gitea.pipexerp.com:huangjun/claude-marketplace.git
|
||||
# SSH
|
||||
/plugin marketplace add ssh://git@gitea.pipexerp.com:10022/pipexerp/ai-proj-helper.git
|
||||
|
||||
# OR HTTPS (requires credential configuration)
|
||||
/plugin marketplace add https://gitea.pipexerp.com/huangjun/claude-marketplace.git
|
||||
/plugin marketplace add https://gitea.pipexerp.com/pipexerp/ai-proj-helper.git
|
||||
```
|
||||
|
||||
### List available plugins
|
||||
@@ -42,12 +35,12 @@ git push -u origin main
|
||||
# Check for your installed plugins
|
||||
```
|
||||
|
||||
## 4. Update Plugins Later
|
||||
## 3. Update Plugins Later
|
||||
|
||||
When you make changes and push updates:
|
||||
|
||||
```bash
|
||||
cd /Users/junhuang/coolbuy/claude-marketplace
|
||||
cd /path/to/ai-proj-helper
|
||||
|
||||
# Make changes to plugins
|
||||
# ...
|
||||
@@ -67,7 +60,7 @@ Users update with:
|
||||
/plugin update ai-proj-plugin@coolbuy-claude-plugins
|
||||
```
|
||||
|
||||
## 5. Private Repository Setup
|
||||
## 4. Repository Authentication
|
||||
|
||||
If your Gitea repo is private, users need authentication:
|
||||
|
||||
@@ -87,30 +80,28 @@ To create a Gitea token:
|
||||
3. Give it "Read repository" permissions
|
||||
4. Copy the token and add to your environment
|
||||
|
||||
## 6. Structure Overview
|
||||
## 5. Structure Overview
|
||||
|
||||
```
|
||||
claude-marketplace/
|
||||
ai-proj-helper/
|
||||
├── .claude-plugin/
|
||||
│ └── marketplace.json # Catalog of all plugins
|
||||
├── plugins/
|
||||
│ ├── ai-proj-plugin/
|
||||
│ │ ├── .claude-plugin/
|
||||
│ │ │ └── plugin.json # Plugin metadata
|
||||
│ │ └── skills/
|
||||
│ │ └── SKILL.md # Skill definition
|
||||
│ └── [33 more plugins...]
|
||||
├── skills-core/ # Core plugins
|
||||
├── skills-dev/ # Development and release plugins
|
||||
├── skills-req/ # Requirement plugins
|
||||
├── skills-integration/ # Integration plugins
|
||||
├── skills-biz/ # Business plugins
|
||||
├── README.md # User documentation
|
||||
├── SETUP.md # This file
|
||||
└── convert-skills.sh # Conversion script (reference)
|
||||
├── generate-marketplace.py # Marketplace generator
|
||||
└── install-skills.sh # Versioned local installer
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. ✅ Push to Gitea: `git push -u origin main`
|
||||
2. ✅ Test locally: `/plugin marketplace add <url>`
|
||||
3. ✅ Install plugins: `/plugin install <name>@coolbuy-claude-plugins`
|
||||
4. ✅ Share with team: Send them the repository URL
|
||||
1. ✅ Test locally: `/plugin marketplace add <url>`
|
||||
2. ✅ Install plugins: `/plugin install <name>@coolbuy-claude-plugins`
|
||||
3. ✅ Share with team: Send them the repository URL
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
|
||||
+36
-192
@@ -1,218 +1,62 @@
|
||||
# Skill Sync Guide
|
||||
|
||||
## Overview
|
||||
仓库中的插件是团队技能的发布源,本机 `~/.claude/skills/` 是安装目标。个人技能保留在
|
||||
`skills-personal/` 或其他本机目录,不会进入公开 marketplace。
|
||||
|
||||
This guide explains how to keep your local skills (`~/.claude/skills/`) synchronized with the marketplace plugins.
|
||||
|
||||
## Quick Sync
|
||||
## 从仓库更新本机
|
||||
|
||||
```bash
|
||||
cd /path/to/claude-marketplace
|
||||
./sync-skills.sh
|
||||
git pull
|
||||
./install-skills.sh --dry-run
|
||||
./install-skills.sh
|
||||
```
|
||||
|
||||
This will:
|
||||
1. ✅ Compare local skills with marketplace plugins
|
||||
2. ➕ Add new skills as plugins
|
||||
3. 📝 Update changed skills
|
||||
4. ✓ Skip unchanged plugins
|
||||
安装器会复制完整技能目录,包括 `SKILL.md`、`references/`、`scripts/` 和 `assets/`。它用内容摘要区分仓库升级和本地修改:
|
||||
|
||||
## Sync Workflow
|
||||
- 目标未修改时,版本升级会自动安装。
|
||||
- 旧版只安装了 `SKILL.md` 时,会安全补齐仓库中的其他同源文件。
|
||||
- 目标存在本地修改时会跳过;确认覆盖后才使用 `--force`。
|
||||
- `--cleanup` 会删除状态文件记录中已从仓库移除的技能,使用前先运行 `--dry-run --cleanup`。
|
||||
|
||||
### 1. Edit Skills Locally
|
||||
|
||||
Work on your skills in `~/.claude/skills/`:
|
||||
```bash
|
||||
code ~/.claude/skills/my-skill/SKILL.md
|
||||
```
|
||||
|
||||
### 2. Run Sync Script
|
||||
按分类安装或查看清单:
|
||||
|
||||
```bash
|
||||
cd ~/path/to/claude-marketplace
|
||||
./sync-skills.sh
|
||||
./install-skills.sh --list
|
||||
./install-skills.sh --category dev
|
||||
```
|
||||
|
||||
### 3. Review Changes
|
||||
## 将本机技能发布到仓库
|
||||
|
||||
```bash
|
||||
git status
|
||||
git diff
|
||||
```
|
||||
不要批量复制整个 `~/.claude/skills/`。系统技能、第三方托管技能、包含机器路径或凭据的技能不应发布。
|
||||
|
||||
### 4. Commit & Push
|
||||
1. 选择确实属于本仓库、可供团队复用的技能。
|
||||
2. 在对应 `skills-*/<name>-plugin/` 下放置 `.claude-plugin/plugin.json` 和完整 `skills/` 目录。
|
||||
3. 清除用户名、绝对路径、内网地址、密钥标识和历史凭据;把环境差异改为从仓库配置解析。
|
||||
4. 更新插件版本并运行:
|
||||
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "Update skill: description of changes"
|
||||
git push
|
||||
```
|
||||
```bash
|
||||
python3 generate-marketplace.py
|
||||
claude plugin validate .
|
||||
git diff --check
|
||||
```
|
||||
|
||||
### 5. Team Updates
|
||||
5. 审核变更后通过分支和 PR 发布。
|
||||
|
||||
Team members update with:
|
||||
```bash
|
||||
/plugin marketplace update coolbuy-claude-plugins
|
||||
/plugin update <plugin-name>@coolbuy-claude-plugins
|
||||
```
|
||||
## 本地个人技能
|
||||
|
||||
## Automated Sync (Optional)
|
||||
`skills-personal/` 受 `.gitignore` 保护,仅供当前机器使用。生成器明确排除此目录,避免
|
||||
`marketplace.json` 引用公开克隆中不存在的文件。若个人技能要转为团队技能,应先按上面的发布流程完成脱敏和审核。
|
||||
|
||||
### Git Hook (Pre-commit)
|
||||
## 常见问题
|
||||
|
||||
Auto-sync when committing changes to skills:
|
||||
**本地修改被跳过怎么办?**
|
||||
|
||||
```bash
|
||||
# In your dotfiles/skills repo
|
||||
cat > .git/hooks/pre-commit << 'EOF'
|
||||
#!/bin/bash
|
||||
# Auto-sync skills to marketplace
|
||||
~/path/to/claude-marketplace/sync-skills.sh
|
||||
EOF
|
||||
先比较仓库源和 `~/.claude/skills/<name>/`。保留本地修改时将其整理成插件变更;确认丢弃时再对该次安装使用 `--force`。
|
||||
|
||||
chmod +x .git/hooks/pre-commit
|
||||
```
|
||||
**marketplace 没更新?**
|
||||
|
||||
### Cron Job (Scheduled)
|
||||
运行 `python3 generate-marketplace.py`,然后检查 `.claude-plugin/marketplace.json` 是否只包含受 Git 跟踪且真实存在的 source。
|
||||
|
||||
Sync daily at 9 AM:
|
||||
**如何移除技能?**
|
||||
|
||||
```bash
|
||||
crontab -e
|
||||
|
||||
# Add this line:
|
||||
0 9 * * * cd ~/path/to/claude-marketplace && ./sync-skills.sh && git add . && git commit -m "Daily sync" && git push
|
||||
```
|
||||
|
||||
## Skill Splitting Guidelines
|
||||
|
||||
From `~/.claude/CLAUDE.md`:
|
||||
|
||||
- **Token Limit**: Single skill ≤ 10,000 tokens
|
||||
- **Check Size**: `wc -w ~/.claude/skills/<skill>/SKILL.md`
|
||||
- **When to Split**: If > 7,500 words (≈10,000 tokens)
|
||||
|
||||
### Split Strategy
|
||||
|
||||
When a skill grows too large:
|
||||
|
||||
1. **Entry Skill** - Overview + command routing (<100 lines)
|
||||
- Example: `req/SKILL.md`
|
||||
|
||||
2. **Command Reference** - Detailed commands (<200 lines)
|
||||
- Example: `req-commands/SKILL.md`
|
||||
|
||||
3. **Workflow Guide** - Complete processes (<200 lines)
|
||||
- Example: `req-workflow/SKILL.md`
|
||||
|
||||
4. **Methodology** - Complex concepts (<150 lines)
|
||||
- Example: `req-review/SKILL.md`
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Sync Script Fails
|
||||
|
||||
```bash
|
||||
# Check permissions
|
||||
ls -la sync-skills.sh
|
||||
|
||||
# Make executable
|
||||
chmod +x sync-skills.sh
|
||||
|
||||
# Check paths
|
||||
echo $HOME/.claude/skills
|
||||
```
|
||||
|
||||
### marketplace.json Not Updated
|
||||
|
||||
```bash
|
||||
# Manually regenerate
|
||||
python3 generate-marketplace.py
|
||||
|
||||
# Or edit directly
|
||||
code .claude-plugin/marketplace.json
|
||||
```
|
||||
|
||||
### Git Conflicts
|
||||
|
||||
```bash
|
||||
# Discard local changes
|
||||
git checkout .claude-plugin/marketplace.json
|
||||
|
||||
# Or merge manually
|
||||
git mergetool
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Descriptive Frontmatter
|
||||
|
||||
Always include in `SKILL.md`:
|
||||
```yaml
|
||||
---
|
||||
name: skill-name
|
||||
description: Clear, concise description of what this skill does
|
||||
---
|
||||
```
|
||||
|
||||
### 2. Version Bumping
|
||||
|
||||
When making significant changes:
|
||||
```bash
|
||||
# Update version in plugin.json
|
||||
{
|
||||
"version": "1.1.0" # was 1.0.0
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Testing Before Sync
|
||||
|
||||
```bash
|
||||
# Test skill locally first
|
||||
/skill-name
|
||||
|
||||
# Then sync to marketplace
|
||||
./sync-skills.sh
|
||||
```
|
||||
|
||||
### 4. Commit Messages
|
||||
|
||||
Use clear, descriptive messages:
|
||||
```bash
|
||||
git commit -m "Add feishu-bitable plugin for table operations"
|
||||
git commit -m "Update req-workflow with new approval process"
|
||||
git commit -m "Fix: Correct PRD template in req-prd"
|
||||
```
|
||||
|
||||
## Monitoring
|
||||
|
||||
### Check Sync Status
|
||||
|
||||
```bash
|
||||
# Compare local vs marketplace
|
||||
diff -qr ~/.claude/skills /tmp/claude-marketplace/plugins
|
||||
```
|
||||
|
||||
### List Differences
|
||||
|
||||
```bash
|
||||
# Find skills not in marketplace
|
||||
comm -23 <(ls ~/.claude/skills | sort) <(ls plugins | sed 's/-plugin$//' | sort)
|
||||
|
||||
# Find plugins not in local
|
||||
comm -13 <(ls ~/.claude/skills | sort) <(ls plugins | sed 's/-plugin$//' | sort)
|
||||
```
|
||||
|
||||
## FAQ
|
||||
|
||||
**Q: Can I sync in reverse (marketplace → local)?**
|
||||
A: Not recommended. Treat local skills as the source of truth.
|
||||
|
||||
**Q: What about binary files (images, scripts)?**
|
||||
A: Copy them manually to the plugin directory, then commit.
|
||||
|
||||
**Q: How do I remove a plugin?**
|
||||
A: Delete the plugin directory, regenerate marketplace.json, commit, and push.
|
||||
|
||||
**Q: Can I sync specific skills only?**
|
||||
A: Modify `sync-skills.sh` to accept a skill name parameter.
|
||||
删除插件目录、重新生成 marketplace、提交变更。使用者随后执行 `./install-skills.sh --dry-run --cleanup`,确认后再去掉 `--dry-run`。
|
||||
|
||||
+6
-13
@@ -14,28 +14,27 @@ script_dir = Path(__file__).parent.resolve()
|
||||
config_file = script_dir / "claude-config.yaml"
|
||||
marketplace_file = script_dir / ".claude-plugin" / "marketplace.json"
|
||||
|
||||
# Skill directories (label, directory name)
|
||||
# Public marketplace skill directories. skills-personal is deliberately
|
||||
# excluded: it is gitignored and must never produce sources that disappear from
|
||||
# a public clone of this repository.
|
||||
SKILL_DIRS = [
|
||||
("core", "skills-core"),
|
||||
("dev", "skills-dev"),
|
||||
("req", "skills-req"),
|
||||
("integration", "skills-integration"),
|
||||
("biz", "skills-biz"),
|
||||
("personal", "skills-personal"),
|
||||
]
|
||||
|
||||
|
||||
def load_config():
|
||||
"""Load claude-config.yaml and return disabled list + personal_dir."""
|
||||
"""Load claude-config.yaml and return the disabled plugin list."""
|
||||
disabled = []
|
||||
personal = "skills-personal"
|
||||
|
||||
if config_file.exists() and HAS_YAML:
|
||||
with open(config_file) as f:
|
||||
cfg = yaml.safe_load(f) or {}
|
||||
skills_cfg = cfg.get("skills", {})
|
||||
disabled = skills_cfg.get("disabled", []) or []
|
||||
personal = skills_cfg.get("personal_dir", personal)
|
||||
elif config_file.exists():
|
||||
# Fallback: parse disabled list without PyYAML
|
||||
in_disabled = False
|
||||
@@ -54,10 +53,7 @@ def load_config():
|
||||
disabled.append(val)
|
||||
elif stripped and not stripped.startswith("#"):
|
||||
break
|
||||
if stripped.startswith("personal_dir:"):
|
||||
personal = stripped.split(":", 1)[1].strip().strip('"').strip("'")
|
||||
|
||||
return disabled, personal
|
||||
return disabled
|
||||
|
||||
|
||||
# Category mapping
|
||||
@@ -116,15 +112,12 @@ def scan_plugins(directory, source_prefix, disabled):
|
||||
|
||||
|
||||
# Load config
|
||||
disabled_skills, personal_dir_name = load_config()
|
||||
disabled_skills = load_config()
|
||||
|
||||
# Collect plugins from all skill directories
|
||||
plugins = []
|
||||
counts = {}
|
||||
for label, dir_name in SKILL_DIRS:
|
||||
# personal_dir may be overridden by config
|
||||
if label == "personal":
|
||||
dir_name = personal_dir_name
|
||||
skill_path = script_dir / dir_name
|
||||
if not skill_path.is_dir():
|
||||
continue
|
||||
|
||||
@@ -183,32 +183,12 @@ EOF
|
||||
fi
|
||||
fi
|
||||
|
||||
# ── Install skills to ~/.claude/skills/ ──────────────────────────────
|
||||
# ── Install complete skill packages ──────────────────────────────────
|
||||
# Use the versioned installer as the single installation path so references,
|
||||
# scripts and assets stay beside SKILL.md and local edits are not overwritten.
|
||||
echo "📦 安装技能到 ~/.claude/skills/ ..."
|
||||
SKILLS_DIR="$HOME/.claude/skills"
|
||||
mkdir -p "$SKILLS_DIR"
|
||||
|
||||
SKILL_COUNT=0
|
||||
for plugin_dir in "$SCRIPT_DIR"/skills-*/; do
|
||||
for skill_path in "$plugin_dir"*-plugin/; do
|
||||
[ -d "$skill_path" ] || continue
|
||||
skill_md="$skill_path/skills/SKILL.md"
|
||||
[ -f "$skill_md" ] || continue
|
||||
|
||||
# Extract skill name: ai-proj-plugin -> ai-proj
|
||||
dir_name=$(basename "$skill_path")
|
||||
skill_name="${dir_name%-plugin}"
|
||||
|
||||
target_dir="$SKILLS_DIR/$skill_name"
|
||||
mkdir -p "$target_dir"
|
||||
|
||||
# Copy SKILL.md (overwrite if exists)
|
||||
cp "$skill_md" "$target_dir/SKILL.md"
|
||||
SKILL_COUNT=$((SKILL_COUNT + 1))
|
||||
done
|
||||
done
|
||||
echo " 已安装 $SKILL_COUNT 个技能"
|
||||
echo "✅ 技能安装完成 → $SKILLS_DIR"
|
||||
"$SCRIPT_DIR/install-skills.sh"
|
||||
echo "✅ 技能安装完成"
|
||||
|
||||
# ── Verify MCP connection ────────────────────────────────────────────
|
||||
echo ""
|
||||
|
||||
+126
-50
@@ -25,6 +25,7 @@ CATEGORY_FILTER=""
|
||||
FORCE=false
|
||||
CLEANUP=false
|
||||
LIST_ONLY=false
|
||||
INSTALL_ACTION=false
|
||||
|
||||
# ── Colour helpers ─────────────────────────────────────────────────────────────
|
||||
GREEN='\033[0;32m'
|
||||
@@ -72,14 +73,28 @@ except: pass
|
||||
fi
|
||||
}
|
||||
|
||||
state_digest() {
|
||||
# state_digest <install_name> -> prints installed content digest or empty string
|
||||
local name="$1"
|
||||
if [[ -f "$STATE_FILE" ]]; then
|
||||
python3 -c "
|
||||
import json
|
||||
try:
|
||||
d=json.load(open('$STATE_FILE'))
|
||||
print(d.get('$name',{}).get('content_digest',''))
|
||||
except: pass
|
||||
" 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
state_set() {
|
||||
# state_set <install_name> <version> <install_type>
|
||||
local name="$1" ver="$2" itype="$3"
|
||||
# state_set <install_name> <version> <install_type> <content_digest>
|
||||
local name="$1" ver="$2" itype="$3" digest="$4"
|
||||
python3 -c "
|
||||
import json,os
|
||||
f='$STATE_FILE'
|
||||
d=json.load(open(f)) if os.path.exists(f) else {}
|
||||
d['$name']={'version':'$ver','install_type':'$itype'}
|
||||
d['$name']={'version':'$ver','install_type':'$itype','content_digest':'$digest'}
|
||||
json.dump(d,open(f,'w'),indent=2)
|
||||
" 2>/dev/null
|
||||
}
|
||||
@@ -116,6 +131,64 @@ read_field() {
|
||||
python3 -c "import json,sys; d=json.load(open('$1')); print(d.get('$2',''))" 2>/dev/null || true
|
||||
}
|
||||
|
||||
content_digest() {
|
||||
# Stable digest for one command file or a complete skill directory.
|
||||
python3 - "$1" <<'PY'
|
||||
import hashlib
|
||||
import os
|
||||
import pathlib
|
||||
import sys
|
||||
|
||||
target = pathlib.Path(sys.argv[1])
|
||||
if not target.exists():
|
||||
print("")
|
||||
raise SystemExit
|
||||
|
||||
digest = hashlib.sha256()
|
||||
files = [target] if target.is_file() else sorted(
|
||||
path for path in target.rglob("*") if path.is_file() or path.is_symlink()
|
||||
)
|
||||
for path in files:
|
||||
relative = path.name if target.is_file() else path.relative_to(target).as_posix()
|
||||
digest.update(relative.encode("utf-8"))
|
||||
digest.update(b"\0")
|
||||
if path.is_symlink():
|
||||
digest.update(b"link\0")
|
||||
digest.update(os.readlink(path).encode("utf-8"))
|
||||
else:
|
||||
digest.update(path.read_bytes())
|
||||
digest.update(b"\0")
|
||||
print(digest.hexdigest())
|
||||
PY
|
||||
}
|
||||
|
||||
is_compatible_subset() {
|
||||
# True when every file in an existing legacy target also exists unchanged in
|
||||
# the repository source. This safely upgrades old SKILL.md-only installs.
|
||||
python3 - "$1" "$2" <<'PY'
|
||||
import pathlib
|
||||
import sys
|
||||
|
||||
source = pathlib.Path(sys.argv[1])
|
||||
target = pathlib.Path(sys.argv[2])
|
||||
if not source.is_dir() or not target.is_dir():
|
||||
raise SystemExit(1)
|
||||
|
||||
for target_path in target.rglob("*"):
|
||||
if target_path.is_dir():
|
||||
continue
|
||||
source_path = source / target_path.relative_to(target)
|
||||
if not source_path.is_file() or target_path.is_symlink() != source_path.is_symlink():
|
||||
raise SystemExit(1)
|
||||
if target_path.is_symlink():
|
||||
if target_path.readlink() != source_path.readlink():
|
||||
raise SystemExit(1)
|
||||
elif target_path.read_bytes() != source_path.read_bytes():
|
||||
raise SystemExit(1)
|
||||
raise SystemExit(0)
|
||||
PY
|
||||
}
|
||||
|
||||
# Resolve the actual source directory to rsync from.
|
||||
# If skills/ has SKILL.md at the top level, use it directly.
|
||||
# If skills/ has a single subdirectory (e.g. skills/dev-test/SKILL.md), use that subdirectory.
|
||||
@@ -135,33 +208,9 @@ resolve_skills_src() {
|
||||
echo "$skills_dir"
|
||||
}
|
||||
|
||||
# ── Conflict detection (has local been modified since we installed it?) ────────
|
||||
has_local_modification() {
|
||||
# Returns 0 (true) if local target differs from repo source, 1 if identical or new
|
||||
local install_name="$1" install_type="$2" plugin_skills_dir="$3"
|
||||
|
||||
if [[ "$install_type" == "command" ]]; then
|
||||
local src="$plugin_skills_dir/SKILL.md"
|
||||
local dst="$COMMANDS_DIR/${install_name}.md"
|
||||
[[ -f "$dst" ]] && ! diff -q "$src" "$dst" &>/dev/null && return 0
|
||||
else
|
||||
local dst_dir="$SKILLS_DIR/$install_name"
|
||||
if [[ -d "$dst_dir" ]]; then
|
||||
# Compare each file from source
|
||||
while IFS= read -r -d '' src_file; do
|
||||
local rel="${src_file#$plugin_skills_dir/}"
|
||||
local dst_file="$dst_dir/$rel"
|
||||
if [[ -f "$dst_file" ]] && ! diff -q "$src_file" "$dst_file" &>/dev/null; then
|
||||
return 0
|
||||
fi
|
||||
done < <(find "$plugin_skills_dir" -type f -print0)
|
||||
fi
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# ── Install a single plugin ────────────────────────────────────────────────────
|
||||
install_plugin() {
|
||||
INSTALL_ACTION=false
|
||||
local json_path="$1"
|
||||
local plugin_dir
|
||||
plugin_dir="$(dirname "$(dirname "$json_path")")" # strip /.claude-plugin/plugin.json
|
||||
@@ -195,27 +244,54 @@ install_plugin() {
|
||||
return
|
||||
fi
|
||||
|
||||
# Check current installed version
|
||||
local current_version
|
||||
current_version="$(state_get "$install_name")"
|
||||
# Resolve actual source (handles plugins where content sits one level deeper,
|
||||
# e.g. skills/dev-test/SKILL.md instead of skills/SKILL.md).
|
||||
local src_dir
|
||||
src_dir="$(resolve_skills_src "$skills_dir")"
|
||||
|
||||
# Skip if up-to-date (same version) and no force
|
||||
if [[ "$current_version" == "$version" && "$FORCE" == false ]]; then
|
||||
local source_path target_path
|
||||
if [[ "$install_type" == "command" ]]; then
|
||||
source_path="$src_dir/SKILL.md"
|
||||
target_path="$COMMANDS_DIR/${install_name}.md"
|
||||
else
|
||||
source_path="$src_dir"
|
||||
target_path="$SKILLS_DIR/$install_name"
|
||||
fi
|
||||
|
||||
if [[ ! -e "$source_path" ]]; then
|
||||
warn "$install_name: install source not found, skipping"
|
||||
return
|
||||
fi
|
||||
|
||||
# Conflict detection: warn if local files were modified
|
||||
if [[ -n "$current_version" && "$FORCE" == false ]]; then
|
||||
if has_local_modification "$install_name" "$install_type" "$skills_dir"; then
|
||||
warn "$install_name: local files were modified — skipping (use --force to overwrite)"
|
||||
return
|
||||
# A recorded content digest distinguishes repository updates from user edits.
|
||||
# Legacy state is adopted automatically only when the target is missing or
|
||||
# already identical to the repository source.
|
||||
local current_version recorded_digest source_digest target_digest
|
||||
current_version="$(state_get "$install_name")"
|
||||
recorded_digest="$(state_digest "$install_name")"
|
||||
source_digest="$(content_digest "$source_path")"
|
||||
target_digest="$(content_digest "$target_path")"
|
||||
|
||||
if [[ "$FORCE" == false && -n "$target_digest" && "$target_digest" == "$source_digest" ]]; then
|
||||
if [[ "$DRY_RUN" == false && ( "$current_version" != "$version" || "$recorded_digest" != "$source_digest" ) ]]; then
|
||||
state_set "$install_name" "$version" "$install_type" "$source_digest"
|
||||
fi
|
||||
return
|
||||
fi
|
||||
|
||||
local legacy_subset=false
|
||||
if [[ "$install_type" == "skill" && -z "$recorded_digest" && -n "$target_digest" ]]; then
|
||||
if is_compatible_subset "$source_path" "$target_path"; then
|
||||
legacy_subset=true
|
||||
fi
|
||||
fi
|
||||
|
||||
# Resolve actual source (handles plugins where content sits one level deeper,
|
||||
# e.g. skills/dev-test/SKILL.md instead of skills/SKILL.md)
|
||||
local src_dir
|
||||
src_dir="$(resolve_skills_src "$skills_dir")"
|
||||
if [[ "$FORCE" == false && -n "$target_digest" && "$legacy_subset" == false ]]; then
|
||||
if [[ -z "$recorded_digest" || "$target_digest" != "$recorded_digest" ]]; then
|
||||
warn "$install_name: local files were modified or have legacy unverified state — skipping (use --force once to adopt repository content)"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
|
||||
# Perform install
|
||||
if [[ "$install_type" == "command" ]]; then
|
||||
@@ -228,11 +304,13 @@ install_plugin() {
|
||||
|
||||
if [[ "$DRY_RUN" == true ]]; then
|
||||
dry "$install_name → $COMMANDS_DIR/${install_name}.md"
|
||||
INSTALL_ACTION=true
|
||||
else
|
||||
mkdir -p "$COMMANDS_DIR"
|
||||
cp "$src_md" "$COMMANDS_DIR/${install_name}.md"
|
||||
state_set "$install_name" "$version" "$install_type"
|
||||
state_set "$install_name" "$version" "$install_type" "$source_digest"
|
||||
ok "$install_name → command (v$version)"
|
||||
INSTALL_ACTION=true
|
||||
fi
|
||||
|
||||
else
|
||||
@@ -241,12 +319,14 @@ install_plugin() {
|
||||
|
||||
if [[ "$DRY_RUN" == true ]]; then
|
||||
dry "$install_name → $dst_dir/"
|
||||
INSTALL_ACTION=true
|
||||
else
|
||||
mkdir -p "$dst_dir"
|
||||
# rsync resolved source (handles nested skills/ structures)
|
||||
rsync -a --delete "$src_dir/" "$dst_dir/"
|
||||
state_set "$install_name" "$version" "$install_type"
|
||||
state_set "$install_name" "$version" "$install_type" "$source_digest"
|
||||
ok "$install_name → skill (v$version)"
|
||||
INSTALL_ACTION=true
|
||||
fi
|
||||
fi
|
||||
}
|
||||
@@ -311,15 +391,11 @@ main() {
|
||||
[[ "$DRY_RUN" == true ]] && warn "DRY RUN — no files will be written"
|
||||
[[ -n "$CATEGORY_FILTER" ]] && info "Category filter: $CATEGORY_FILTER"
|
||||
|
||||
local installed=0 skipped=0
|
||||
local installed=0
|
||||
|
||||
while IFS= read -r json_path; do
|
||||
local before
|
||||
before="$(state_all_names | wc -l || true)"
|
||||
install_plugin "$json_path"
|
||||
local after
|
||||
after="$(state_all_names | wc -l || true)"
|
||||
if [[ "$after" -gt "$before" ]] || [[ "$DRY_RUN" == true ]]; then
|
||||
if [[ "$INSTALL_ACTION" == true ]]; then
|
||||
((installed++)) || true
|
||||
fi
|
||||
done < <(find_plugins)
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "ai-proj-cicd-release-plugin",
|
||||
"description": "执行和审计 AI-Proj 服务从 Gitea 门禁、不可变镜像、预发验证到生产发布和回滚的 CI/CD 流程。",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
},
|
||||
"install_name": "ai-proj-cicd-release",
|
||||
"install_type": "skill",
|
||||
"dir_category": "dev"
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
---
|
||||
name: ai-proj-cicd-release
|
||||
description: Execute and audit the AI-Proj service CI/CD flow across Gitea gates, immutable image builds, staging verification, approved production release, rollback, and evidence capture. Use for AI-Proj CI status, release PRs, staging or production deployments, failed-release diagnosis, deployed commit/schema verification, and delivery-chain repair. Do not use for unrelated repositories or macOS application packaging.
|
||||
---
|
||||
|
||||
# AI-Proj CI/CD release
|
||||
|
||||
Use the repository's live workflows and release scripts as the executable source of truth. Keep staging and production isolated, bind artifacts to exact commits, and fail closed when a gate, provenance check, rollback target, or environment contract is uncertain.
|
||||
|
||||
## Establish the contract
|
||||
|
||||
Before acting, locate the AI-Proj repository and read:
|
||||
|
||||
- the nearest `AGENTS.md`;
|
||||
- `.gitea/CI_SOP.md`;
|
||||
- the applicable workflow in `.gitea/workflows/`;
|
||||
- `scripts/ci/common.sh`, `release-lib.sh`, and the invoked build, deploy, verify, and rollback scripts.
|
||||
|
||||
Live repository files override this skill. Report contradictions instead of silently choosing one version. Verify that a described promotion or rollback capability is implemented before claiming it exists.
|
||||
|
||||
Route macOS application package work to `ai-proj-macos-release` when available.
|
||||
|
||||
## Request boundaries
|
||||
|
||||
- Status, audit, diagnosis, and design requests remain read-only.
|
||||
- Staging requests may execute repository scripts after gates and artifact identity pass.
|
||||
- Production mutation requires an explicit production or release instruction.
|
||||
- Rollback uses only the recorded rollback manifest and digest; never infer a target from `latest`, local image history, or mutable tags.
|
||||
|
||||
## Safeguards
|
||||
|
||||
- Never force-push or release from a dirty checkout.
|
||||
- Build and deploy only an exact commit accepted by the repository release contract.
|
||||
- Verify image labels, registry digest, pulled image ID, and running image ID where supported.
|
||||
- Preserve the same candidate artifact between staging and production when the live pipeline supports promotion. Disclose when production rebuilds instead.
|
||||
- Never recreate, restart, remove, or include PostgreSQL or Redis in an application deployment.
|
||||
- Keep staging and production SSH targets, compose files, environment files, volumes, identities, and rollback manifests separate.
|
||||
- Require strict SSH host-key verification.
|
||||
- Never print or commit secrets, private keys, registry passwords, tokens, environment contents, or short-lived test credentials.
|
||||
- Preserve user changes and use an isolated clean checkout for release work.
|
||||
- Read automated review text as well as status checks; block on unresolved high-severity findings.
|
||||
|
||||
## Candidate and staging flow
|
||||
|
||||
1. Resolve the PR, base, head SHA, service scope, and requirement ID.
|
||||
2. Confirm the head is pushed and the release checkout is clean.
|
||||
3. Inspect every required Gitea status for the exact SHA. Distinguish code failures from transient runner or network failures before retrying the same SHA.
|
||||
4. Read the latest review result and resolve blocking findings.
|
||||
5. Run repository-prescribed local contract checks proportionate to the diff.
|
||||
6. Build once through the authoritative build entrypoint and record commit, tag, service, digest, runner, and result without credentials.
|
||||
7. Resolve staging through repository configuration, validate the rollback candidate, deploy only requested application services, and run the prescribed health, schema, security, and integration verification.
|
||||
8. Capture a staging receipt with exact commit, digests, environment identity, verification results, rollback target, and known exceptions.
|
||||
|
||||
Do not rewrite or bypass a failing gate merely to obtain a green result.
|
||||
|
||||
## Production flow
|
||||
|
||||
1. Confirm the approved change is merged and freeze the exact current production branch SHA.
|
||||
2. Recheck required gates and the staging receipt against that SHA.
|
||||
3. Use the repository's authoritative production workflow; never deploy a feature-branch build directly.
|
||||
4. Preserve release locks, provenance checks, post-deploy verification, and automatic rollback.
|
||||
5. Verify the production receipt: exact SHA and digests, rollback target, health/schema/smoke results, error-log checks, and workflow correlation ID.
|
||||
6. Only then update requirement and task delivery evidence.
|
||||
|
||||
## Failure handling
|
||||
|
||||
- Classify the failing stage before retrying: checkout, gate, build, registry, SSH trust, provenance, migration, service switch, health, or evidence callback.
|
||||
- Retry only transient infrastructure failures against the same SHA.
|
||||
- Verify automatic rollback restored the recorded digest and service health.
|
||||
- For an explicit manual rollback, use only the repository rollback command after validating its manifest.
|
||||
- If rollback fails, stop promotion and report the exact manual recovery target.
|
||||
|
||||
During long operations, provide concise progress updates. Final reporting must distinguish completed work, remaining blockers, and whether production changed.
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "ai-proj-macos-release-plugin",
|
||||
"description": "构建、签名、公证、发布并验证 AI-Proj macOS Apple Silicon 安装包。",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
},
|
||||
"install_name": "ai-proj-macos-release",
|
||||
"install_type": "skill",
|
||||
"dir_category": "dev"
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
---
|
||||
name: ai-proj-macos-release
|
||||
description: Build, sign, notarize, publish, and verify the AI-Proj macOS Apple Silicon package through the repository's release chain. Use when asked to release, republish, update, or repair the downloadable macOS application, including Gatekeeper failures and download-manifest updates. Do not use for service deployments or unrelated applications.
|
||||
---
|
||||
|
||||
# AI-Proj macOS release
|
||||
|
||||
Use this workflow only for an explicitly requested AI-Proj macOS package release. Repository scripts and current project instructions are authoritative; stop and report any contradiction.
|
||||
|
||||
## Resolve the release contract
|
||||
|
||||
Before building, read the nearest `AGENTS.md`, the desktop package configuration, and the repository's macOS build, publish, and verification scripts. Resolve from those files:
|
||||
|
||||
- application version and architecture;
|
||||
- production API configuration;
|
||||
- signing identity and notarization mechanism;
|
||||
- object-storage bucket, endpoint, release prefix, and public manifest;
|
||||
- required website or download-manifest fallback version.
|
||||
|
||||
Do not copy machine-specific credential paths or identifiers into source control. Use the operator's configured secure credential provider without printing secret values.
|
||||
|
||||
## Release flow
|
||||
|
||||
1. Confirm the requested release version is unused. Keep package metadata, native application metadata, artifact filename, public manifest, and website fallback aligned.
|
||||
2. Use a clean checkout of the exact approved commit. Run the repository's production desktop build script with the production API mode.
|
||||
3. Require a valid Developer ID signature. If the repository's default notarization profile is unavailable, use another already-authorized App Store Connect credential source only after confirming its key, key ID, and issuer belong together.
|
||||
4. Submit the final package to Apple notarization, wait for acceptance, staple the ticket, and validate it.
|
||||
5. Mount the package read-only and verify the nested application with `codesign`, `spctl`, and the repository's smoke checks. Require Gatekeeper to report a notarized Developer ID.
|
||||
6. Publish through the repository script. Use its configured object-storage credentials and upload mode; never handcraft a mutable public path when the script provides immutable versioned objects.
|
||||
7. Require remote read-back verification of size and SHA-256. Upload artifacts first and update the public manifest last.
|
||||
8. Download the public artifact independently and repeat signature, notarization, Gatekeeper, size, and checksum verification.
|
||||
9. Confirm the manifest's latest version and asset URL, then update the website entry if the request includes it.
|
||||
|
||||
## Failure boundaries
|
||||
|
||||
- Missing signing or storage credentials: stop and report the missing configured provider; do not search broadly through personal files.
|
||||
- Notarization authentication failure: stop and correct the credential tuple; never publish an unnotarized package.
|
||||
- Gatekeeper reports an unnotarized or invalid application: do not publish.
|
||||
- Upload stalls or fails: use only an alternative mode supported by the repository script, then repeat remote checksum verification.
|
||||
- A public version already exists: do not overwrite it unless the user explicitly authorizes replacement and the repository permits it.
|
||||
- Never expose signing keys, API keys, keychain passwords, storage credentials, or token values in logs, commits, manifests, or bundles.
|
||||
|
||||
Record the exact commit, version, artifact checksum and size, Apple result, public URL, manifest result, and verification outcome. Do not mark the release complete until the independently downloaded artifact passes all checks.
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "defect-analysis-plugin",
|
||||
"description": "系统性设计缺陷分析。对需求方案/代码架构进行多维度检查,发现隐藏的技术风险和设计漏洞。当用户提到缺陷检查、方案审查、设计审计时自动激活。",
|
||||
"version": "1.0.0",
|
||||
"version": "1.1.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
},
|
||||
|
||||
@@ -59,7 +59,9 @@ description: 系统性设计缺陷分析。对需求方案/代码架构进行多
|
||||
|
||||
- 每轮检查一个维度,输出发现的缺陷列表
|
||||
- 如果某轮发现 0 个新缺陷 → **收敛,停止**
|
||||
- 如果 5 轮后仍有新发现 → 继续,最多 10 轮
|
||||
- 如果 5 轮后仍有新发现 → 继续;20 轮作为阶段复盘点,不得误报为已收敛
|
||||
- 达到 20 轮仍有新发现时,汇总剩余风险面并请求用户确认是否继续;用户已明确要求持续审计时可继续下一阶段
|
||||
- 只有出现一轮 0 个新缺陷时才标记收敛;达到授权范围、时间或预算边界时应报告“尚未收敛”,不得伪装完成
|
||||
- 每个缺陷标注严重度和轮次
|
||||
|
||||
## 输出格式
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "frontend-design-plugin",
|
||||
"description": "Create distinctive, production-grade frontend interfaces with high design quality. Generates creative, polished code that avoids generic AI aesthetics.",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
name: frontend-design
|
||||
description: Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
|
||||
arguments: [component|page|storybook] <description>
|
||||
arguments: "[component|page|storybook] <description>"
|
||||
---
|
||||
|
||||
# Frontend Design 前端设计技能
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
{
|
||||
"name": "karpathy-guidelines",
|
||||
"description": "Karpathy 四原则编码行为守则(Think Before Coding / Simplicity First / Surgical Changes / Goal-Driven Execution)。已深度融合到 req 技能工作流各阶段,可独立激活用于任意编码场景。",
|
||||
"version": "1.0.0",
|
||||
"author": "qiudl",
|
||||
"source": "https://github.com/forrestchang/andrej-karpathy-skills",
|
||||
"tags": ["coding-guidelines", "karpathy", "simplicity", "surgical", "goal-driven"],
|
||||
"skills": ["karpathy-guidelines"]
|
||||
"version": "1.0.1",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
},
|
||||
"install_name": "karpathy-guidelines",
|
||||
"install_type": "skill",
|
||||
"dir_category": "dev"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "review-checklist-plugin",
|
||||
"description": "项目级代码评审检查清单。按项目积累的特定检查项,挂载在 dev-review 下自动加载。",
|
||||
"version": "1.0.0",
|
||||
"version": "1.1.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
},
|
||||
|
||||
@@ -13,16 +13,17 @@ description: 项目级代码评审检查清单。按项目积累特定检查项
|
||||
|
||||
## 使用方式
|
||||
|
||||
1. `dev-review` 执行五视角扫描时,自动加载当前项目的检查清单
|
||||
2. 扫描完成后,逐条检查清单项
|
||||
3. 检查结果附加到 CR 报告的「项目检查清单」章节
|
||||
1. `dev-review` 执行五视角扫描时,先读取 `references/general.md`
|
||||
2. 如果仓库是 AI-Proj,读取 `references/ai-proj.md`;如果是 Coolbuy PaaS,读取 `references/coolbuy-paas.md`
|
||||
3. 扫描完成后,逐条检查适用的清单项
|
||||
4. 检查结果附加到 CR 报告的「项目检查清单」章节
|
||||
|
||||
## 检查清单文件
|
||||
|
||||
```
|
||||
review-checklist-plugin/
|
||||
├── skills/SKILL.md # 本文件
|
||||
└── checklists/
|
||||
review-checklist/
|
||||
├── SKILL.md # 本文件
|
||||
└── references/
|
||||
├── ai-proj.md # AI-Proj 项目清单
|
||||
├── coolbuy-paas.md # 酷采3.0 项目清单
|
||||
└── general.md # 通用清单(所有项目适用)
|
||||
@@ -32,7 +33,7 @@ review-checklist-plugin/
|
||||
|
||||
当 CR 中发现了一个**项目特有**的问题模式,且未来可能复发时:
|
||||
|
||||
1. 打开对应项目的检查清单文件
|
||||
1. 打开 `references/` 中对应项目的检查清单文件
|
||||
2. 添加条目,格式:`- [ ] {检查项} — 教训:{来源}`
|
||||
3. 标注严重度和适用范围
|
||||
|
||||
|
||||
+9
-1
@@ -18,6 +18,14 @@
|
||||
- [ ] JWT token 类型是否区分 access/refresh?— 教训:token 混用导致安全漏洞
|
||||
- [ ] bcrypt cost 是否使用 12?— 教训:默认 cost 10 导致登录失败
|
||||
|
||||
### 租户隔离(多企业安全,源自 REQ-20260711-0004)
|
||||
- [ ] 隔离/权限类修复是否枚举了威胁模型的**所有读取面**?— list 枚举 + 单条直读 + 按 ID/pattern 查 + count + 关联子查询。教训:P1 只修 list 面漏了 find_task/get-by-id 直读面,直读即绕过枚举防护,audit 才逮到高危残留
|
||||
- [ ] 同一威胁在**镜像面**是否一并处理?— 一个对象类型(task)漏,同类(project/document/manual/history)大概率同漏
|
||||
- [ ] MCP 裸 SQL(不走仓储层)是否应用 `ResolveTenantScope` / scope 片段?— SSE 面 list_tasks/list_projects 曾裸 SQL 无企业过滤
|
||||
- [ ] context 注入的是**类型化 key**(`EnterpriseIDContextKey{}`)而非字符串 key?— 字符串 key 与 `ResolveTenantScope` 读的类型化 key 不通,静默失效
|
||||
- [ ] scope 解析不出 / 依赖为 nil 时是否 **fail-closed**(空哨兵拒绝)而非跳过(退化全量)?
|
||||
- [ ] MCP endpoint 参数是否 snake_case + camelCase 双绑?— CLI 发 snake、bridge 发 camel,gin 静默忽略不匹配参数(REQ-20260711-0003)
|
||||
|
||||
### Redis
|
||||
- [ ] Redis key 是否有 TTL?— 缺少 TTL 导致内存泄露
|
||||
- [ ] Redis 不可用时是否降级到数据库?
|
||||
@@ -37,6 +45,6 @@
|
||||
|
||||
## 通用
|
||||
|
||||
- [ ] `.env` ��凭据文件是否被意外加入 git?
|
||||
- [ ] `.env` 等凭据文件是否被意外加入 git?
|
||||
- [ ] 是否有硬编码的 URL/IP/端口?— 应使用配置
|
||||
- [ ] 错误日志是否包含足够的上下文信息?(user_id, tenant_id, request_id)
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
|
||||
### 数据迁移
|
||||
- [ ] 从酷采2.0迁移的字段映射是否正确?(varchar ID → bigint ID)
|
||||
- [ ] 迁移脚本是否处理了酷采2.0���软删除标记(is_delete → deleted_at)?
|
||||
- [ ] 迁移脚本是否处理了酷采2.0 的软删除标记(is_delete → deleted_at)?
|
||||
|
||||
## 前端(Vue 3 + Ant Design Vue)
|
||||
|
||||
+2
@@ -1,5 +1,7 @@
|
||||
# 通用代码评审检查清单
|
||||
|
||||
每次代码审查都应加载本清单。
|
||||
|
||||
适用于所有项目,补充六视角扫描法(五传统视角 + Karpathy Scope 视角)。
|
||||
|
||||
## Karpathy 反模式速查(Scope 审计者视角辅助)
|
||||
@@ -1,16 +1,10 @@
|
||||
{
|
||||
"name": "doubao-voice-plugin",
|
||||
"description": "Doubao (豆包) Voice API integration for TTS and ASR",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
},
|
||||
"skills": [
|
||||
{
|
||||
"name": "doubao-voice",
|
||||
"path": "./skills/SKILL.md"
|
||||
}
|
||||
],
|
||||
"install_name": "doubao-voice",
|
||||
"install_type": "skill",
|
||||
"dir_category": "integration"
|
||||
|
||||
Executable
+78
@@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
TEST_ROOT="$(mktemp -d)"
|
||||
trap 'rm -rf "$TEST_ROOT"' EXIT
|
||||
|
||||
FIXTURE_REPO="$TEST_ROOT/repo"
|
||||
TEST_HOME="$TEST_ROOT/home"
|
||||
mkdir -p "$FIXTURE_REPO/skills-dev/example-plugin/.claude-plugin"
|
||||
mkdir -p "$FIXTURE_REPO/skills-dev/example-plugin/skills/references"
|
||||
mkdir -p "$TEST_HOME"
|
||||
cp "$PROJECT_DIR/install-skills.sh" "$FIXTURE_REPO/install-skills.sh"
|
||||
|
||||
write_manifest() {
|
||||
local plugin="$1" name="$2" version="$3"
|
||||
mkdir -p "$FIXTURE_REPO/skills-dev/${plugin}-plugin/.claude-plugin"
|
||||
cat > "$FIXTURE_REPO/skills-dev/${plugin}-plugin/.claude-plugin/plugin.json" <<JSON
|
||||
{"name":"${plugin}-plugin","version":"${version}","install_name":"${name}","install_type":"skill","dir_category":"dev"}
|
||||
JSON
|
||||
}
|
||||
|
||||
write_manifest example example 1.0.0
|
||||
cat > "$FIXTURE_REPO/skills-dev/example-plugin/skills/SKILL.md" <<'EOF'
|
||||
---
|
||||
name: example
|
||||
description: Installer fixture version one.
|
||||
---
|
||||
version one
|
||||
EOF
|
||||
printf 'reference one\n' > "$FIXTURE_REPO/skills-dev/example-plugin/skills/references/guide.md"
|
||||
|
||||
HOME="$TEST_HOME" "$FIXTURE_REPO/install-skills.sh" >/dev/null
|
||||
test -f "$TEST_HOME/.claude/skills/example/references/guide.md"
|
||||
|
||||
# A repository version upgrade replaces an unchanged prior install.
|
||||
write_manifest example example 2.0.0
|
||||
cat > "$FIXTURE_REPO/skills-dev/example-plugin/skills/SKILL.md" <<'EOF'
|
||||
---
|
||||
name: example
|
||||
description: Installer fixture version two.
|
||||
---
|
||||
version two
|
||||
EOF
|
||||
HOME="$TEST_HOME" "$FIXTURE_REPO/install-skills.sh" >/dev/null
|
||||
grep -q 'version two' "$TEST_HOME/.claude/skills/example/SKILL.md"
|
||||
grep -q '"version": "2.0.0"' "$TEST_HOME/.claude/.installed-skills.json"
|
||||
|
||||
# A local edit is preserved even when the repository advances again.
|
||||
printf 'local edit\n' >> "$TEST_HOME/.claude/skills/example/SKILL.md"
|
||||
write_manifest example example 3.0.0
|
||||
printf 'repository version three\n' >> "$FIXTURE_REPO/skills-dev/example-plugin/skills/SKILL.md"
|
||||
output="$(HOME="$TEST_HOME" "$FIXTURE_REPO/install-skills.sh")"
|
||||
grep -q 'local files were modified' <<<"$output"
|
||||
grep -q 'local edit' "$TEST_HOME/.claude/skills/example/SKILL.md"
|
||||
if grep -q 'repository version three' "$TEST_HOME/.claude/skills/example/SKILL.md"; then
|
||||
echo 'local modification was overwritten' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Legacy SKILL.md-only installs gain missing repository resources when their
|
||||
# existing content is an unchanged subset of the source.
|
||||
write_manifest legacy legacy 1.0.0
|
||||
mkdir -p "$FIXTURE_REPO/skills-dev/legacy-plugin/skills/references"
|
||||
cat > "$FIXTURE_REPO/skills-dev/legacy-plugin/skills/SKILL.md" <<'EOF'
|
||||
---
|
||||
name: legacy
|
||||
description: Legacy installation fixture.
|
||||
---
|
||||
legacy content
|
||||
EOF
|
||||
printf 'legacy reference\n' > "$FIXTURE_REPO/skills-dev/legacy-plugin/skills/references/guide.md"
|
||||
mkdir -p "$TEST_HOME/.claude/skills/legacy"
|
||||
cp "$FIXTURE_REPO/skills-dev/legacy-plugin/skills/SKILL.md" "$TEST_HOME/.claude/skills/legacy/SKILL.md"
|
||||
HOME="$TEST_HOME" "$FIXTURE_REPO/install-skills.sh" >/dev/null
|
||||
test -f "$TEST_HOME/.claude/skills/legacy/references/guide.md"
|
||||
|
||||
echo 'install-skills tests passed'
|
||||
@@ -22,6 +22,8 @@ PLUGIN_MAP = {
|
||||
"publish-plugin": ("publish", "skill", "core"),
|
||||
|
||||
# skills-dev
|
||||
"ai-proj-cicd-release-plugin": ("ai-proj-cicd-release", "skill", "dev"),
|
||||
"ai-proj-macos-release-plugin": ("ai-proj-macos-release", "skill", "dev"),
|
||||
"agent-browser-plugin": ("agent-browser", "skill", "dev"),
|
||||
"agent-swarm-plugin": ("agent-swarm", "skill", "dev"),
|
||||
"ai-chat-plugin": ("ai-chat", "skill", "dev"),
|
||||
@@ -44,6 +46,7 @@ PLUGIN_MAP = {
|
||||
"executing-plans-plugin": ("executing-plans", "skill", "dev"),
|
||||
"finishing-branch-plugin": ("finishing-a-development-branch","skill", "dev"), # name mismatch!
|
||||
"frontend-design-plugin": ("frontend-design", "skill", "dev"),
|
||||
"karpathy-guidelines-plugin": ("karpathy-guidelines", "skill", "dev"),
|
||||
"pull-request-plugin": ("pull-request", "skill", "dev"),
|
||||
"review-checklist-plugin": ("review-checklist", "skill", "dev"),
|
||||
|
||||
|
||||
Reference in New Issue
Block a user