
Skill Management
- 34 installs
- 17 repo stars
- Updated July 25, 2026
- dwsy/agent
A full skill lifecycle manager that uses an LLM to discover, evaluate, security-audit, adapt and test agent skills across GitHub, the skills.sh marketplace and the Skills CLI (npx skills).
About
skill-management is a Claude Code skill that manages the full lifecycle of agent skills - discovering, evaluating, security-auditing, adapting and testing them - using an LLM for smart analysis and searching across GitHub, the skills.sh marketplace, and the Skills CLI. A solo builder reaches for it to find, vet, and safely integrate new skills into their local agent setup.
- Three-source search: GitHub, skills.sh, Skills CLI
- LLM-driven skill classification and quality scoring
- Security audit of skills
- Adapt and test skills locally
Skill Management by the numbers
- 34 all-time installs (skills.sh)
- Ranked #393 of 781 Skill Development skills by installs in the Skillselion catalog
- Data as of Jul 29, 2026 (Skillselion catalog sync)
npx skills add https://github.com/dwsy/agent --skill skill-managementAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 34 |
|---|---|
| repo stars | ★ 17 |
| Last updated | July 25, 2026 |
| Repository | dwsy/agent ↗ |
What it does
A full skill lifecycle manager that uses an LLM to discover, evaluate, security-audit, adapt and test agent skills across GitHub, the skills.sh marketplace and the Skills CLI (npx skills).
Who is it for?
Builders curating and securing their agent skill set
Skip if: Users who never install third-party skills
Files
技能全生命周期管理系统
完整的技能管理流程,从发现到部署的端到端管理,充分利用 LLM 智能分析能力。
🎯 核心特性
1. 三数据源搜索
- GitHub - 搜索 GitHub 上的技能仓库
- skills.sh marketplace - 搜索 skills.sh 技能市场
- Skills CLI - 使用
npx skillsCLI 搜索和安装技能(基于 Vercel 开源方案)
2. 智能技能分类
- 自动识别技能类型:knowledge、tool、hybrid、process
- 差异化评估标准
3. LLM 深度分析
- 智能分类
- 深度评估
- 安全审计
- 定制化报告
4. 差异化评估
- 知识型:重点评估内容质量(40%)
- 工具型:重点评估功能和安全(40%)
5. Skills CLI 集成
基于 Vercel skills 开源方案,提供:
- 搜索技能 -
npx skills find <keyword> - 安装技能 -
npx skills add <owner/repo@skill> - 检查更新 -
npx skills check - 更新技能 -
npx skills update
🔄 工作流程
┌─────────────┐
│ 搜索技能 │ ← 脚本:GitHub CLI 或 skills.sh marketplace
└──────┬──────┘
│
┌──────▼──────┐
│ 选择技能 │ ← LLM:使用 interview 展示列表 + 智能介绍
└──────┬──────┘
│
┌──────▼──────┐
│ 发现技能 │ ← 脚本:克隆仓库、查找 SKILL.md
└──────┬──────┘
│
┌──────▼──────┐
│ 智能分类 │ ← LLM:判断技能类型
└──────┬──────┘
│
┌──────▼──────┐
│ 评估技能 │ ← LLM:差异化分析
└──────┬──────┘
│
┌──────▼──────┐
│ 安全审计 │ ← LLM:差异化审计
└──────┬──────┘
│
┌──────▼──────┐
│ 适应性改造 │ ← 脚本:分析需求
└──────┬──────┘
│
┌──────▼──────┐
│ 融合测试 │ ← 脚本:兼容性检查
└──────┬──────┘
│
┌──────▼──────┐
│ 智能报告 │ ← LLM:定制化报告
└──────┬──────┘
│
┌──────▼──────┐
│ 用户通知 │ ← 脚本:显示摘要
└─────────────┘🚀 快速开始
搜索技能
GitHub 搜索
bun ~/.pi/agent/skills/skill-management/scripts/search.ts "claude office"skills.sh marketplace 搜索
bun ~/.pi/agent/skills/skill-management/scripts/search.ts "react" --source marketplaceSkills CLI 搜索
bun ~/.pi/agent/skills/skill-management/scripts/search.ts "react" --source cli使用 Skills CLI 直接安装
# 搜索技能
npx skills find react
# 安装特定技能
npx skills add vercel-labs/agent-skills@vercel-react-best-practices
# 检查更新
npx skills check
# 更新所有技能
npx skills update查看热门技能
bun ~/.pi/agent/skills/skill-management/scripts/search.ts trending查看统计信息
bun ~/.pi/agent/skills/skill-management/scripts/search.ts stats完整流程
# 使用 GitHub 搜索
bun ~/.pi/agent/skills/skill-management/scripts/pipeline.ts "claude office" --interactive
# 使用 marketplace 搜索
bun ~/.pi/agent/skills/skill-management/scripts/pipeline.ts "react" --source marketplace --interactive🤖 LLM 智能分析
智能分类
自动识别 4 种技能类型:
- knowledge - 纯文档、指南、最佳实践
- tool - 包含可执行脚本和工具
- hybrid - 既有文档又有脚本
- process - 流程指南和工作流
差异化评估
| 维度 | 知识型 | 工具型 |
|---|---|---|
| 内容质量 | 40% | 20% |
| 功能完整性 | 20% | 40% |
| 实用性 | 20% | 20% |
| 文档质量 | 10% | 10% |
| 代码质量 | 5% | 10% |
| 安全性 | 5% | 10% |
📁 文件结构
~/.pi/agent/skills/skill-management/
├── SKILL.md # 本文档
├── README.md # 使用说明
├── config.json # 配置文件
├── scripts/
│ ├── assess.ts # 智能评估(自动分类 + 差异化)
│ ├── audit.ts # 智能审计(自动分类 + 差异化)
│ ├── pipeline.ts # 完整流程脚本
│ ├── select.ts # 技能选择脚本
│ ├── search.ts # 三数据源搜索(GitHub + marketplace + CLI)
│ ├── skills-cli.ts # Skills CLI (npx skills) 集成模块
│ ├── interactive.ts # 交互式决策脚本
│ ├── report.ts # 智能报告生成脚本
│ └── notify.ts # 通知脚本
├── reports/ # 智能评估报告目录
└── templates/ # 模板文件🎨 数据源对比
| 数据源 | 类型 | 优势 | 用途 |
|---|---|---|---|
| GitHub | 代码仓库 | 搜索开源技能项目 | 搜索 GitHub 上的技能仓库 |
| skills.sh | 技能市场 | 技能聚合平台 | 发现热门和社区技能 |
| Skills CLI | 包管理器 | 统一的技能生态 | 搜索、安装、更新技能 |
📝 使用示例
示例 1: GitHub 搜索
bun ~/.pi/agent/skills/skill-management/scripts/search.ts "office"示例 2: Marketplace 搜索
bun ~/.pi/agent/skills/skill-management/scripts/search.ts "react" --source marketplace示例 3: 查看热门技能
bun ~/.pi/agent/skills/skill-management/scripts/search.ts trending示例 4: 查看统计
bun ~/.pi/agent/skills/skill-management/scripts/search.ts stats🎯 最佳实践
1. 先搜索后选择 - 使用三数据源搜索更多技能 2. 充分利用 LLM - LLM 参与全流程分析 3. 区分技能类型 - 不同类型使用不同评估标准 4. 定制化报告 - 根据类型生成定制化报告 5. 优先使用 Skills CLI - 对于 skills.sh 生态的技能,使用 npx skills 进行安装和管理 6. 技能命名格式 - 使用 owner/repo@skill-name 格式引用特定技能
{"assessment": {"minStars": 10, "maxDaysSinceUpdate": 180, "requiredFiles": ["SKILL.md"], "allowedDependencies": ["python", "node", "bun"], "blockedPatterns": ["eval", "exec", "system"], "rationalityWeight": 0.3, "functionalityWeight": 0.3, "activityWeight": 0.2, "securityWeight": 0.2}, "security": {"auditLevel": "strict", "checkNetworkAccess": true, "checkFilePermissions": true, "maxDependencyCount": 50, "dangerousFunctions": {"high": ["eval", "exec", "system", "os.system"], "medium": ["subprocess", "child_process", "shell.exec"], "low": ["open", "write", "read"]}, "secretPatterns": ["password\\s*=", "api_key\\s*=", "secret\\s*=", "token\\s*=", "private_key"]}, "integration": {"testTimeout": 300, "regressionTests": true, "compatibilityCheck": true, "conflictDetection": {"checkNameConflicts": true, "checkDependencyConflicts": true, "checkNamespaceConflicts": true}}, "notification": {"onDecisionPoint": true, "onCompletion": true, "onError": true, "onWarning": true, "channel": "console", "logFile": "notifications.log"}, "adaptation": {"autoFixPaths": true, "preserveOriginals": true, "backupBeforeModify": true, "pathMappings": {"~/.pi/agent/skills": "${SKILLS_DIR}", "~/.claude/skills": "${CLAUDE_SKILLS_DIR}"}}, "pipeline": {"defaultPhases": ["discover", "assess", "audit", "adapt", "integrate", "report", "notify"], "interactiveMode": false, "stopOnError": true, "verbose": false}, "reports": {"outputDir": "reports", "format": "markdown", "includeDetails": true, "includeRecommendations": true, "keepHistory": true}}技能管理系统 - 使用示例
示例 1: 完整的技能搜索、选择、评估流程
步骤 1: 启动流程并搜索技能
bun ~/.pi/agent/skills/skill-management/scripts/pipeline.ts "claude office" --interactive输出:
🚀 技能管理流程启动
搜索关键词: claude office
交互模式: ✅
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🔍 Phase 1: 搜索技能
搜索: claude office
找到 5 个技能
📋 Phase 2: 选择技能
💡 请使用 interview 工具让用户选择技能
配置文件: /tmp/skill-pipeline/select-config.json
⏸️ 等待用户选择...步骤 2: Pi Agent 读取选择配置并使用 interview
# Pi Agent 读取配置
read /tmp/skill-pipeline/select-config.json配置内容:
{
"title": "选择要安装的技能",
"description": "根据搜索结果,请选择要安装和评估的技能",
"questions": [
{
"id": "skill_choice",
"type": "single",
"question": "请选择要安装的技能:",
"options": [
"tfriedel/claude-office-skills ⭐ 211★ - Office document creation and editing skills for Claude Code...",
"anthropics/skills ⭐ 150★ - Official Claude skills repository...",
"badlogic/skills ⭐ 85★ - Pi Agent skills repository...",
"user/office-automation ⭐ 45★ - Office automation tools...",
"dev/document-processor ⭐ 20★ - Document processing utilities..."
],
"recommended": "tfriedel/claude-office-skills"
}
]
}步骤 3: Pi Agent 使用 interview 工具
# Pi Agent 使用 interview 工具
interview /tmp/skill-pipeline/select-config.json用户看到交互式表单:
┌─────────────────────────────────────────────────────┐
│ 选择要安装的技能 │
├─────────────────────────────────────────────────────┤
│ 根据搜索结果,请选择要安装和评估的技能 │
├─────────────────────────────────────────────────────┤
│ │
│ Q1: 请选择要安装的技能: │
│ ● tfriedel/claude-office-skills ⭐ 211★ │
│ Office document creation and editing... │
│ ○ anthropics/skills ⭐ 150★ │
│ Official Claude skills repository... │
│ ○ badlogic/skills ⭐ 85★ │
│ Pi Agent skills repository... │
│ ○ user/office-automation ⭐ 45★ │
│ Office automation tools... │
│ ○ dev/document-processor ⭐ 20★ │
│ Document processing utilities... │
│ │
│ Q2: 自定义技能名称(可选): │
│ ┌─────────────────────────────────────────┐ │
│ │ office-combo │ │
│ └─────────────────────────────────────────┘ │
│ │
│ Q3: 任何额外的要求或说明: │
│ ┌─────────────────────────────────────────┐ │
│ │ 需要支持 PDF、Word、Excel、PPT │ │
│ └─────────────────────────────────────────┘ │
│ │
│ [提交] [取消] │
└─────────────────────────────────────────────────────┘步骤 4: 用户提交选择,Pi Agent 介绍技能
用户选择 tfriedel/claude-office-skills 后,Pi Agent 会:
1. 读取技能 README
# Pi Agent 读取 README
gh repo view tfriedel/claude-office-skills2. 介绍技能详情
📝 技能介绍
名称: claude-office-skills
作者: tfriedel
星标: 211★
Forks: 35
最后更新: 2026-01-24
功能:
- ✅ PowerPoint (PPTX) - 创建演示文稿、HTML 转 PPTX
- ✅ Word (DOCX) - 文档编辑、修订跟踪、注释
- ✅ Excel (XLSX) - 财务模型、公式、数据分析
- ✅ PDF - 表单填写、文档合并、数据提取
特点:
- 🎨 HTML-to-PPTX 转换
- 🔍 专业的修订跟踪工作流
- 📊 零错误的公式要求
- 📝 完整的文档和示例
该技能包含 4 个子技能,完全符合您的需求!3. 询问用户是否继续安装
# Pi Agent 使用 interview
interview ~/.pi/agent/skills/skill-management/.interview-config.json用户看到:
┌─────────────────────────────────────────┐
│ 确认安装技能 │
├─────────────────────────────────────────┤
│ │
│ 是否安装 claude-office-skills? │
│ │
│ ● 是,继续安装 (推荐) │
│ ○ 否,重新选择 │
│ ○ 取消 │
│ │
│ [提交] [取消] │
└─────────────────────────────────────────┘步骤 5: 用户确认安装
用户选择"是,继续安装"后,流程继续:
📥 Phase 3: 发现技能
克隆仓库: tfriedel/claude-office-skills
安装技能: office-combo
✅ 找到 4 个技能
📊 Phase 4: 评估技能
🤖 调用 Pi Agent 进行深度分析...
分析提示已生成: /tmp/skill-assessment-prompt.md
请让 Pi Agent 阅读该文件并进行分析
✅ 评估完成
💡 请阅读分析提示并使用 interview 工具询问用户
分析提示: /tmp/skill-assessment-prompt.md
⏸️ 等待用户决策...步骤 6: Pi Agent 评估技能
# Pi Agent 读取评估提示
read /tmp/skill-assessment-prompt.mdPi Agent 进行分析并输出:
{
"rationality": true,
"score": 95,
"issues": [],
"strengths": [
"SKILL.md 格式规范,描述清晰",
"功能完整,支持 4 种 Office 格式",
"文档齐全,包含详细的工作流程",
"脚本数量适中,代码质量高"
],
"weaknesses": [],
"security": {
"passed": true,
"findings": []
},
"recommendations": [],
"analysis": "该技能整体设计优秀,完全满足 Office 文档处理需求..."
}然后 Pi Agent 使用 interview 询问用户是否继续。
步骤 7: 继续后续流程
用户确认后,流程继续执行安全审计、适应性改造、融合测试等步骤。
---
示例 2: 快速搜索并自动选择
# 搜索并自动选择星标最高的技能
bun ~/.pi/agent/skills/skill-management/scripts/pipeline.ts "pdf processing"流程会: 1. 搜索技能 2. 自动选择第一个(星标最高) 3. 安装并评估 4. 生成报告
---
示例 3: 仅搜索技能列表
# 搜索技能
bun ~/.pi/agent/skills/gh-skill-finder/scripts/search.ts "browser" --sort stars --details输出:
🔍 搜索技能: browser
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✅ 找到 5 个技能:
1. anthropic/browser-tool
⭐ 120★ - Browser automation tool for Claude...
📦 语言: TypeScript
🔀 Forks: 25
📅 更新: 2026-01-20
2. user/web-scraper
⭐ 85★ - Web scraping utilities...
📦 语言: Python
🔀 Forks: 15
📅 更新: 2026-01-15
3. dev/selenium-wrapper
⭐ 45★ - Selenium wrapper for easy use...
📦 语言: Python
🔀 Forks: 8
📅 更新: 2025-12-20
...---
关键要点
1. 技能选择的三个步骤
1. 搜索 - 使用 gh search 获取候选列表 2. 展示 - Pi Agent 使用 interview 工具展示列表 3. 介绍 - Pi Agent 介绍选中技能的详情
2. Pi Agent 的角色
- 读取选择配置
- 使用 interview 工具展示表单
- 介绍选中技能的功能和特点
- 询问用户是否继续
3. 用户的角色
- 通过 interview 工具选择技能
- 查看技能介绍
- 确认是否安装
4. 关键文件
| 文件 | 作用 |
|---|---|
/tmp/skill-pipeline/select-config.json | 技能选择配置 |
/tmp/skill-assessment-prompt.md | 评估分析提示 |
.interview-config.json | interview 配置 |
---
完整流程图
用户: 搜索 "claude office"
↓
脚本: gh search → 获取 5 个候选技能
↓
脚本: 生成 select-config.json
↓
Pi Agent: 使用 interview 展示技能列表
↓
用户: 选择 "tfriedel/claude-office-skills"
↓
Pi Agent: 读取 README,介绍技能详情
↓
Pi Agent: 使用 interview 询问是否安装
↓
用户: 确认安装
↓
脚本: 克隆并安装技能
↓
脚本: 生成评估提示
↓
Pi Agent: 读取并分析技能
↓
Pi Agent: 输出分析结果
↓
Pi Agent: 使用 interview 询问是否继续
↓
用户: 确认继续
↓
脚本: 继续审计、改造、测试
↓
脚本: 生成报告
↓
完成!---
总结
这个流程的核心是:
1. 搜索获取列表 - 使用 gh search 2. interview 展示选择 - Pi Agent 使用 interview 工具 3. Pi Agent 介绍技能 - 读取 README 并介绍 4. 用户确认安装 - 通过 interview 工具 5. Pi Agent 深度分析 - 评估、审计技能 6. 用户决策继续 - 关键节点使用 interview
通过这种方式,用户可以:
- 看到清晰的技能列表
- 了解每个技能的详情
- 参与关键决策
- 获得专业的技能评估
技能管理系统改进总结
🎯 改进目标
基于本次测试(react-best-practices),发现系统存在两个关键问题:
1. 对纯文件处理很差 - 知识型技能被机械评分 40/100,但实际质量很高 2. 脚本太死板 - 缺少 LLM 智能分析能力,评估标准一刀切
✅ 改进内容
1. 智能技能分类
改进前:
- 机械检查目录结构
- 不区分技能类型
- 一刀切评分标准
改进后:
- LLM 自动识别技能类型
- 支持 4 种类型:知识型、工具型、混合型、流程型
分类逻辑:
async function determineSkillType(skillInfo: any): Promise<string> {
const hasScripts = skillInfo.hasScripts;
const content = skillInfo.content.skill.toLowerCase();
if (hasScripts) {
if (content.includes('guide') || content.includes('reference') || content.includes('best practices')) {
return 'hybrid'; // 混合型
}
return 'tool'; // 工具型
}
if (content.includes('guide') || content.includes('reference') || content.includes('best practices') ||
content.includes('tutorial') || content.includes('documentation')) {
return 'knowledge'; // 知识型
}
if (content.includes('workflow') || content.includes('process') || content.includes('steps')) {
return 'process'; // 流程型
}
return 'unknown';
}2. 差异化评估标准
改进前:
- 所有技能使用相同评分标准
- 知识型技能因缺少 scripts/references/assets 被扣分
改进后:
- 根据技能类型使用不同评分权重
| 维度 | 知识型 | 工具型 | 混合型 | 流程型 |
|---|---|---|---|---|
| 内容质量 | 40% | 20% | 30% | 35% |
| 功能完整性 | 20% | 40% | 30% | 25% |
| 实用性 | 20% | 20% | 20% | 20% |
| 文档质量 | 10% | 10% | 10% | 10% |
| 代码质量 | 5% | 10% | 8% | 5% |
| 安全性 | 5% | 10% | 7% | 5% |
3. 差异化安全审计
改进前:
- 所有技能都执行相同的安全检查
- 知识型技能执行不必要的代码检查
改进后:
- 根据技能类型调整审计重点
知识型技能审计重点:
- 内容安全性 - 文档中是否包含危险操作示例?
- 误导性内容 - 是否有错误的安全建议?
- 敏感信息 - 文档中是否泄露敏感信息?
- 链接安全 - 外部链接是否安全可信?
工具型技能审计重点:
- 代码安全 - 危险函数、命令注入、路径遍历
- 依赖安全 - 依赖漏洞、来源可信度
- 数据安全 - 敏感信息、数据泄露
- 权限安全 - 文件权限、网络访问、系统调用
- 错误处理 - 错误信息泄露、异常处理
4. 智能报告生成
改进前:
- 机械生成报告
- 不区分技能类型
- 评分不准确
改进后:
- LLM 根据技能类型生成定制化报告
- 差异化评分权重
- 具体改进建议
报告结构(知识型):
## 1. 执行摘要
## 2. 内容质量分析
- 完整性
- 组织结构
- 可读性
## 3. 功能分析
## 4. 评分明细
- 内容质量 (40%)
- 功能完整性 (20%)
- 实用性 (20%)
- 文档质量 (10%)
- 代码质量 (5%)
- 安全性 (5%)📊 改进效果对比
react-best-practices 评估对比
| 项目 | 改进前 | 改进后 | 说明 |
|---|---|---|---|
| 技能类型识别 | ❌ 未识别 | ✅ knowledge | 自动识别为知识型 |
| 评分标准 | 机械评分 | 差异化评分 | 根据类型调整权重 |
| 综合评分 | 40/100 | 88/100 | 内容质量高 |
| 内容质量评分 | 20/100 | 40/40 | 知识型重点评估 |
| 功能完整性 | 0/100 | 18/20 | 涵盖 8 个类别 |
| 代码质量 | 0/100 | 2/5 | 纯知识型,不适用 |
| 安全性 | 0/100 | 0/5 | 纯文档类型 |
| 评估准确性 | ❌ 低 | ✅ 高 | 反映真实质量 |
office-pdf 评估对比
| 项目 | 改进前 | 改进后 | 说明 |
|---|---|---|---|
| 技能类型识别 | ❌ 未识别 | ✅ tool | 自动识别为工具型 |
| 综合评分 | 75/100 | 75/100 | 功能完整 |
| 内容质量 | 20/100 | 18/20 | SKILL.md 规范 |
| 功能完整性 | 20/100 | 35/40 | 功能完整 |
| 代码质量 | 20/100 | 8/10 | 代码结构清晰 |
| 安全性 | 10/100 | 8/10 | 基本安全 |
🎯 核心改进点
1. 更多使用 LLM 能力
改进前:
- 脚本做机械检查
- LLM 仅用于最终分析
改进后:
- LLM 参与全流程
- 智能分类
- 深度分析
- 定制化报告
LLM 应用场景:
// 1. 智能分类
const skillType = await determineSkillType(skillInfo);
// 2. 生成差异化分析提示
const prompt = generateAnalysisPrompt(skillInfo, skillType);
// 3. 解析 LLM 分析结果
const parsed = parseLLMAnalysis(llmOutput);
// 4. 生成定制化报告
const report = await generateLLMReport(skillInfo, skillType);2. 脚本不再死板
改进前:
// 机械检查
if (!skillInfo.structure.scripts.exists) score -= 15;
if (!skillInfo.structure.references.exists) score -= 10;
if (!skillInfo.structure.assets.exists) score -= 5;改进后:
// 智能判断
if (skillType === 'knowledge') {
// 知识型重点评估内容质量
score += contentQuality * 0.4;
} else if (skillType === 'tool') {
// 工具型重点评估功能和安全
score += functionality * 0.4;
}3. 对纯文件优化处理
改进前:
- 知识型技能因缺少 scripts 被扣分
- 不考虑内容质量
改进后:
- 识别知识型技能
- 重点评估内容质量
- 忽略不相关的目录检查
📝 使用示例
评估知识型技能
bun ~/.pi/agent/skills/skill-management/scripts/assess.ts ~/.pi/agent/skills/react-best-practices输出:
🤖 智能评估: react-best-practices
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📥 收集技能信息...
🧠 LLM 识别技能类型...
技能类型: knowledge (知识型)
🔍 LLM 深度分析...
分析提示: /tmp/skill-assessment-prompt.md
✅ 评估完成
技能类型: knowledge
综合评分: 88/100 - 优秀
合理性: ✅ 通过评估工具型技能
bun ~/.pi/agent/skills/skill-management/scripts/assess.ts ~/.pi/agent/skills/office-pdf输出:
🤖 智能评估: office-pdf
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📥 收集技能信息...
🧠 LLM 识别技能类型...
技能类型: tool (工具型)
🔍 LLM 深度分析...
分析提示: /tmp/skill-assessment-prompt.md
✅ 评估完成
技能类型: tool
综合评分: 75/100 - 良好
合理性: ✅ 通过🎉 总结
改进成果
1. ✅ 智能分类 - 自动识别 4 种技能类型 2. ✅ 差异化评估 - 根据类型使用不同评分标准 3. ✅ 更多 LLM - LLM 参与全流程,不再死板 4. ✅ 优化纯文件 - 知识型技能得到正确评估 5. ✅ 智能报告 - 根据类型生成定制化报告
测试验证
- ✅ react-best-practices: 40/100 → 88/100 (知识型)
- ✅ office-pdf: 75/100 → 75/100 (工具型)
- ✅ 评估准确性大幅提升
- ✅ LLM 能力充分利用
后续优化方向
1. 更精细的分类 - 子类型识别(如 knowledge-guide, knowledge-reference) 2. 自适应评分 - 根据技能特点动态调整权重 3. 更多 LLM 场景 - 自动化改进建议生成 4. 历史对比 - 跟踪技能版本变化
---
改进完成时间: 2026-01-24 测试技能: react-best-practices, office-pdf 改进状态: ✅ 完成
技能全生命周期管理系统
完整的技能管理流程,从搜索、选择到评估、部署的端到端管理。
🎯 核心设计理念
这个系统采用三层架构:
1. 脚本层 - 收集信息、执行命令、准备数据 2. Pi Agent 层 - 进行深度分析,使用 interview 工具协调用户交互 3. 用户层 - 通过 interview 工具进行决策和反馈
🔄 完整工作流程
┌─────────────┐
│ 搜索技能 │ ← 脚本:gh search,获取候选列表
└──────┬──────┘
│
┌──────▼──────┐
│ 选择技能 │ ← Pi Agent:使用 interview 展示列表 + 介绍
└──────┬──────┘
│
┌──────▼──────┐
│ 发现技能 │ ← 脚本:克隆仓库、查找 SKILL.md
└──────┬──────┘
│
┌──────▼──────┐
│ 评估技能 │ ← 脚本:收集信息 → Pi Agent:深度分析 → 用户:决策
└──────┬──────┘
│
┌──────▼──────┐
│ 安全审计 │ ← 脚本:基础检查 → Pi Agent:深度审计 → 用户:决策
└──────┬──────┘
│
┌──────▼──────┐
│ 适应性改造 │ ← 脚本:分析需求
└──────┬──────┘
│
┌──────▼──────┐
│ 融合测试 │ ← 脚本:兼容性检查
└──────┬──────┘
│
┌──────▼──────┐
│ 生成报告 │ ← 脚本:汇总结果
└──────┬──────┘
│
┌──────▼──────┐
│ 用户通知 │ ← 脚本:显示摘要
└─────────────┘🚀 快速开始
方式 1: 完整交互式流程(推荐)
# 搜索并选择技能
bun ~/.pi/agent/skills/skill-management/scripts/pipeline.ts "claude office" --interactive流程说明: 1. 搜索 - 使用 gh search 搜索技能 2. 选择 - Pi Agent 使用 interview 工具展示技能列表,用户选择 3. 发现 - 克隆并安装选中的技能 4. 评估 - Pi Agent 分析并询问用户是否继续 5. 审计 - Pi Agent 审计并询问用户是否继续 6. 改造 - 分析适配需求 7. 测试 - 兼容性检查 8. 报告 - 生成评估报告 9. 通知 - 显示完成摘要
方式 2: 自动选择第一个
# 自动选择星标最高的技能
bun ~/.pi/agent/skills/skill-management/scripts/pipeline.ts "pdf processing"方式 3: 分步手动流程
# 1. 搜索技能
bun ~/.pi/agent/skills/gh-skill-finder/scripts/search.ts "claude office" --sort stars
# 2. 选择技能(Pi Agent 使用 interview)
bun ~/.pi/agent/skills/skill-management/scripts/select.ts --list "tfriedel/claude-office-skills,anthropics/skills"
# 3. 安装技能
bun ~/.pi/agent/skills/gh-skill-finder/scripts/install.ts tfriedel/claude-office-skills office
# 4. 评估技能(生成分析提示)
bun ~/.pi/agent/skills/skill-management/scripts/assess.ts ~/.pi/agent/skills/office-pdf
# 5. Pi Agent 读取并分析
read /tmp/skill-assessment-prompt.md
# 6. Pi Agent 使用 interview 询问用户
interview ~/.pi/agent/skills/skill-management/.interview-config.json📋 技能选择流程(关键)
1. 搜索获取候选列表
bun ~/.pi/agent/skills/gh-skill-finder/scripts/search.ts "claude office" --sort stars输出示例:
🔍 搜索技能: claude office
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✅ 找到 5 个技能:
1. tfriedel/claude-office-skills
⭐ 211★ - Office document creation and editing skills for Claude Code...
2. anthropics/skills
⭐ 150★ - Official Claude skills repository...
3. badlogic/skills
⭐ 85★ - Pi Agent skills repository...
4. user/office-automation
⭐ 45★ - Office automation tools...
5. dev/document-processor
⭐ 20★ - Document processing utilities...2. Pi Agent 使用 interview 工具展示选择
# 读取选择配置
cat /tmp/skill-pipeline/select-config.json
# 使用 interview 工具
interview /tmp/skill-pipeline/select-config.json3. 用户看到交互式表单
┌─────────────────────────────────────────────────────┐
│ 选择要安装的技能 │
├─────────────────────────────────────────────────────┤
│ 根据搜索结果,请选择要安装和评估的技能 │
├─────────────────────────────────────────────────────┤
│ │
│ Q1: 请选择要安装的技能: │
│ ○ tfriedel/claude-office-skills ⭐ 211★ │
│ Office document creation and editing... │
│ ○ anthropics/skills ⭐ 150★ │
│ Official Claude skills repository... │
│ ○ badlogic/skills ⭐ 85★ │
│ Pi Agent skills repository... │
│ ○ user/office-automation ⭐ 45★ │
│ Office automation tools... │
│ ● dev/document-processor ⭐ 20★ │
│ Document processing utilities... │
│ │
│ Q2: 自定义技能名称(可选): │
│ ┌─────────────────────────────────────────┐ │
│ │ │ │
│ └─────────────────────────────────────────┘ │
│ │
│ Q3: 任何额外的要求或说明: │
│ ┌─────────────────────────────────────────┐ │
│ │ │ │
│ └─────────────────────────────────────────┘ │
│ │
│ [提交] [取消] │
└─────────────────────────────────────────────────────┘4. Pi Agent 介绍选中的技能
用户选择后,Pi Agent 会:
- 读取选中技能的 README.md
- 分析技能的功能和特点
- 向用户介绍技能详情
- 询问是否继续安装
🤖 Pi Agent 分析流程
评估阶段
1. 脚本收集信息
- SKILL.md 内容
- 所有脚本文件
- 依赖项配置
- 目录结构
2. 脚本生成分析提示
# 保存到
/tmp/skill-assessment-prompt.md3. Pi Agent 读取并分析
read /tmp/skill-assessment-prompt.md4. Pi Agent 输出分析结果
- 合理性评分
- 功能分析
- 安全性评估
- 代码质量
- 适配性分析
5. Pi Agent 使用 interview 询问用户
interview ~/.pi/agent/skills/skill-management/.interview-config.json📁 文件结构
~/.pi/agent/skills/skill-management/
├── SKILL.md # 本文档
├── README.md # 使用说明
├── config.json # 配置文件
├── scripts/
│ ├── assess.ts # 评估脚本
│ ├── audit.ts # 审计脚本
│ ├── pipeline.ts # 完整流程脚本
│ ├── select.ts # 技能选择脚本
│ ├── interactive.ts # 交互式决策脚本
│ ├── report.ts # 报告生成脚本
│ └── notify.ts # 通知脚本
├── reports/ # 评估报告目录
└── templates/ # 模板文件
/tmp/skill-pipeline/
├── select-config.json # 技能选择配置
├── decision-assess.json # 评估决策文件
└── decision-audit.json # 审计决策文件
/tmp/
├── skill-assessment-prompt.md # Pi Agent 评估分析提示
└── skill-security-audit-prompt.md # Pi Agent 安全审计提示🎨 核心特性
1. 智能搜索
- 使用 GitHub CLI 搜索
- 按星标、更新时间排序
- 支持关键词、语言、话题筛选
2. 交互式选择
- 使用 interview 工具展示列表
- Pi Agent 介绍每个技能
- 用户自由选择
3. 深度分析
- Pi Agent 进行全面评估
- 分析合理性、功能性、安全性
- 检查代码质量和适配性
4. 用户决策
- 关键节点使用 interview 工具
- 用户确认是否继续
- 提供反馈和建议
5. 完整报告
- 汇总所有分析结果
- 记录用户决策
- 提供后续建议
📊 分析维度
评估维度
- 合理性:SKILL.md 格式、目录结构、依赖项、文档
- 功能性:核心功能、完整性、缺陷、优势劣势
- 安全性:危险操作、敏感信息、文件操作、命令注入
- 代码质量:结构、错误处理、注释、最佳实践
- 适配性:环境依赖、路径引用、改造需求
审计维度
- 代码安全:危险函数、命令注入、路径遍历、输入验证
- 依赖安全:依赖漏洞、来源可信度、更新频率
- 数据安全:敏感信息、数据泄露、加密传输
- 权限安全:文件权限、网络访问、系统调用
- 错误处理:错误信息泄露、异常处理、日志安全
📝 使用示例
示例 1: 搜索并选择 Office 技能
# 启动完整流程
bun ~/.pi/agent/skills/skill-management/scripts/pipeline.ts "claude office" --interactive
# 流程会自动:
# 1. 搜索 office 相关技能
# 2. 使用 interview 展示技能列表
# 3. 用户选择一个技能
# 4. Pi Agent 介绍技能并询问是否安装
# 5. 安装并评估技能
# 6. 生成报告示例 2: 仅搜索技能
# 搜索技能
bun ~/.pi/agent/skills/gh-skill-finder/scripts/search.ts "pdf" --sort stars --details
# 输出技能列表和详细信息示例 3: 手动选择并评估
# 1. 从列表中选择一个技能
bun ~/.pi/agent/skills/skill-management/scripts/select.ts --list "tfriedel/claude-office-skills,anthropics/skills"
# 2. 安装技能
bun ~/.pi/agent/skills/gh-skill-finder/scripts/install.ts tfriedel/claude-office-skills office
# 3. 评估技能
bun ~/.pi/agent/skills/skill-management/scripts/assess.ts ~/.pi/agent/skills/office
# 4. Pi Agent 读取并分析
read /tmp/skill-assessment-prompt.md
# 5. Pi Agent 使用 interview 询问用户
interview ~/.pi/agent/skills/skill-management/.interview-config.json🎯 最佳实践
1. 先搜索后选择 - 用关键词搜索,查看候选列表 2. 充分利用 interview - 让用户参与关键决策 3. 仔细阅读分析 - Pi Agent 的分析很有价值 4. 保留分析记录 - LLM 分析结果应该保存 5. 迭代优化 - 根据反馈改进流程
📚 相关技能
gh-skill-finder- 技能发现和搜索工具interview- 用户交互工具(Pi Agent 内置)
🔗 工具链
gh-skill-finder (搜索)
↓
skill-management (管理)
├─ select.ts → interview (选择技能)
├─ assess.ts → Pi Agent 分析 → interview (评估决策)
├─ audit.ts → Pi Agent 分析 → interview (审计决策)
└─ pipeline.ts (完整流程)🚨 注意事项
1. Pi Agent 是核心 - 脚本收集信息,Pi Agent 进行分析 2. interview 是关键 - 用户决策通过 interview 工具 3. 提示文件是桥梁 - /tmp/skill-*.md 是脚本和 Pi Agent 的桥梁 4. 选择配置很重要 - select-config.json 用于技能选择 5. 用户参与决策 - 在关键节点必须询问用户
技能评估报告: office-pdf
生成时间: 2026/1/24 10:42:00 技能名称: pdf 综合评分: 75/100
---
1. 基本信息
- 技能名称: pdf
- 描述: Comprehensive PDF manipulation toolkit for extracting text and tables, creating new PDFs, merging/splitting documents, and handling forms. When Claude needs to fill in a PDF form or programmatically process, generate, or analyze PDF documents at scale.
- 大小: 88K
- 文件数: 11
- 目录数: 2
- 最后修改: 2026-01-24 10:36:07
---
2. 目录结构
| 目录 | 状态 | 文件数 |
|---|---|---|
| scripts/ | ✅ | 8 |
| references/ | ❌ | 0 |
| assets/ | ❌ | 0 |
---
3. 依赖项
Python 依赖
无
Node.js 依赖
无
开发依赖
无
---
4. 脚本文件
| 文件名 | 大小 | 权限 | 行数 |
|---|---|---|---|
| fill_fillable_fields.py | undefined | /Users/dengwenyu/.pi/agent/skills/office-pdf/scripts/fill_fillable_fields.py | 114 |
| convert_pdf_to_images.py | undefined | /Users/dengwenyu/.pi/agent/skills/office-pdf/scripts/convert_pdf_to_images.py | 35 |
| extract_form_field_info.py | undefined | /Users/dengwenyu/.pi/agent/skills/office-pdf/scripts/extract_form_field_info.py | 152 |
| check_bounding_boxes.py | undefined | /Users/dengwenyu/.pi/agent/skills/office-pdf/scripts/check_bounding_boxes.py | 70 |
| check_bounding_boxes_test.py | undefined | /Users/dengwenyu/.pi/agent/skills/office-pdf/scripts/check_bounding_boxes_test.py | 226 |
| create_validation_image.py | undefined | /Users/dengwenyu/.pi/agent/skills/office-pdf/scripts/create_validation_image.py | 41 |
| fill_pdf_form_with_annotations.py | undefined | /Users/dengwenyu/.pi/agent/skills/office-pdf/scripts/fill_pdf_form_with_annotations.py | 107 |
| check_fillable_fields.py | undefined | /Users/dengwenyu/.pi/agent/skills/office-pdf/scripts/check_fillable_fields.py | 12 |
---
5. 参考资料
无参考资料
---
6. 资源文件
无资源文件
---
7. 评分详情
| 项目 | 得分 | 说明 |
|---|---|---|
| SKILL.md 格式 | 20 | YAML 前言完整性 |
| 描述完整性 | 10 | 名称和描述 |
| 目录结构 | 15 | scripts/、references/、assets/ |
| 脚本数量 | 20 | 8 个脚本 |
| 文档数量 | 0 | 0 个文档 |
| 依赖合理性 | 10 | 依赖项管理 |
| 总分 | 75 | 满分 100 |
---
8. 评估结论
✅ 优势
- 技能结构完整
- 文档齐全
- 符合规范
⚠️ 不足
- 评分较低,建议优化
- 补充文档和脚本
- 完善依赖管理
💡 建议
1. 保持现有质量 2. 保持脚本质量 3. 添加 references/ 目录存放文档 4. 保持无依赖状态
---
9. 使用指南
安装位置
/Users/dengwenyu/.pi/agent/skills/office-pdf
文档位置
/Users/dengwenyu/.pi/agent/skills/office-pdf/SKILL.md
快速开始
# 查看技能文档
bat ~/.pi/agent/skills/office-pdf/SKILL.md
# 列出脚本文件
ls -la ~/.pi/agent/skills/office-pdf/scripts/
# 查看参考资料
ls -la ~/.pi/agent/skills/office-pdf/references/---
10. 附录
YAML 前言
name: pdf
description: Comprehensive PDF manipulation toolkit for extracting text and tables, creating new PDFs, merging/splitting documents, and handling forms. When Claude needs to fill in a PDF form or programmatically process, generate, or analyze PDF documents at scale.React Best Practices 技能评估报告
生成时间: 2026/1/24 11:15:00 技能仓库: michaelshimeles/react-best-practices 作者: Vercel Engineering 许可证: MIT
---
📋 执行摘要
✅ 搜索 → ✅ 选择 → ✅ 安装 → ✅ 评估 → ✅ 安全审计 → ✅ 报告
用户决策: 继续安装,完全接受评估结果
---
🎯 Pi Agent 深度评估
评估评分: 88/100 - 优秀
✅ 优势
1. 专业性高 - 来自 Vercel Engineering,权威性高 2. 内容完整 - 涵盖 8 个类别,40+ 条性能优化规则 3. 结构清晰 - 按优先级(CRITICAL/HIGH/MEDIUM/LOW)组织 4. 实用性强 - 每条规则都有代码示例和对比 5. 无依赖 - 开箱即用,无需安装额外工具 6. 安全性好 - 无危险操作,无敏感信息 7. SKILL.md 规范 - YAML 前言完整,描述清晰
⚠️ 不足
1. 缺少详细文档 - references/ 目录缺失 2. 缺少工具 - 没有 scripts/ 和辅助工具 3. 缺少示例 - 没有 assets/ 和示例代码 4. 文件缺失 - 提到的 react-performance-guidelines.md 不存在
📊 功能覆盖
| 类别 | 优先级 | 规则数 | 状态 |
|---|---|---|---|
| Eliminating Waterfalls | CRITICAL | 5 | ✅ |
| Bundle Size Optimization | CRITICAL | 5 | ✅ |
| Server-Side Performance | HIGH | 4 | ✅ |
| Client-Side Data Fetching | MEDIUM-HIGH | 2 | ✅ |
| Re-render Optimization | MEDIUM | 6 | ✅ |
| Rendering Performance | MEDIUM | 7 | ✅ |
| JavaScript Performance | LOW-MEDIUM | 11 | ✅ |
| Advanced Patterns | LOW | 2 | ✅ |
---
🔒 安全审计
安全评分: 95/100 - 优秀
✅ 安全性分析
| 维度 | 状态 | 说明 |
|---|---|---|
| 代码安全 | ✅ | 无脚本文件,无危险函数 |
| 依赖安全 | ✅ | 无外部依赖 |
| 数据安全 | ✅ | 无敏感信息 |
| 权限安全 | ✅ | 无文件操作需求 |
| 错误处理 | ✅ | 纯文档类型,不适用 |
🎯 审计结论
这是一个纯知识型技能,仅包含文档和指南,没有任何可执行代码。不存在任何安全风险,可以安全使用。
---
📚 技能内容概览
核心功能
React Best Practices 是一个全面的 React 和 Next.js 性能优化指南,包含:
1. 消除瀑布流 (CRITICAL)
- 延迟 await 到使用点
- 使用 Promise.all() 并行化
- 防止 API 路由中的瀑布链
- 策略性 Suspense 边界
2. Bundle 优化 (CRITICAL)
- 避免桶文件导入
- 条件模块加载
- 动态导入重型组件
- 基于用户意图的预加载
3. 服务端性能 (HIGH)
- 跨请求 LRU 缓存
- RSC 边界的最小化序列化
- 组件组合的并行数据获取
4. 客户端数据获取 (MEDIUM-HIGH)
- 全局事件监听器去重
- SWR 自动去重
5. 重渲染优化 (MEDIUM)
- 延迟状态读取
- 提取记忆化组件
- 窄化 effect 依赖
- 使用过渡进行非紧急更新
6. 渲染性能 (MEDIUM)
- SVG 包装器动画
- CSS content-visibility
- 提升静态 JSX 元素
7. JavaScript 性能 (LOW-MEDIUM)
- 批处理 DOM CSS 更改
- 构建索引映射
- 缓存属性访问
- 使用 Set/Map 进行 O(1) 查找
8. 高级模式 (LOW)
- 在 refs 中存储事件处理程序
- useLatest 用于稳定的回调引用
使用场景
✅ 适合使用:
- React/Next.js 应用性能优化
- 代码审查和重构
- 学习 React 最佳实践
- 性能问题排查
- 减少包大小
- 消除请求瀑布流
---
📈 关键性能指标
技能文档中提到的关键指标:
- Time to Interactive (TTI) - 页面变为完全可交互的时间
- Largest Contentful Paint (LCP) - 主要内容可见的时间
- First Input Delay (FID) - 对用户交互的响应速度
- Cumulative Layout Shift (CLS) - 视觉稳定性
- Bundle size - 初始 JavaScript 负载
- Server response time - 服务端渲染内容的 TTFB
---
💡 推荐改进
短期改进
1. 添加 references/ 目录
- 创建详细的性能指南文档
- 补充缺失的 react-performance-guidelines.md
- 添加更多实际案例
2. 创建 scripts/ 目录
- 性能检查工具
- Bundle 大小分析脚本
- 代码质量检查器
3. 添加 assets/ 目录
- 示例项目模板
- 性能优化前后对比
- 可视化图表
长期改进
1. 自动化工具
- 性能分析 CLI 工具
- 代码审查自动化
- 性能报告生成器
2. 示例库
- 完整的项目示例
- 不同场景的优化案例
- 性能测试基准
3. 交互式指南
- 在线性能优化教程
- 实时代码编辑器
- 性能对比演示
---
🎯 使用建议
何时使用
# 当你需要优化 React 应用性能时
# 当你进行代码审查时
# 当你学习 React 最佳实践时
# 当你排查性能问题时如何使用
1. 阅读 SKILL.md
cat ~/.pi/agent/skills/react-best-practices/SKILL.md2. 参考相关规则
- 根据优先级(CRITICAL → HIGH → MEDIUM → LOW)
- 查看代码示例
- 应用优化建议
3. 测量影响
- 使用 React DevTools Profiler
- 使用浏览器性能工具
- 验证改进效果
---
📋 总结
✅ 推荐使用
React Best Practices 是一个高质量的知识型技能,适合作为 React 性能优化的参考指南。
优点:
- 专业性高,来自 Vercel Engineering
- 内容完整,覆盖 8 个类别 40+ 条规则
- 结构清晰,按优先级组织
- 实用性强,每条都有代码示例
- 无依赖,开箱即用
- 安全性高,无风险
缺点:
- 缺少配套文档和工具
- 缺少示例代码和模板
适用场景:
- React/Next.js 性能优化
- 代码审查和重构
- 学习最佳实践
- 性能问题排查
最终评分: 88/100 - 优秀,建议使用
---
🔗 相关资源
- React Documentation
- Next.js Documentation
- SWR Documentation
- Vercel Bundle Optimization
- Vercel Dashboard Performance
---
📊 LLM 分析文件
- 评估分析:
/tmp/skill-assessment-prompt.md - 安全审计:
/tmp/skill-security-audit-prompt.md
---
报告生成者: Pi Agent 报告版本: 1.0.0 评估日期: 2026-01-24
remotion-best-practices 评估报告
生成时间: 2026/1/24 11:31:10 技能类型: knowledge 作者: Unknown 版本: N/A
---
🤖 LLM 智能分析
请阅读报告提示文件并生成详细分析:
read /tmp/skill-report-prompt.md然后根据提示生成完整的评估报告。
---
📊 基础信息
- 文件数量: 32
- 脚本文件: ❌
- 参考资料: ❌
- 资源文件: ❌
- Python 依赖: 0
- Node.js 依赖: 0
---
📚 技能描述
Best practices for Remotion - Video creation in React
---
🏷️ 标签
无
---
📄 完整报告生成中...
请让 Claude 阅读 /tmp/skill-report-prompt.md 并生成完整的评估报告。
#!/usr/bin/env bun
/**
* 智能评估脚本 - 使用 LLM 进行智能分析和判断
*/
import { $ } from 'bun';
interface AssessmentOptions {
llm?: boolean;
verbose?: boolean;
}
interface SkillType {
type: 'knowledge' | 'tool' | 'hybrid';
confidence: number;
reason: string;
}
interface AssessmentResult {
skillName: string;
skillType: SkillType;
rationality: boolean;
score: number;
details: any;
llmAnalysis?: string;
issues: string[];
strengths: string[];
weaknesses: string[];
}
async function assessSkill(skillPath: string, options: AssessmentOptions = {}) {
const skillName = skillPath.split('/').pop() || skillPath;
console.log(`\n🤖 智能评估: ${skillName}`);
console.log('━'.repeat(60));
const result: AssessmentResult = {
skillName,
skillType: { type: 'knowledge', confidence: 0, reason: '' },
rationality: true,
score: 0,
details: {},
issues: [],
strengths: [],
weaknesses: []
};
// 步骤 1: 收集技能信息
console.log(`\n📥 收集技能信息...`);
const skillInfo = await collectSkillInfo(skillPath);
result.details = skillInfo;
// 步骤 2: LLM 智能识别技能类型
console.log(`\n🧠 LLM 识别技能类型...`);
const skillType = await identifySkillType(skillInfo);
result.skillType = skillType;
console.log(` 类型: ${skillType.type} (置信度: ${skillType.confidence}%)`);
console.log(` 原因: ${skillType.reason}`);
// 步骤 3: LLM 深度分析
console.log(`\n🔍 LLM 深度分析...`);
const llmAnalysis = await performLLMAnalysis(skillInfo, skillType);
result.llmAnalysis = llmAnalysis;
// 步骤 4: 解析 LLM 分析结果
console.log(`\n📊 解析分析结果...`);
const parsed = parseLLMAnalysis(llmAnalysis, skillType);
result.rationality = parsed.rationality;
result.score = parsed.score;
result.issues.push(...parsed.issues);
result.strengths.push(...parsed.strengths);
result.weaknesses.push(...parsed.weaknesses);
// 输出结果
console.log(`\n✅ 评估完成`);
console.log(` 技能类型: ${result.skillType.type}`);
console.log(` 综合评分: ${result.score}/100`);
console.log(` 合理性: ${result.rationality ? '✅ 通过' : '❌ 不通过'}`);
if (result.strengths.length > 0) {
console.log(`\n💪 优势 (${result.strengths.length}):`);
result.strengths.slice(0, 3).forEach((s, i) => {
console.log(` ${i + 1}. ${s}`);
});
}
if (result.issues.length > 0) {
console.log(`\n⚠️ 问题 (${result.issues.length}):`);
result.issues.slice(0, 3).forEach((issue, i) => {
console.log(` ${i + 1}. ${issue}`);
});
}
return result;
}
async function collectSkillInfo(skillPath: string) {
const info: any = {
path: skillPath,
files: [],
structure: {},
content: {}
};
// 读取 SKILL.md
const skillFile = `${skillPath}/SKILL.md`;
if (await $`test -f ${skillFile}`.quiet().then(() => true).catch(() => false)) {
info.content.skill = await Bun.file(skillFile).text();
}
// 列出所有文件
const findProc = await $`find ${skillPath} -type f`.quiet();
info.files = findProc.stdout.toString().trim().split('\n').filter(Boolean);
// 检查目录结构
const dirs = ['scripts', 'references', 'assets'];
for (const dir of dirs) {
const exists = await $`test -d ${skillPath}/${dir}`.quiet().then(() => true).catch(() => false);
info.structure[dir] = {
exists,
files: exists ? await countFiles(`${skillPath}/${dir}`) : 0
};
}
// 读取脚本文件内容
if (info.structure.scripts.exists) {
info.content.scripts = {};
for (const file of info.files) {
if (file.includes('/scripts/')) {
const name = file.split('/').pop();
try {
info.content.scripts[name!] = await Bun.file(file).text();
} catch (e) {
info.content.scripts[name!] = '[读取失败]';
}
}
}
}
// 读取参考资料
if (info.structure.references.exists) {
info.content.references = {};
for (const file of info.files) {
if (file.includes('/references/')) {
const name = file.split('/').pop();
try {
info.content.references[name!] = await Bun.file(file).text();
} catch (e) {
info.content.references[name!] = '[读取失败]';
}
}
}
}
// 读取依赖文件
const requirementsPath = `${skillPath}/requirements.txt`;
if (await $`test -f ${requirementsPath}`.quiet().then(() => true).catch(() => false)) {
info.content.dependencies = await Bun.file(requirementsPath).text();
}
const packageJsonPath = `${skillPath}/package.json`;
if (await $`test -f ${packageJsonPath}`.quiet().then(() => true).catch(() => false)) {
info.content.packageJson = await Bun.file(packageJsonPath).text();
}
return info;
}
/**
* LLM 智能识别技能类型
*/
async function identifySkillType(skillInfo: any): Promise<SkillType> {
const prompt = generateTypeIdentificationPrompt(skillInfo);
// 写入提示文件
const promptFile = '/tmp/skill-type-identification.md';
await Bun.write(promptFile, prompt);
console.log(` 提示文件: ${promptFile}`);
console.log(` ⚠️ 请 LLM 读取此文件并识别技能类型`);
// 返回默认值,实际类型由 LLM 确定
return {
type: 'knowledge',
confidence: 0,
reason: '等待 LLM 分析'
};
}
function generateTypeIdentificationPrompt(skillInfo: any): string {
return `# 技能类型识别请求
请分析以下技能,识别其类型并给出置信度。
## 技能信息
### SKILL.md 内容
\`\`\`
${skillInfo.content.skill || '无 SKILL.md 文件'}
\`\`\`
### 目录结构
- scripts/: ${skillInfo.structure.scripts?.exists ? `✅ 存在 (${skillInfo.structure.scripts.files} 个文件)` : '❌ 不存在'}
- references/: ${skillInfo.structure.references?.exists ? `✅ 存在 (${skillInfo.structure.references.files} 个文件)` : '❌ 不存在'}
- assets/: ${skillInfo.structure.assets?.exists ? `✅ 存在 (${skillInfo.structure.assets.files} 个文件)` : '❌ 不存在'}
### 文件列表
${skillInfo.files.map(f => `- ${f}`).join('\n')}
### 脚本内容 (${Object.keys(skillInfo.content.scripts || {}).length} 个)
${Object.keys(skillInfo.content.scripts || {}).map(name => `#### ${name}\n\`\`\`\n${skillInfo.content.scripts[name].substring(0, 200)}...\n\`\`\``).join('\n\n')}
### 参考资料 (${Object.keys(skillInfo.content.references || {}).length} 个)
${Object.keys(skillInfo.content.references || {}).map(name => `- ${name}`).join('\n')}
### 依赖项
\`\`\`
Python: ${skillInfo.content.dependencies || '无'}
\`\`\`
\`\`\`
Node.js: ${skillInfo.content.packageJson || '无'}
\`\`\`
## 技能类型定义
### 1. 知识型 (knowledge)
- 主要提供知识、指南、最佳实践
- SKILL.md 包含详细的说明和示例
- 可能没有 scripts/ 目录
- 适合作为参考文档使用
- 例如: React Best Practices, Code Style Guide
### 2. 工具型 (tool)
- 提供可执行的脚本和工具
- 有 scripts/ 目录,包含可执行代码
- 可能需要依赖项
- 适合执行特定任务
- 例如: PDF 处理工具, 代码格式化器
### 3. 混合型 (hybrid)
- 既有知识内容,也有工具脚本
- SKILL.md 包含说明,scripts/ 包含工具
- references/ 可能包含详细文档
- 适合学习和实践结合
- 例如: Office 文档处理技能
## 输出格式
请按照以下格式输出识别结果:
\`\`\`json
{
"type": "knowledge|tool|hybrid",
"confidence": 0-100,
"reason": "详细的判断理由",
"characteristics": ["特征1", "特征2", ...]
}
\`\`\`
## 判断依据
请根据以下特征判断:
- SKILL.md 的内容和结构
- 是否有 scripts/ 目录及其内容
- 是否有 references/ 目录及其内容
- 是否有 assets/ 目录及其内容
- 依赖项的有无和类型
- 文件数量和类型
## 注意事项
- 知识型技能即使没有 scripts/ 目录也可能是优秀的
- 工具型技能的 SKILL.md 可能相对简单
- 混合型技能兼具两者特点
- 给出具体的判断理由
`;
}
/**
* LLM 深度分析
*/
async function performLLMAnalysis(skillInfo: any, skillType: SkillType): Promise<string> {
const prompt = generateAnalysisPrompt(skillInfo, skillType);
// 写入提示文件
const promptFile = '/tmp/skill-assessment-prompt.md';
await Bun.write(promptFile, prompt);
console.log(` 分析提示: ${promptFile}`);
console.log(` ⚠️ 请 LLM 读取此文件并进行深度分析`);
return prompt;
}
function generateAnalysisPrompt(skillInfo: any, skillType: SkillType): string {
const typeSpecificGuidance = {
knowledge: `
## 知识型技能评估重点
知识型技能主要评估:
1. **内容质量** - SKILL.md 的内容是否专业、准确、完整
2. **结构清晰** - 内容组织是否清晰,易于理解
3. **实用性** - 是否提供实际可用的指导和示例
4. **权威性** - 内容来源是否可靠,是否有参考价值
5. **完整性** - 是否覆盖了相关主题的主要方面
**不要求**:
- scripts/ 目录(知识型可能没有)
- references/ 目录(SKILL.md 本身可能已包含)
- assets/ 目录(知识型可能不需要)
**评分标准**:
- 内容质量 (40分)
- 结构清晰 (20分)
- 实用性 (20分)
- 权威性 (10分)
- 完整性 (10分)
`,
tool: `
## 工具型技能评估重点
工具型技能主要评估:
1. **功能完整性** - 工具是否实现了预期的功能
2. **代码质量** - 脚本代码是否清晰、可维护
3. **错误处理** - 是否有适当的错误处理
4. **文档说明** - SKILL.md 是否清楚地说明如何使用
5. **依赖管理** - 依赖项是否合理、必要
**要求**:
- scripts/ 目录(工具型必须有)
- 清晰的使用说明
- 适当的错误处理
**评分标准**:
- 功能完整性 (30分)
- 代码质量 (25分)
- 错误处理 (20分)
- 文档说明 (15分)
- 依赖管理 (10分)
`,
hybrid: `
## 混合型技能评估重点
混合型技能主要评估:
1. **知识内容** - SKILL.md 的内容质量
2. **工具功能** - 脚本工具的功能和代码质量
3. **整合程度** - 知识和工具是否很好地结合
4. **文档完整** - 是否有详细的参考资料
5. **实用性** - 是否能真正帮助用户完成任务
**要求**:
- SKILL.md 内容完整
- scripts/ 目录有实用工具
- references/ 可选但推荐
**评分标准**:
- 知识内容 (30分)
- 工具功能 (30分)
- 整合程度 (20分)
- 文档完整 (10分)
- 实用性 (10分)
`
};
return `# 技能深度分析请求
请对以下技能进行全面分析,按照技能类型使用相应的评估标准。
## 技能类型
**类型**: ${skillType.type}
**置信度**: ${skillType.confidence}%
**判断理由**: ${skillType.reason}
${typeSpecificGuidance[skillType.type]}
## 技能信息
### SKILL.md 内容
\`\`\`
${skillInfo.content.skill || '无 SKILL.md 文件'}
\`\`\`
### 目录结构
- scripts/: ${skillInfo.structure.scripts?.exists ? `✅ 存在 (${skillInfo.structure.scripts.files} 个文件)` : '❌ 不存在'}
- references/: ${skillInfo.structure.references?.exists ? `✅ 存在 (${skillInfo.structure.references.files} 个文件)` : '❌ 不存在'}
- assets/: ${skillInfo.structure.assets?.exists ? `✅ 存在 (${skillInfo.structure.assets.files} 个文件)` : '❌ 不存在'}
### 脚本文件 (${Object.keys(skillInfo.content.scripts || {}).length} 个)
${Object.keys(skillInfo.content.scripts || {}).length > 0
? Object.keys(skillInfo.content.scripts || {}).map(name => `#### ${name}\n\`\`\`\n${skillInfo.content.scripts[name].substring(0, 300)}...\n\`\`\``).join('\n\n')
: '无脚本文件'}
### 参考资料 (${Object.keys(skillInfo.content.references || {}).length} 个)
${Object.keys(skillInfo.content.references || {}).length > 0
? Object.keys(skillInfo.content.references || {}).map(name => `- ${name}`).join('\n')
: '无参考资料'}
### 依赖项
\`\`\`
Python: ${skillInfo.content.dependencies || '无'}
\`\`\`
\`\`\`
Node.js: ${skillInfo.content.packageJson || '无'}
\`\`\`
## 分析要求
请从以下维度进行评估:
### 1. 内容/功能分析 (${skillType.type === 'knowledge' ? '知识内容' : skillType.type === 'tool' ? '工具功能' : '知识和工具'})
- ${skillType.type === 'knowledge' ? 'SKILL.md 的内容质量、专业性、准确性' : skillType.type === 'tool' ? '工具的功能完整性、代码质量、错误处理' : '知识内容的质量和工具功能的完整性'}
- 是否有明显的缺陷或遗漏
- 与同类技能相比的优势/劣势
### 2. 结构/组织分析
- 内容组织是否清晰
- 是否易于理解和查找
- 是否有良好的层次结构
### 3. 实用性分析
- 是否真正有用
- 是否能解决实际问题
- 是否有实际应用场景
### 4. 完整性分析
- 是否覆盖了相关主题的主要方面
- 是否有重要的遗漏
- 是否需要补充
### 5. 安全性分析
- 是否有危险操作
- 是否有硬编码敏感信息
- 依赖项是否安全
## 输出格式
请按照以下格式输出分析结果:
\`\`\`json
{
"rationality": true/false,
"score": 0-100,
"breakdown": {
"contentQuality": 0-40,
"structure": 0-20,
"practicality": 0-20,
"authority": 0-10,
"completeness": 0-10
},
"issues": ["问题1", "问题2", ...],
"strengths": ["优势1", "优势2", ...],
"weaknesses": ["劣势1", "劣势2", ...],
"recommendations": ["建议1", "建议2", ...],
"analysis": "详细分析文本..."
}
\`\`\`
## 注意事项
- 请仔细阅读所有内容
- 根据技能类型使用相应的评分标准
- 给出具体、可操作的建议
- 评分要客观公正
- 知识型技能不要因为没有 scripts/ 目录就扣分
- 工具型技能重点评估代码质量和功能
`;
}
function parseLLMAnalysis(llmOutput: string, skillType: SkillType): any {
const result: any = {
rationality: true,
score: 50,
breakdown: {},
issues: [],
strengths: [],
weaknesses: [],
recommendations: []
};
// 尝试从 LLM 输出中提取 JSON
const jsonMatch = llmOutput.match(/```json\n([\s\S]*?)\n```/);
if (jsonMatch) {
try {
const parsed = JSON.parse(jsonMatch[1]);
return parsed;
} catch (e) {
// JSON 解析失败
}
}
// 基于关键词的分析
if (llmOutput.includes('优秀') || llmOutput.includes('excellent')) {
result.score = 85;
} else if (llmOutput.includes('良好') || llmOutput.includes('good')) {
result.score = 70;
} else if (llmOutput.includes('一般') || llmOutput.includes('average')) {
result.score = 50;
}
result.rationality = result.score >= 50;
return result;
}
async function countFiles(dir: string): Promise<number> {
const proc = await $`find ${dir} -type f | wc -l`.quiet();
return parseInt(proc.stdout.toString().trim());
}
// 解析命令行参数
const args = process.argv.slice(2);
const skillPath = args[0];
if (!skillPath) {
console.log(`
智能评估脚本 - 使用 LLM 进行智能分析和判断
用法:
bun scripts/assess.ts <skill-path> [选项]
选项:
--verbose 详细输出
示例:
bun scripts/assess.ts ~/.pi/agent/skills/react-best-practices
bun scripts/assess.ts ~/.pi/agent/skills/office-pdf --verbose
`);
process.exit(1);
}
// 解析选项
const options: AssessmentOptions = {
llm: true
};
for (let i = 1; i < args.length; i++) {
const arg = args[i];
if (arg === '--verbose') options.verbose = true;
}
// 执行评估
assessSkill(skillPath, options).catch(err => {
console.error(`❌ 评估失败: ${err.message}`);
process.exit(1);
});#!/usr/bin/env bun
/**
* 安全审计脚本 - 调用 LLM 进行深度安全审计
*/
import { $ } from 'bun';
interface AuditOptions {
llm?: boolean;
interactive?: boolean;
}
interface AuditResult {
skillName: string;
passed: boolean;
security: any;
score: number;
issues: string[];
recommendations: string[];
}
async function auditSkill(skillPath: string, options: AuditOptions = {}) {
const skillName = skillPath.split('/').pop() || skillPath;
console.log(`\n🔒 安全审计: ${skillName}`);
console.log('━'.repeat(60));
const result: AuditResult = {
skillName,
passed: true,
security: {},
score: 0,
issues: [],
recommendations: []
};
// 收集技能信息
const skillInfo = await collectSkillInfo(skillPath);
// 判断技能类型
const skillType = await determineSkillType(skillInfo);
console.log(` 技能类型: ${skillType}`);
// 基础安全检查(仅对有脚本的技能)
let basicChecks: any = { score: 50, passed: true, issues: [], findings: {} };
if (skillInfo.hasScripts) {
console.log(`\n🔍 执行基础安全检查...`);
basicChecks = await performBasicSecurityChecks(skillPath);
result.security.basic = basicChecks;
} else {
console.log(` ✅ 纯知识型技能,无需基础安全检查`);
result.security.basic = { note: "纯知识型技能,无脚本文件" };
}
// 调用 LLM 进行深度安全审计(始终执行)
if (options.llm !== false) {
console.log(`\n🤖 调用 LLM 进行深度安全审计...`);
const llmAnalysis = await performLLMSecurityAudit(skillInfo, basicChecks, skillType);
// 解析 LLM 分析结果
const parsed = parseLLMAudit(llmAnalysis);
result.security.llm = parsed;
result.score = parsed.score;
result.issues.push(...parsed.issues);
result.recommendations.push(...parsed.recommendations);
result.passed = parsed.passed;
} else {
result.score = basicChecks.score;
result.issues.push(...basicChecks.issues);
result.passed = basicChecks.passed;
}
// 输出结果
console.log(`\n✅ 审计完成`);
console.log(` 安全评分: ${result.score}/100`);
console.log(` 审计结果: ${result.passed ? '✅ 通过' : '❌ 未通过'}`);
if (result.issues.length > 0) {
console.log(`\n⚠️ 发现 ${result.issues.length} 个安全问题:`);
result.issues.forEach((issue, i) => {
console.log(` ${i + 1}. ${issue}`);
});
}
if (result.recommendations.length > 0) {
console.log(`\n💡 修复建议:`);
result.recommendations.forEach((rec, i) => {
console.log(` ${i + 1}. ${rec}`);
});
}
return result;
}
async function collectSkillInfo(skillPath: string) {
const info: any = {
path: skillPath,
files: [],
content: {},
hasScripts: false
};
// 读取 SKILL.md
const skillFile = `${skillPath}/SKILL.md`;
if (await $`test -f ${skillFile}`.quiet().then(() => true).catch(() => false)) {
info.content.skill = await Bun.file(skillFile).text();
}
// 列出所有文件
const findProc = await $`find ${skillPath} -type f`.quiet();
info.files = findProc.stdout.toString().trim().split('\n').filter(Boolean);
// 检查是否有脚本文件
info.hasScripts = info.files.some(f => f.includes('/scripts/'));
// 读取脚本文件内容
if (info.hasScripts) {
info.content.scripts = {};
for (const file of info.files) {
if (file.includes('/scripts/')) {
const name = file.split('/').pop();
try {
info.content.scripts[name!] = await Bun.file(file).text();
} catch (e) {
info.content.scripts[name!] = '[读取失败]';
}
}
}
}
// 读取依赖文件
const requirementsPath = `${skillPath}/requirements.txt`;
if (await $`test -f ${requirementsPath}`.quiet().then(() => true).catch(() => false)) {
info.content.requirements = await Bun.file(requirementsPath).text();
}
const packageJsonPath = `${skillPath}/package.json`;
if (await $`test -f ${packageJsonPath}`.quiet().then(() => true).catch(() => false)) {
info.content.package = await Bun.file(packageJsonPath).text();
}
// 读取参考文档
const refsPath = `${skillPath}/references`;
if (await $`test -d ${refsPath}`.quiet().then(() => true).catch(() => false)) {
info.content.references = {};
const findRefs = await $`find ${refsPath} -name "*.md" -o -name "*.txt"`.quiet();
const refFiles = findRefs.stdout.toString().trim().split('\n').filter(Boolean);
for (const file of refFiles) {
const name = file.split('/').pop();
try {
info.content.references[name!] = await Bun.file(file).text();
} catch (e) {
info.content.references[name!] = '[读取失败]';
}
}
}
return info;
}
/**
* 使用 LLM 判断技能类型
*/
async function determineSkillType(skillInfo: any): Promise<string> {
if (!skillInfo.content.skill) return 'unknown';
const content = skillInfo.content.skill.toLowerCase();
const hasScripts = skillInfo.hasScripts;
// 如果有脚本文件,很可能是工具型
if (hasScripts) {
if (content.includes('guide') || content.includes('reference') || content.includes('best practices')) {
return 'hybrid'; // 混合型:有脚本但主要是知识
}
return 'tool'; // 工具型
}
// 没有脚本,判断内容类型
if (content.includes('guide') || content.includes('reference') || content.includes('best practices') ||
content.includes('tutorial') || content.includes('documentation')) {
return 'knowledge'; // 知识型
}
if (content.includes('workflow') || content.includes('process') || content.includes('steps')) {
return 'process'; // 流程型
}
return 'unknown';
}
async function performBasicSecurityChecks(skillPath: string) {
const result: any = {
score: 50,
passed: true,
issues: [],
findings: {}
};
const scriptsPath = `${skillPath}/scripts`;
// 检查危险函数
const dangerousPatterns = {
eval: 'eval() 执行动态代码',
exec: 'exec() 执行系统命令',
system: 'system() 执行 shell 命令',
subprocess: 'subprocess 执行外部命令',
'os.system': 'os.system() 执行系统命令'
};
if (await $`test -d ${scriptsPath}`.quiet().then(() => true).catch(() => false)) {
for (const [pattern, desc] of Object.entries(dangerousPatterns)) {
const grepProc = await $`grep -r "${pattern}" ${scriptsPath} 2>/dev/null || true`.quiet();
const matches = grepProc.stdout.toString().trim();
if (matches) {
const count = matches.split('\n').filter(Boolean).length;
result.findings[pattern] = { count, desc };
if (pattern === 'eval' || pattern === 'exec' || pattern === 'system' || pattern === 'os.system') {
result.issues.push(`高危函数 ${desc} (${count} 处)`);
result.passed = false;
result.score -= 10;
} else {
result.score -= 5;
}
}
}
// 检查硬编码凭据
const secretPatterns = [
'password\\s*=',
'api_key\\s*=',
'secret\\s*=',
'token\\s*=',
'private_key'
];
for (const pattern of secretPatterns) {
const grepProc = await $`grep -rE "${pattern}" ${scriptsPath} 2>/dev/null || true`.quiet();
const matches = grepProc.stdout.toString().trim();
if (matches) {
result.issues.push(`可能包含硬编码凭据: ${pattern}`);
result.passed = false;
result.score -= 5;
}
}
// 检查网络访问
const netPatterns = ['http://', 'https://', 'requests.get', 'fetch(', 'axios'];
for (const pattern of netPatterns) {
const grepProc = await $`grep -r "${pattern}" ${scriptsPath} 2>/dev/null || true`.quiet();
const matches = grepProc.stdout.toString().trim();
if (matches) {
const count = matches.split('\n').filter(Boolean).length;
result.findings[`network_${pattern}`] = { count };
result.score -= 2;
}
}
}
result.score = Math.max(0, result.score);
return result;
}
/**
* 调用 LLM 进行深度安全审计
*/
async function performLLMSecurityAudit(skillInfo: any, basicChecks: any, skillType: string): Promise<string> {
// 生成审计提示
const prompt = generateSecurityAuditPrompt(skillInfo, basicChecks, skillType);
// 将提示写入临时文件,供主 LLM 分析
const promptFile = '/tmp/skill-security-audit-prompt.md';
await Bun.write(promptFile, prompt);
console.log(` 审计提示已生成: ${promptFile}`);
console.log(` 请让 Claude 阅读该文件并进行分析`);
return prompt;
}
function generateSecurityAuditPrompt(skillInfo: any, basicChecks: any, skillType: string): string {
let contentAnalysis = '### SKILL.md 内容\n```';
if (skillInfo.content.skill) {
contentAnalysis += skillInfo.content.skill.substring(0, 3000);
if (skillInfo.content.skill.length > 3000) {
contentAnalysis += '\n...(内容已截断)';
}
}
contentAnalysis += '```\n';
// 添加脚本内容
if (skillInfo.hasScripts && skillInfo.content.scripts) {
contentAnalysis += '\n### 脚本文件\n';
Object.keys(skillInfo.content.scripts).forEach(name => {
const scriptContent = skillInfo.content.scripts[name];
contentAnalysis += `\n#### ${name}\n\`\`\`\n${scriptContent.substring(0, 500)}...\n\`\`\`\n`;
});
}
// 添加依赖信息
contentAnalysis += '\n### 依赖项\n```';
if (skillInfo.content.requirements) {
contentAnalysis += `Python:\n${skillInfo.content.requirements}`;
}
if (skillInfo.content.package) {
contentAnalysis += `\nNode.js:\n${skillInfo.content.package}`;
}
contentAnalysis += '```\n';
return `# 技能安全审计请求
## 技能信息
**技能类型:** ${skillType}
**是否有脚本:** ${skillInfo.hasScripts ? '是' : '否'}
**文件数量:** ${skillInfo.files.length}
${contentAnalysis}
## 基础安全检查结果
\`\`\`json
${JSON.stringify(basicChecks, null, 2)}
\`\`\`
## 审计要求
请根据技能类型(${skillType})进行相应的安全审计:
### 如果是知识型技能(knowledge)
重点审查:
- **内容安全性**: 文档中是否包含危险操作示例?
- **误导性内容**: 是否有错误的安全建议?
- **敏感信息**: 文档中是否泄露敏感信息?
- **链接安全**: 外部链接是否安全可信?
### 如果是工具型技能(tool)
重点审查:
- **代码安全**: 危险函数、命令注入、路径遍历
- **依赖安全**: 依赖漏洞、来源可信度
- **数据安全**: 敏感信息、数据泄露
- **权限安全**: 文件权限、网络访问、系统调用
- **错误处理**: 错误信息泄露、异常处理
### 如果是混合型技能(hybrid)
同时审查知识型和工具型的所有维度
### 如果是流程型技能(process)
重点审查:
- **流程安全性**: 流程步骤是否有安全风险?
- **输入验证**: 流程中是否有用户输入验证?
- **输出安全**: 流程输出是否安全?
## 输出格式
请按照以下格式输出审计结果:
\`\`\`json
{
"passed": true/false,
"score": 0-100,
"severity": "high/medium/low/none",
"skillType": "${skillType}",
"issues": [
{
"type": "类型",
"severity": "high/medium/low",
"description": "问题描述",
"location": "位置",
"recommendation": "修复建议"
}
],
"findings": {
"contentIssues": [],
"codeIssues": [],
"dependencyIssues": [],
"otherIssues": []
},
"recommendations": ["建议1", "建议2", ...],
"analysis": "详细审计分析..."
}
\`\`\`
## 审计标准
### 高风险 (high)
- 存在可被利用的安全漏洞
- 硬编码敏感信息
- 未经验证的用户输入
- 危险的系统调用
- 误导性的安全建议(知识型)
### 中风险 (medium)
- 潜在的安全问题
- 不完善的错误处理
- 可疑的依赖项
- 不明确的最佳实践
### 低风险 (low)
- 代码质量问题
- 最佳实践建议
- 优化建议
### 无风险 (none)
- 纯知识型且内容安全
- 无任何安全问题
## 注意事项
- 根据技能类型调整审计重点
- 对于知识型技能,重点关注内容质量而非代码安全
- 给出具体、可操作的建议
- 评分要客观公正
`;
}
function parseLLMAudit(llmOutput: string): any {
const result: any = {
passed: true,
score: 50,
severity: 'none',
issues: [],
recommendations: []
};
// 尝试从 LLM 输出中提取 JSON
const jsonMatch = llmOutput.match(/```json\n([\s\S]*?)\n```/);
if (jsonMatch) {
try {
const parsed = JSON.parse(jsonMatch[1]);
result.passed = parsed.passed;
result.score = parsed.score;
result.severity = parsed.severity;
result.issues = parsed.issues?.map((i: any) =>
typeof i === 'string' ? i : `${i.type}: ${i.description}`
) || [];
result.recommendations = parsed.recommendations || [];
return result;
} catch (e) {
// JSON 解析失败
}
}
// 基于关键词的分析
if (llmOutput.includes('高风险') || llmOutput.includes('high')) {
result.score -= 30;
result.passed = false;
result.severity = 'high';
}
if (llmOutput.includes('中风险') || llmOutput.includes('medium')) {
result.score -= 15;
result.severity = 'medium';
}
if (llmOutput.includes('无风险') || llmOutput.includes('none')) {
result.score = 100;
result.severity = 'none';
}
result.score = Math.max(0, Math.min(100, result.score));
return result;
}
// 解析命令行参数
const args = process.argv.slice(2);
const skillPath = args[0];
if (!skillPath) {
console.log(`
安全审计脚本 - 调用 LLM 进行深度安全审计
用法:
bun scripts/audit.ts <skill-path> [选项]
选项:
--no-llm 不使用 LLM,仅进行基础审计
--interactive 交互式模式(需要用户介入)
示例:
bun scripts/audit.ts ~/.pi/agent/skills/office-pdf
bun scripts/audit.ts ~/.pi/agent/skills/react-best-practices
bun scripts/audit.ts ~/.pi/agent/skills/office-pdf --no-llm
`);
process.exit(1);
}
// 解析选项
const options: AuditOptions = {
llm: true
};
for (let i = 1; i < args.length; i++) {
const arg = args[i];
if (arg === '--no-llm') options.llm = false;
else if (arg === '--interactive') options.interactive = true;
}
// 执行审计
auditSkill(skillPath, options).catch(err => {
console.error(`❌ 审计失败: ${err.message}`);
process.exit(1);
});#!/usr/bin/env bun
/**
* 用户交互脚本 - 使用 interview 工具进行用户介入决策
*/
import { $ } from 'bun';
interface InteractiveOptions {
phase?: string;
message?: string;
promptFile?: string;
issues?: string[];
}
async function interactiveDecision(options: InteractiveOptions = {}) {
const { phase, message, promptFile, issues } = options;
console.log(`\n🤔 用户介入请求`);
console.log('━'.repeat(60));
// 读取 LLM 分析结果
let analysisContent = '';
if (promptFile && await $`test -f ${promptFile}`.quiet().then(() => true).catch(() => false)) {
console.log(`\n📄 读取分析结果: ${promptFile}`);
analysisContent = await Bun.file(promptFile).text();
console.log(` 分析内容长度: ${analysisContent.length} 字符`);
}
// 生成 interview 问题配置
const interviewConfig = generateInterviewConfig(phase, message, issues, analysisContent);
// 写入配置文件
const configFile = `${process.env.HOME}/.pi/agent/skills/skill-management/.interview-config.json`;
await Bun.write(configFile, JSON.stringify(interviewConfig, null, 2));
console.log(`\n💡 Interview 配置已生成: ${configFile}`);
console.log(`\n📝 请 Claude 使用 interview 工具询问用户:`);
console.log(` interview ${configFile}`);
console.log(`\n⚠️ 等待用户决策...`);
return { configFile };
}
function generateInterviewConfig(
phase?: string,
message?: string,
issues?: string[],
analysisContent?: string
) {
const questions: any[] = [];
// 基础问题:是否继续
questions.push({
id: 'continue',
type: 'single',
question: message || '是否继续流程?',
options: ['继续', '停止', '跳过当前阶段'],
recommended: '继续'
});
// 如果有分析内容,添加相关问题
if (analysisContent && analysisContent.length > 0) {
questions.push({
id: 'review_analysis',
type: 'single',
question: 'LLM 分析结果是否可接受?',
options: ['完全接受', '部分接受', '不接受'],
recommended: '部分接受'
});
questions.push({
id: 'analysis_score',
type: 'single',
question: 'LLM 给出的评分是否合理?',
options: ['合理', '偏高', '偏低'],
recommended: '合理'
});
}
// 如果有问题列表,添加反馈问题
if (issues && issues.length > 0) {
questions.push({
id: 'address_issues',
type: 'multi',
question: '发现以下问题,请选择需要立即修复的:',
options: issues.slice(0, 10), // 限制最多 10 个选项
recommended: []
});
questions.push({
id: 'issue_action',
type: 'single',
question: '对于未修复的问题,希望如何处理?',
options: ['记录并继续', '暂时跳过', '停止流程等待修复'],
recommended: '记录并继续'
});
}
// 阶段特定问题
if (phase === 'assess') {
questions.push({
id: 'skill_rationality',
type: 'single',
question: '该技能的合理性评估:',
options: ['完全合理', '基本合理', '需要改进', '不合理'],
recommended: '基本合理'
});
}
if (phase === 'audit') {
questions.push({
id: 'security_acceptance',
type: 'single',
question: '安全审计结果:',
options: ['安全可用', '存在低风险可接受', '存在中风险需考虑', '存在高风险不可用'],
recommended: '存在低风险可接受'
});
}
if (phase === 'adapt') {
questions.push({
id: 'adapt_action',
type: 'single',
question: '是否需要进行适应性改造?',
options: ['立即改造', '稍后改造', '无需改造'],
recommended: '立即改造'
});
}
// 添加反馈问题
questions.push({
id: 'feedback',
type: 'text',
question: '请提供任何额外的反馈或要求:',
recommended: ''
});
return {
title: `技能管理流程 - ${phase || '决策点'}`,
description: message || '请根据 LLM 分析结果做出决策',
questions
};
}
// 解析命令行参数
const args = process.argv.slice(2);
if (args.length === 0) {
console.log(`
用户交互脚本 - 使用 interview 工具进行用户介入决策
用法:
bun scripts/interactive.ts [选项]
选项:
--phase <phase> 当前阶段
--message <msg> 决策消息
--prompt-file <file> LLM 分析提示文件
--issues <issue1,issue2,...> 问题列表(逗号分隔)
示例:
# 评估阶段决策
bun scripts/interactive.ts --phase assess --message "评估已完成,是否继续?"
# 审计阶段决策(带分析结果)
bun scripts/interactive.ts --phase audit --message "审计已完成" --prompt-file /tmp/skill-security-audit-prompt.md
# 改造阶段决策(带问题列表)
bun scripts/interactive.ts --phase adapt --message "发现需要适配的路径" --issues "路径1,路径2,路径3"
# 使用 interview 工具
# Claude 应该使用以下命令询问用户:
# interview ~/.pi/agent/skills/skill-management/.interview-config.json
`);
process.exit(1);
}
// 解析选项
const options: InteractiveOptions = {};
for (let i = 0; i < args.length; i++) {
const arg = args[i];
if (arg === '--phase' && args[i + 1]) {
options.phase = args[i + 1];
i++;
} else if (arg === '--message' && args[i + 1]) {
options.message = args[i + 1];
i++;
} else if (arg === '--prompt-file' && args[i + 1]) {
options.promptFile = args[i + 1];
i++;
} else if (arg === '--issues' && args[i + 1]) {
options.issues = args[i + 1].split(',');
i++;
}
}
// 执行交互
interactiveDecision(options).catch(err => {
console.error(`❌ 交互失败: ${err.message}`);
process.exit(1);
});#!/usr/bin/env bun
/**
* 通知脚本 - 向用户发送技能管理流程的通知
*/
import { $ } from 'bun';
interface NotifyOptions {
type?: 'decision' | 'progress' | 'complete' | 'error' | 'warning';
skill?: string;
message?: string;
phase?: string;
report?: string;
channel?: 'console' | 'file' | 'both';
}
async function notify(options: NotifyOptions = {}) {
const {
type = 'info',
skill,
message,
phase,
report,
channel = 'console'
} = options;
const notification = buildNotification(type, skill, message, phase, report);
if (channel === 'console' || channel === 'both') {
console.log(notification);
}
if (channel === 'file' || channel === 'both') {
const logPath = `${process.env.HOME}/.pi/agent/skills/skill-management/notifications.log`;
await Bun.appendFile(logPath, `\n${new Date().toISOString()}\n${notification}\n`);
}
return { success: true };
}
function buildNotification(
type: string,
skill?: string,
message?: string,
phase?: string,
report?: string
): string {
const icons = {
decision: '🤔',
progress: '⏳',
complete: '✅',
error: '❌',
warning: '⚠️',
info: 'ℹ️'
};
const icon = icons[type as keyof typeof icons] || icons.info;
let output = `\n${icon} ${type.toUpperCase()}`;
if (skill) output += ` - ${skill}`;
output += '\n' + '━'.repeat(60);
if (phase) output += `\n\n📍 阶段: ${phase}`;
if (message) output += `\n\n📝 ${message}`;
if (report) output += `\n\n📄 报告: ${report}`;
switch (type) {
case 'decision':
output += `\n\n⏸️ 流程暂停,等待用户确认`;
output += `\n\n操作选项:`;
output += `\n [Y] 继续`;
output += `\n [N] 停止`;
output += `\n [S] 跳过当前阶段`;
break;
case 'progress':
output += `\n\n🔄 流程进行中...`;
break;
case 'complete':
output += `\n\n🎉 流程顺利完成!`;
output += `\n\n后续步骤:`;
output += `\n 1. 查看详细报告`;
output += `\n 2. 测试技能功能`;
output += `\n 3. 根据建议优化`;
break;
case 'error':
output += `\n\n🚨 发生错误,流程终止`;
output += `\n\n排查建议:`;
output += `\n 1. 检查错误日志`;
output += `\n 2. 验证输入参数`);
output += `\n 3. 重试流程`;
break;
case 'warning':
output += `\n\n⚠️ 注意事项`;
output += `\n\n建议:`;
output += `\n 1. 仔细阅读警告信息`);
output += `\n 2. 评估潜在风险`;
output += `\n 3. 采取相应措施`;
break;
}
output += '\n';
return output;
}
// 解析命令行参数
const args = process.argv.slice(2);
if (args.length === 0) {
console.log(`
通知脚本 - 向用户发送技能管理流程的通知
用法:
bun scripts/notify.ts [选项]
选项:
--type <type> 通知类型 (decision, progress, complete, error, warning)
--skill <name> 技能名称
--message <msg> 通知消息
--phase <phase> 当前阶段
--report <path> 报告路径
--channel <channel> 通知渠道 (console, file, both)
示例:
# 决策点通知
bun scripts/notify.ts --type decision --skill office-pdf --message "需要确认是否继续"
# 进度通知
bun scripts/notify.ts --type progress --skill office-pdf --phase "Phase 3: 安全审计"
# 完成通知
bun scripts/notify.ts --type complete --skill office-pdf --report reports/office-pdf.md
# 错误通知
bun scripts/notify.ts --type error --message "依赖安装失败"
# 警告通知
bun scripts/notify.ts --type warning --message "发现潜在安全风险"
`);
process.exit(0);
}
// 解析选项
const options: NotifyOptions = {};
for (let i = 0; i < args.length; i++) {
const arg = args[i];
if (arg === '--type' && args[i + 1]) {
options.type = args[i + 1] as any;
i++;
} else if (arg === '--skill' && args[i + 1]) {
options.skill = args[i + 1];
i++;
} else if (arg === '--message' && args[i + 1]) {
options.message = args[i + 1];
i++;
} else if (arg === '--phase' && args[i + 1]) {
options.phase = args[i + 1];
i++;
} else if (arg === '--report' && args[i + 1]) {
options.report = args[i + 1];
i++;
} else if (arg === '--channel' && args[i + 1]) {
options.channel = args[i + 1] as any;
i++;
}
}
// 发送通知
notify(options).catch(err => {
console.error(`❌ 通知发送失败: ${err.message}`);
process.exit(1);
});#!/usr/bin/env bun
/**
* 完整流程脚本 - 一键执行技能管理的完整流程,使用 interview 工具进行用户介入
*/
import { $ } from 'bun';
const SKILLS_DIR = `${process.env.HOME}/.pi/agent/skills`;
const TEMP_DIR = '/tmp/skill-pipeline';
const REPORTS_DIR = `${process.env.HOME}/.pi/agent/skills/skill-management/reports`;
interface PipelineOptions {
interactive?: boolean;
verbose?: boolean;
skipAudit?: boolean;
skipTest?: boolean;
}
async function runPipeline(keyword?: string, options: PipelineOptions = {}) {
const phases = [
'search',
'select',
'discover',
'assess',
'audit',
'adapt',
'integrate',
'report',
'notify'
];
console.log(`\n🚀 技能管理流程启动`);
if (keyword) console.log(` 搜索关键词: ${keyword}`);
console.log(` 交互模式: ${options.interactive ? '✅' : '❌'}`);
console.log('━'.repeat(60));
const results: any = {};
// 准备工作目录
await $`rm -rf ${TEMP_DIR}`;
await $`mkdir -p ${TEMP_DIR} ${REPORTS_DIR}`;
// Phase 1: 搜索技能
if (keyword) {
console.log(`\n🔍 Phase 1: 搜索技能`);
const searchResult = await searchSkills(keyword);
results.search = searchResult;
if (!searchResult.success || searchResult.skills.length === 0) {
console.error(`❌ 搜索失败或未找到技能`);
return results;
}
}
// Phase 2: 选择技能
console.log(`\n📋 Phase 2: 选择技能`);
const selectResult = await selectSkill(results.search?.skills || [], options.interactive);
results.select = selectResult;
if (!selectResult.selected) {
console.log(`⏸️ 未选择技能,流程结束`);
return results;
}
const selectedSkill = selectResult.selected;
// Phase 3: 发现技能
console.log(`\n📥 Phase 3: 发现技能`);
const discoverResult = await discover(selectedSkill.repo, selectedSkill.name);
results.discover = discoverResult;
if (!discoverResult.success) {
console.error(`❌ 发现阶段失败`);
return results;
}
const skillPath = `${SKILLS_DIR}/${discoverResult.skillName}`;
// Phase 4: 评估技能
console.log(`\n📊 Phase 4: 评估技能`);
const assessResult = await assess(skillPath, options.interactive);
results.assess = assessResult;
if (options.interactive && !assessResult.userDecision?.continue) {
console.log(`⏸️ 用户选择停止流程`);
return results;
}
// Phase 5: 安全审计
if (!options.skipAudit) {
console.log(`\n🔒 Phase 5: 安全审计`);
const auditResult = await audit(skillPath, options.interactive);
results.audit = auditResult;
if (options.interactive && !auditResult.userDecision?.continue) {
console.log(`⏸️ 用户选择停止流程`);
return results;
}
}
// Phase 6: 适应性改造
console.log(`\n🔧 Phase 6: 适应性改造`);
const adaptResult = await adapt(skillPath, options.interactive);
results.adapt = adaptResult;
// Phase 7: 融合测试
if (!options.skipTest) {
console.log(`\n🧪 Phase 7: 融合测试`);
const integrateResult = await integrate(skillPath);
results.integrate = integrateResult;
}
// Phase 8: 生成报告
console.log(`\n📄 Phase 8: 生成报告`);
const reportResult = await generateReport(discoverResult.skillName, results);
results.report = reportResult;
// Phase 9: 用户通知
console.log(`\n🔔 Phase 9: 用户通知`);
await notify(discoverResult.skillName, results);
console.log(`\n✅ 流程完成`);
console.log(` 技能: ${discoverResult.skillName}`);
console.log(` 报告: ${REPORTS_DIR}/${discoverResult.skillName}.md`);
return results;
}
async function searchSkills(keyword: string) {
const result: any = { success: false, skills: [] };
try {
console.log(` 搜索: ${keyword}`);
// 使用 gh 搜索
const proc = Bun.spawn(['gh', 'search', 'repos', keyword, '-L', '20', '--sort', 'stars', '--order', 'desc'], {
stdout: 'pipe',
stderr: 'pipe'
});
const output = await new Response(proc.stdout).text();
const error = await new Response(proc.stderr).text();
if (error) {
result.error = error;
return result;
}
// 解析输出
const lines = output.trim().split('\n');
for (const line of lines) {
const match = line.match(/^(\S+)\/(\S+)\s+([\d.]+★)\s+(.+)$/);
if (match) {
result.skills.push({
owner: match[1],
name: match[2],
repo: `${match[1]}/${match[2]}`,
stars: match[3],
description: match[4]
});
}
}
result.success = true;
console.log(` 找到 ${result.skills.length} 个技能`);
} catch (error: any) {
result.error = error.message;
}
return result;
}
async function selectSkill(skills: any[], interactive: boolean) {
const result: any = { selected: null };
if (skills.length === 0) {
console.log(` 无技能可选择`);
return result;
}
// 生成选择配置
const selectConfig = generateSelectConfig(skills);
// 写入配置文件
const configFile = `${TEMP_DIR}/select-config.json`;
await Bun.write(configFile, JSON.stringify(selectConfig, null, 2));
console.log(` 💡 请使用 interview 工具让用户选择技能`);
console.log(` 配置文件: ${configFile}`);
if (interactive) {
console.log(`\n ⏸️ 等待用户选择...`);
// 在实际使用中,Pi Agent 会读取配置并使用 interview 工具
// 这里只是生成配置,实际的交互由 Pi Agent 完成
} else {
// 非交互模式,选择第一个
result.selected = skills[0];
console.log(` 自动选择: ${result.selected.repo}`);
}
return result;
}
function generateSelectConfig(skills: any[]) {
return {
title: '选择要安装的技能',
description: '根据搜索结果,请选择要安装和评估的技能',
questions: [
{
id: 'skill_choice',
type: 'single',
question: '请选择要安装的技能:',
options: skills.map(s => `${s.repo} ⭐ ${s.stars} - ${s.description.substring(0, 50)}...`),
recommended: skills[0].repo
},
{
id: 'custom_name',
type: 'text',
question: '自定义技能名称(可选,留空使用默认名称):',
recommended: ''
},
{
id: 'feedback',
type: 'text',
question: '任何额外的要求或说明:',
recommended: ''
}
]
};
}
async function discover(repo: string, skillName?: string) {
const result: any = { success: false };
try {
console.log(` 克隆仓库: ${repo}`);
const repoName = repo.split('/')[1];
const cloneDir = `${TEMP_DIR}/${repoName}`;
await $`gh repo clone ${repo} ${cloneDir}`;
// 查找技能
const skillFiles = await $`find ${cloneDir} -name "SKILL.md" -type f`.quiet();
const skills = skillFiles.stdout.toString().trim().split('\n').filter(Boolean);
if (skills.length === 0) {
result.error = '未找到 SKILL.md 文件';
return result;
}
// 复制技能
const skillDir = skills[0].replace('/SKILL.md', '');
const targetName = skillName || repoName.replace(/-skill$/, '').replace(/-skills$/, '');
const targetPath = `${SKILLS_DIR}/${targetName}`;
console.log(` 安装技能: ${targetName}`);
await $`cp -r ${skillDir} ${targetPath}`;
result.success = true;
result.skillName = targetName;
result.skillPath = targetPath;
result.skillsFound = skills.length;
} catch (error: any) {
result.error = error.message;
}
return result;
}
async function assess(skillPath: string, interactive: boolean) {
const assessScript = `${process.env.HOME}/.pi/agent/skills/skill-management/scripts/assess.ts`;
// 生成分析提示
await $`bun ${assessScript} ${skillPath}`.quiet();
let userDecision: any = { continue: true };
if (interactive) {
console.log(` 💡 请阅读分析提示并使用 interview 工具询问用户`);
console.log(` 分析提示: /tmp/skill-assessment-prompt.md`);
}
return { success: true, userDecision };
}
async function audit(skillPath: string, interactive: boolean) {
const auditScript = `${process.env.HOME}/.pi/agent/skills/skill-management/scripts/audit.ts`;
// 生成审计提示
await $`bun ${auditScript} ${skillPath}`.quiet();
let userDecision: any = { continue: true };
if (interactive) {
console.log(` 💡 请阅读审计提示并使用 interview 工具询问用户`);
console.log(` 审计提示: /tmp/skill-security-audit-prompt.md`);
}
return { success: true, userDecision };
}
async function adapt(skillPath: string, interactive: boolean) {
console.log(` 分析适配需求...`);
const grepProc = await $`grep -r "home/\\.pi" ${skillPath} 2>/dev/null || true`.quiet();
const matches = grepProc.stdout.toString().trim();
if (matches) {
console.log(` ⚠️ 发现 ${matches.split('\n').filter(Boolean).length} 处路径引用需要调整`);
} else {
console.log(` ✅ 无需路径调整`);
}
return { success: true, adapted: matches.length > 0 };
}
async function integrate(skillPath: string) {
console.log(` 检查命名冲突...`);
const skillName = skillPath.split('/').pop()!;
const conflict = await $`find ${SKILLS_DIR} -maxdepth 1 -name "${skillName}*" ! -path "${skillPath}" 2>/dev/null | wc -l`.quiet();
const conflictCount = parseInt(conflict.stdout.toString().trim());
if (conflictCount > 0) {
console.log(` ⚠️ 发现 ${conflictCount} 个可能冲突的技能`);
} else {
console.log(` ✅ 无命名冲突`);
}
console.log(` ✅ 基础兼容性检查通过`);
return { success: true, conflicts: conflictCount };
}
async function generateReport(skillName: string, results: any) {
const reportPath = `${REPORTS_DIR}/${skillName}.md`;
const content = `# 技能评估报告: ${skillName}
生成时间: ${new Date().toLocaleString('zh-CN')}
## 执行流程
✅ 搜索 → ✅ 选择 → ✅ 发现 → ✅ 评估 → ${results.audit ? '✅' : '⏭️'} 审计 → ✅ 改造 → ${results.integrate ? '✅' : '⏭️'} 融合 → ✅ 报告
## 技能信息
- **名称**: ${skillName}
- **仓库**: ${results.select?.selected?.repo || 'N/A'}
- **描述**: ${results.select?.selected?.description || 'N/A'}
- **星标**: ${results.select?.selected?.stars || 'N/A'}
## LLM 分析文件
- 评估分析: \`/tmp/skill-assessment-prompt.md\`
- 安全审计: \`/tmp/skill-security-audit-prompt.md\`
## 建议
1. ✅ 技能已安装到本地
2. 📝 查看 LLM 分析结果
3. 🧪 测试技能功能
4. 📚 阅读技能文档: \`${SKILLS_DIR}/${skillName}/SKILL.md\`
## 下一步
请 Pi Agent 读取 LLM 分析文件并给出详细建议。
`;
await Bun.write(reportPath, content);
console.log(` 报告已生成: ${reportPath}`);
return { success: true, reportPath };
}
async function notify(skillName: string, results: any) {
console.log(`\n📋 通知摘要`);
console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`);
console.log(`\n✅ 技能管理流程已完成`);
console.log(` 技能: ${skillName}`);
console.log(` 仓库: ${results.select?.selected?.repo || 'N/A'}`);
console.log(`\n📄 LLM 分析文件:`);
console.log(` - 评估: /tmp/skill-assessment-prompt.md`);
console.log(` - 审计: /tmp/skill-security-audit-prompt.md`);
console.log(`\n📚 技能文档: ${SKILLS_DIR}/${skillName}/SKILL.md`);
console.log(`\n💡 下一步:`);
console.log(` 1. 读取 LLM 分析文件`);
console.log(` 2. 根据分析结果进行决策`);
console.log(` 3. 测试技能功能`);
}
// 解析命令行参数
const args = process.argv.slice(2);
const keyword = args[0];
if (!keyword) {
console.log(`
完整流程脚本 - 技能搜索、选择、安装、评估全流程
用法:
bun scripts/pipeline.ts <keyword> [选项]
参数:
keyword 搜索关键词(必需)
选项:
--interactive 交互式模式(使用 interview 工具)
--verbose 详细输出
--skip-audit 跳过安全审计
--skip-test 跳过融合测试
阶段:
search 搜索技能
select 选择技能(使用 interview)
discover 发现并安装技能
assess 评估技能(Pi Agent 分析)
audit 安全审计(Pi Agent 分析)
adapt 适应性改造
integrate 融合测试
report 生成报告
notify 用户通知
示例:
# 搜索 office 技能并选择
bun scripts/pipeline.ts "claude office" --interactive
# 搜索 pdf 技能
bun scripts/pipeline.ts "pdf processing"
# 搜索并自动选择第一个
bun scripts/pipeline.ts "browser skill"
`);
process.exit(1);
}
// 解析选项
const options: PipelineOptions = {};
for (let i = 1; i < args.length; i++) {
const arg = args[i];
if (arg === '--interactive') {
options.interactive = true;
} else if (arg === '--verbose') {
options.verbose = true;
} else if (arg === '--skip-audit') {
options.skipAudit = true;
} else if (arg === '--skip-test') {
options.skipTest = true;
}
}
// 执行流程
runPipeline(keyword, options).catch(err => {
console.error(`❌ 流程失败: ${err.message}`);
process.exit(1);
});#!/usr/bin/env bun
/**
* 报告生成脚本 - 使用 LLM 生成智能化的技能评估报告
*/
import { $ } from 'bun';
const REPORTS_DIR = `${process.env.HOME}/.pi/agent/skills/skill-management/reports`;
interface ReportOptions {
llm?: boolean;
detailed?: boolean;
}
async function generateReport(skillName: string, options: ReportOptions = {}) {
const skillPath = `${process.env.HOME}/.pi/agent/skills/${skillName}`;
const reportPath = `${REPORTS_DIR}/${skillName}.md`;
console.log(`\n📄 生成报告: ${skillName}`);
console.log('━'.repeat(60));
// 收集技能信息
const skillInfo = await collectSkillInfo(skillPath);
// 判断技能类型
const skillType = await determineSkillType(skillInfo);
console.log(` 技能类型: ${skillType}`);
// 使用 LLM 生成报告
if (options.llm !== false) {
console.log(`\n🤖 调用 LLM 生成智能化报告...`);
const llmReport = await generateLLMReport(skillInfo, skillType);
// 写入报告
await Bun.write(reportPath, llmReport);
console.log(` ✅ 报告已生成: ${reportPath}`);
// 显示摘要
showReportSummary(llmReport);
} else {
// 基础报告
const basicReport = generateBasicReport(skillInfo, skillType);
await Bun.write(reportPath, basicReport);
console.log(` ✅ 报告已生成: ${reportPath}`);
}
return { success: true, reportPath };
}
async function collectSkillInfo(skillPath: string) {
const info: any = {
path: skillPath,
files: [],
structure: {},
content: {},
stats: {}
};
// 读取 SKILL.md
const skillFile = `${skillPath}/SKILL.md`;
if (await $`test -f ${skillFile}`.quiet().then(() => true).catch(() => false)) {
info.content.skill = await Bun.file(skillFile).text();
// 提取 YAML 前言
const yamlMatch = info.content.skill.match(/^---\n(.*?)\n---/s);
if (yamlMatch) {
info.content.yaml = yamlMatch[1];
const nameMatch = yamlMatch[1].match(/name:\s*(.+)/);
const descMatch = yamlMatch[1].match(/description:\s*(.+)/);
const authorMatch = yamlMatch[1].match(/author:\s*(.+)/);
const versionMatch = yamlMatch[1].match(/version:\s*(.+)/);
const tagsMatch = yamlMatch[1].match(/tags:\s*\[(.+)\]/);
info.name = nameMatch ? nameMatch[1].trim() : skillPath.split('/').pop();
info.description = descMatch ? descMatch[1].trim() : '';
info.author = authorMatch ? authorMatch[1].trim() : 'Unknown';
info.version = versionMatch ? versionMatch[1].trim() : 'N/A';
info.tags = tagsMatch ? tagsMatch[1].split(',').map(t => t.trim()) : [];
}
}
// 统计信息
const findProc = await $`find ${skillPath} -type f`.quiet();
info.files = findProc.stdout.toString().trim().split('\n').filter(Boolean);
info.stats.fileCount = info.files.length;
// 目录结构
const dirs = ['scripts', 'references', 'assets'];
for (const dir of dirs) {
const exists = await $`test -d ${skillPath}/${dir}`.quiet().then(() => true).catch(() => false);
info.structure[dir] = { exists };
if (exists) {
const countProc = await $`find ${skillPath}/${dir} -type f | wc -l`.quiet();
info.structure[dir].count = parseInt(countProc.stdout.toString().trim());
}
}
// 依赖项
const requirementsPath = `${skillPath}/requirements.txt`;
if (await $`test -f ${requirementsPath}`.quiet().then(() => true).catch(() => false)) {
info.content.requirements = await Bun.file(requirementsPath).text();
info.stats.pythonDeps = info.content.requirements.trim().split('\n').filter(Boolean).length;
}
const packageJsonPath = `${skillPath}/package.json`;
if (await $`test -f ${packageJsonPath}`.quiet().then(() => true).catch(() => false)) {
info.content.package = await Bun.file(packageJsonPath).text();
try {
const pkg = JSON.parse(info.content.package);
info.stats.nodeDeps = Object.keys(pkg.dependencies || {}).length;
info.stats.devDeps = Object.keys(pkg.devDependencies || {}).length;
} catch (e) {
info.stats.nodeDeps = 0;
}
}
return info;
}
/**
* 使用 LLM 判断技能类型
*/
async function determineSkillType(skillInfo: any): Promise<string> {
if (!skillInfo.content.skill) return 'unknown';
const content = skillInfo.content.skill.toLowerCase();
const hasScripts = skillInfo.structure.scripts?.exists;
if (hasScripts) {
if (content.includes('guide') || content.includes('reference') || content.includes('best practices')) {
return 'hybrid';
}
return 'tool';
}
if (content.includes('guide') || content.includes('reference') || content.includes('best practices') ||
content.includes('tutorial') || content.includes('documentation')) {
return 'knowledge';
}
if (content.includes('workflow') || content.includes('process') || content.includes('steps')) {
return 'process';
}
return 'unknown';
}
/**
* 调用 LLM 生成智能报告
*/
async function generateLLMReport(skillInfo: any, skillType: string): Promise<string> {
// 生成报告提示
const prompt = generateReportPrompt(skillInfo, skillType);
// 将提示写入临时文件
const promptFile = '/tmp/skill-report-prompt.md';
await Bun.write(promptFile, prompt);
console.log(` 报告提示已生成: ${promptFile}`);
console.log(` 请让 Claude 阅读该文件并生成报告`);
// 返回一个占位报告,实际的报告由 LLM 生成
return `# ${skillInfo.name || '技能'} 评估报告
**生成时间:** ${new Date().toLocaleString('zh-CN')}
**技能类型:** ${skillType}
**作者:** ${skillInfo.author || 'Unknown'}
**版本:** ${skillInfo.version || 'N/A'}
---
## 🤖 LLM 智能分析
请阅读报告提示文件并生成详细分析:
\`\`\`bash
read /tmp/skill-report-prompt.md
\`\`\`
然后根据提示生成完整的评估报告。
---
## 📊 基础信息
- **文件数量:** ${skillInfo.stats.fileCount}
- **脚本文件:** ${skillInfo.structure.scripts?.exists ? `✅ (${skillInfo.structure.scripts.count} 个)` : '❌'}
- **参考资料:** ${skillInfo.structure.references?.exists ? `✅ (${skillInfo.structure.references.count} 个)` : '❌'}
- **资源文件:** ${skillInfo.structure.assets?.exists ? `✅ (${skillInfo.structure.assets.count} 个)` : '❌'}
- **Python 依赖:** ${skillInfo.stats.pythonDeps || 0}
- **Node.js 依赖:** ${skillInfo.stats.nodeDeps || 0}
---
## 📚 技能描述
${skillInfo.description || '无描述'}
---
## 🏷️ 标签
${skillInfo.tags?.length ? skillInfo.tags.map(t => `\`${t}\``).join(', ') : '无'}
---
## 📄 完整报告生成中...
请让 Claude 阅读 \`/tmp/skill-report-prompt.md\` 并生成完整的评估报告。
`;
}
function generateReportPrompt(skillInfo: any, skillType: string): string {
return `# 技能评估报告生成请求
请为以下技能生成一份详细的评估报告。
## 技能信息
**名称:** ${skillInfo.name || 'Unknown'}
**类型:** ${skillType}
**作者:** ${skillInfo.author || 'Unknown'}
**版本:** ${skillInfo.version || 'N/A'}
**描述:** ${skillInfo.description || '无'}
**标签:** ${skillInfo.tags?.join(', ') || '无'}
**统计信息:**
- 文件数量: ${skillInfo.stats.fileCount}
- 脚本文件: ${skillInfo.structure.scripts?.exists ? `${skillInfo.structure.scripts.count} 个` : '无'}
- 参考资料: ${skillInfo.structure.references?.exists ? `${skillInfo.structure.references.count} 个` : '无'}
- 资源文件: ${skillInfo.structure.assets?.exists ? `${skillInfo.structure.assets.count} 个` : '无'}
- Python 依赖: ${skillInfo.stats.pythonDeps || 0}
- Node.js 依赖: ${skillInfo.stats.nodeDeps || 0}
## SKILL.md 内容
\`\`\`
${skillInfo.content.skill || '无 SKILL.md 文件'}
\`\`\`
## 报告要求
请生成一份完整的评估报告,包含以下部分:
### 1. 执行摘要
- 技能类型和特点
- 综合评分(0-100)
- 主要优缺点
- 推荐使用场景
### 2. 技能类型分析
根据技能类型(${skillType})进行分析:
**如果是知识型技能(knowledge):**
- 内容质量和完整性
- 组织结构和可读性
- 实用性和应用价值
- 文档深度和广度
**如果是工具型技能(tool):**
- 功能完整性和实用性
- 代码质量和可维护性
- 依赖项合理性
- 安全性和稳定性
**如果是混合型技能(hybrid):**
- 同时分析知识部分和工具部分
- 评估两者的协调性
**如果是流程型技能(process):**
- 流程清晰度和可操作性
- 步骤完整性和逻辑性
- 适用场景和灵活性
### 3. 详细评估
#### 3.1 内容质量
- SKILL.md 格式规范性
- 描述清晰度和完整性
- 文档结构和组织
#### 3.2 功能分析
- 核心功能是什么
- 功能覆盖度
- 与同类技能的对比
#### 3.3 使用体验
- 易用性
- 学习曲线
- 文档完整性
#### 3.4 技术评估
- 依赖项合理性
- 代码质量(如果适用)
- 安全性(如果适用)
### 4. 评分明细
根据技能类型给出评分:
| 维度 | 权重 | 得分 | 说明 |
|------|------|------|------|
| 内容质量 | ${skillType === 'knowledge' ? '40%' : '20%'} | 0-100 | |
| 功能完整性 | ${skillType === 'tool' ? '40%' : '20%'} | 0-100 | |
| 实用性 | 20% | 0-100 | |
| 文档质量 | 10% | 0-100 | |
| 代码质量 | ${skillType === 'tool' ? '10%' : '5%'} | 0-100 | |
| 安全性 | ${skillType === 'tool' ? '10%' : '5%'} | 0-100 | |
| **综合评分** | **100%** | **0-100** | |
### 5. 优势
列出 3-5 个主要优势
### 6. 不足
列出 3-5 个主要不足
### 7. 改进建议
给出 3-5 个具体的改进建议
### 8. 使用场景
列出适合的使用场景
### 9. 对比分析
与同类技能的对比(如果了解)
### 10. 总结
- 是否推荐使用
- 适用人群
- 注意事项
## 输出格式
请使用 Markdown 格式输出完整的报告,包含:
- 清晰的标题结构
- 表格展示评分
- 代码示例(如果适用)
- emoji 图标增强可读性
## 注意事项
- 根据技能类型调整评估重点
- 评分要客观公正
- 给出具体、可操作的建议
- 报告要易于阅读和理解
`;
}
function generateBasicReport(skillInfo: any, skillType: string): string {
return `# ${skillInfo.name || '技能'} 评估报告
**生成时间:** ${new Date().toLocaleString('zh-CN')}
**技能类型:** ${skillType}
---
## 基础信息
- **名称:** ${skillInfo.name || 'Unknown'}
- **描述:** ${skillInfo.description || '无'}
- **作者:** ${skillInfo.author || 'Unknown'}
- **版本:** ${skillInfo.version || 'N/A'}
- **文件数量:** ${skillInfo.stats.fileCount}
## 目录结构
| 目录 | 状态 |
|------|------|
| scripts/ | ${skillInfo.structure.scripts?.exists ? '✅' : '❌'} |
| references/ | ${skillInfo.structure.references?.exists ? '✅' : '❌'} |
| assets/ | ${skillInfo.structure.assets?.exists ? '✅' : '❌'} |
## 依赖项
- Python: ${skillInfo.stats.pythonDeps || 0}
- Node.js: ${skillInfo.stats.nodeDeps || 0}
---
*这是基础报告,请使用 --llm 选项生成完整的智能化报告。*
`;
}
function showReportSummary(report: string) {
// 提取关键信息并显示摘要
const lines = report.split('\n');
console.log(`\n📋 报告摘要:`);
for (const line of lines) {
if (line.includes('技能类型:') || line.includes('综合评分:') ||
line.includes('作者:') || line.includes('版本:')) {
console.log(` ${line.trim()}`);
}
}
}
// 解析命令行参数
const args = process.argv.slice(2);
const skillName = args[0];
if (!skillName) {
console.log(`
报告生成脚本 - 使用 LLM 生成智能化的技能评估报告
用法:
bun scripts/report.ts <skill-name> [选项]
参数:
skill-name 技能名称(必需)
选项:
--no-llm 不使用 LLM,生成基础报告
--detailed 生成详细报告
示例:
bun scripts/report.ts react-best-practices
bun scripts/report.ts office-pdf --detailed
bun scripts/report.ts office-docx --no-llm
`);
process.exit(1);
}
// 解析选项
const options: ReportOptions = {
llm: true
};
for (let i = 1; i < args.length; i++) {
const arg = args[i];
if (arg === '--no-llm') options.llm = false;
else if (arg === '--detailed') options.detailed = true;
}
// 执行报告生成
generateReport(skillName, options).catch(err => {
console.error(`❌ 报告生成失败: ${err.message}`);
process.exit(1);
});#!/usr/bin/env bun
import { $ } from 'bun';
import { searchWithCLI, SkillsCLIResult } from './skills-cli';
const SKILLS_BASE = 'https://skills.sh';
interface Skill {
source: string;
skillId: string;
name: string;
installs: number;
}
let skillsCache: Skill[] | null = null;
async function fetchSkills(): Promise<Skill[]> {
if (skillsCache) return skillsCache;
try {
console.log(` 正在获取 skills.sh 数据...`);
const response = await fetch(`${SKILLS_BASE}/trending`);
const html = await response.text();
// Extract skills data from HTML
const scriptMatch = html.match(/<script id="__NEXT_DATA__"[^>]*>([\s\S]*?)<\/script>/);
if (!scriptMatch) {
console.warn(` ⚠️ skills.sh 数据格式可能已变化,无法提取数据`);
return [];
}
const data = JSON.parse(scriptMatch[1]);
const skills: Skill[] = [];
// Traverse the data structure to find skills
function extractSkills(obj: any) {
if (Array.isArray(obj)) {
obj.forEach(extractSkills);
} else if (typeof obj === 'object' && obj !== null) {
if (obj.skillId && obj.source && obj.name && typeof obj.installs === 'number') {
skills.push({
source: obj.source,
skillId: obj.skillId,
name: obj.name,
installs: obj.installs
});
}
Object.values(obj).forEach(extractSkills);
}
}
extractSkills(data);
skillsCache = skills;
console.log(` ✅ 获取到 ${skills.length} 个技能`);
return skills;
} catch (error) {
console.error(' ❌ Failed to fetch skills:', error.message);
return [];
}
}
async function searchMarketplace(keyword: string, limit: number = 20) {
console.log(`\n🔍 搜索 skills.sh marketplace: ${keyword}`);
console.log('━'.repeat(60));
const skills = await fetchSkills();
const lowerKeyword = keyword.toLowerCase();
const results = skills.filter(s =>
s.name.toLowerCase().includes(lowerKeyword) ||
s.skillId.toLowerCase().includes(lowerKeyword) ||
s.source.toLowerCase().includes(lowerKeyword)
);
if (results.length === 0) {
console.log(`❌ 未找到匹配的技能`);
return [];
}
results.sort((a, b) => b.installs - a.installs);
console.log(`\n✅ 找到 ${Math.min(results.length, limit)} 个技能:\n`);
return results.slice(0, limit);
}
async function getMarketplaceSkill(skillId: string) {
const skills = await fetchSkills();
return skills.find(s => s.skillId === skillId || s.skillId.toLowerCase() === skillId.toLowerCase());
}
export async function search(keyword: string, options: any = {}) {
const { source = 'github', limit = 20 } = options;
if (source === 'marketplace') {
return await searchMarketplace(keyword, limit);
}
if (source === 'cli') {
return await searchWithCLI(keyword, limit);
}
// 默认使用 GitHub 搜索
console.log(`\n🔍 搜索 GitHub 仓库: ${keyword}`);
console.log('━'.repeat(60));
const proc = Bun.spawn(['gh', 'search', 'repos', keyword, '-L', limit.toString(), '--sort', 'stars'], {
stdout: 'pipe',
stderr: 'pipe'
});
const output = await new Response(proc.stdout).text();
const error = await new Response(proc.stderr).text();
if (error) {
console.error(`❌ 搜索失败: ${error}`);
return [];
}
const lines = output.trim().split('\n');
const results: any[] = [];
for (const line of lines) {
const match = line.match(/^(\S+)\/(\S+)\s+([\d.]+★)\s+(.+)$/);
if (match) {
results.push({
owner: match[1],
name: match[2],
repo: `${match[1]}/${match[2]}`,
stars: match[3],
description: match[4],
source: 'github'
});
}
}
console.log(`\n✅ 找到 ${results.length} 个技能\n`);
return results;
}
export async function listTrending(limit: number = 20) {
console.log(`\n📈 skills.sh 热门技能 (Top ${limit})`);
console.log('━'.repeat(60));
const skills = await fetchSkills();
if (skills.length === 0) {
console.log(`❌ 未找到技能`);
return [];
}
const topSkills = skills.sort((a, b) => b.installs - a.installs).slice(0, limit);
console.log(`\n✅ 找到 ${topSkills.length} 个热门技能:\n`);
return topSkills;
}
export async function getStats() {
const skills = await fetchSkills();
const totalInstalls = skills.reduce((sum, s) => sum + s.installs, 0);
const avgInstalls = totalInstalls / skills.length;
const topSources = skills.reduce((acc, s) => {
acc[s.source] = (acc[s.source] || 0) + 1;
return acc;
}, {} as Record<string, number>);
return {
total: skills.length,
totalInstalls,
avgInstalls: Math.round(avgInstalls),
topSources: Object.entries(topSources)
.sort((a, b) => b[1] - a[1])
.slice(0, 5)
.map(([source, count]) => ({ source, count }))
};
}
// CLI 接口
if (import.meta.main) {
const args = process.argv.slice(2);
const keyword = args[0];
if (!keyword) {
console.log(`
技能搜索工具 - 支持三数据源
用法:
bun scripts/search.ts <keyword> [选项]
数据源:
github GitHub 仓库搜索(默认)
marketplace skills.sh marketplace
cli Skills CLI (npx skills)
选项:
--source <type> 数据源类型 (github/marketplace/cli)
--limit <num> 结果数量 (默认: 20)
示例:
bun scripts/search.ts "react" --source github
bun scripts/search.ts "react" --source marketplace
bun scripts/search.ts "react" --source cli
bun scripts/search.ts trending
bun scripts/search.ts stats
`);
process.exit(1);
}
// 解析选项
const options: any = {};
for (let i = 1; i < args.length; i++) {
if (args[i] === '--source' && args[i + 1]) {
options.source = args[i + 1];
i++;
} else if (args[i] === '--limit' && args[i + 1]) {
options.limit = parseInt(args[i + 1], 10);
i++;
}
}
// 执行对应的命令
if (keyword === 'marketplace') {
const searchKeyword = args[1];
if (!searchKeyword) {
console.log('用法: bun scripts/search.ts marketplace <keyword>');
process.exit(1);
}
await searchMarketplace(searchKeyword, options.limit);
} else if (keyword === 'trending') {
const results = await listTrending(options.limit);
results.forEach((skill, i) => {
console.log(`${i + 1}. ${skill.name} (${skill.installs} installs) [${skill.source}/${skill.skillId}]`);
});
} else if (keyword === 'stats') {
const stats = await getStats();
console.log(`\n📊 技能统计`);
console.log('━'.repeat(60));
console.log(` 总技能数: ${stats.total}`);
console.log(` 总安装数: ${stats.totalInstalls.toLocaleString()}`);
console.log(` 平均安装数: ${stats.avgInstalls.toLocaleString()}`);
console.log(` Top 5 来源:`);
stats.topSources.forEach(({ source, count }) => {
console.log(` ${source}: ${count} 个技能`);
});
} else {
// 默认:搜索
await search(keyword, options);
}
}