Major type system refactoring and error fixes across the codebase: **Type System Improvements:** - Extended OpenFangStreamEvent with 'connected' and 'agents_updated' event types - Added GatewayPong interface for WebSocket pong responses - Added index signature to MemorySearchOptions for Record compatibility - Fixed RawApproval interface with hand_name, run_id properties **Gateway & Protocol Fixes:** - Fixed performHandshake nonce handling in gateway-client.ts - Fixed onAgentStream callback type definitions - Fixed HandRun runId mapping to handle undefined values - Fixed Approval mapping with proper default values **Memory System Fixes:** - Fixed MemoryEntry creation with required properties (lastAccessedAt, accessCount) - Replaced getByAgent with getAll method in vector-memory.ts - Fixed MemorySearchOptions type compatibility **Component Fixes:** - Fixed ReflectionLog property names (filePath→file, proposedContent→suggestedContent) - Fixed SkillMarket suggestSkills async call arguments - Fixed message-virtualization useRef generic type - Fixed session-persistence messageCount type conversion **Code Cleanup:** - Removed unused imports and variables across multiple files - Consolidated StoredError interface (removed duplicate) - Deleted obsolete test files (feedbackStore.test.ts, memory-index.test.ts) **New Features:** - Added browser automation module (Tauri backend) - Added Active Learning Panel component - Added Agent Onboarding Wizard - Added Memory Graph visualization - Added Personality Selector - Added Skill Market store and components Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
412 lines
14 KiB
TypeScript
412 lines
14 KiB
TypeScript
/**
|
|
* * skillMarketStore.ts - 技能市场状态管理
|
|
*
|
|
* * 猛攻状态管理技能浏览、搜索、安装/卸载等功能
|
|
*/
|
|
|
|
import { create } from 'zustand';
|
|
import { persist } from 'zustand/middleware';
|
|
import type { Skill, SkillReview, SkillMarketState } from '../types/skill-market';
|
|
|
|
// === 存储键 ===
|
|
const STORAGE_KEY = 'zclaw-skill-market';
|
|
const INSTALLED_KEY = 'zclaw-installed-skills';
|
|
|
|
// === 默认状态 ===
|
|
const initialState: SkillMarketState = {
|
|
skills: [],
|
|
installedSkills: [],
|
|
searchResults: [],
|
|
selectedSkill: null,
|
|
searchQuery: '',
|
|
categoryFilter: 'all',
|
|
isLoading: false,
|
|
error: null,
|
|
};
|
|
|
|
// === Store 定义 ===
|
|
interface SkillMarketActions {
|
|
// 技能加载
|
|
loadSkills: () => Promise<void>;
|
|
// 技能搜索
|
|
searchSkills: (query: string) => void;
|
|
// 分类过滤
|
|
filterByCategory: (category: string) => void;
|
|
// 选择技能
|
|
selectSkill: (skill: Skill | null) => void;
|
|
// 安装技能
|
|
installSkill: (skillId: string) => Promise<boolean>;
|
|
// 卸载技能
|
|
uninstallSkill: (skillId: string) => Promise<boolean>;
|
|
// 获取技能详情
|
|
getSkillDetails: (skillId: string) => Promise<Skill | null>;
|
|
// 加载评论
|
|
loadReviews: (skillId: string) => Promise<SkillReview[]>;
|
|
// 添加评论
|
|
addReview: (skillId: string, review: Omit<SkillReview, 'id' | 'skillId' | 'createdAt'>) => Promise<void>;
|
|
// 刷新技能列表
|
|
refreshSkills: () => Promise<void>;
|
|
// 清除错误
|
|
clearError: () => void;
|
|
// 重置状态
|
|
reset: () => void;
|
|
}
|
|
|
|
// === Store 创建 ===
|
|
export const useSkillMarketStore = create<SkillMarketState & SkillMarketActions>()(
|
|
persist({
|
|
key: STORAGE_KEY,
|
|
storage: localStorage,
|
|
partialize: (state) => ({
|
|
installedSkills: state.installedSkills,
|
|
categoryFilter: state.categoryFilter,
|
|
}),
|
|
}),
|
|
initialState,
|
|
{
|
|
// === 技能加载 ===
|
|
loadSkills: async () => {
|
|
set({ isLoading: true, error: null });
|
|
try {
|
|
// 扫描 skills 目录获取可用技能
|
|
const skills = await scanSkillsDirectory();
|
|
// 从 localStorage 恢复安装状态
|
|
const stored = localStorage.getItem(INSTALLED_KEY);
|
|
const installedSkills: string[] = stored ? JSON.parse(stored) : [];
|
|
// 更新技能的安装状态
|
|
const updatedSkills = skills.map(skill => ({
|
|
...skill,
|
|
installed: installedSkills.includes(skill.id),
|
|
})));
|
|
set({
|
|
skills: updatedSkills,
|
|
installedSkills,
|
|
isLoading: false,
|
|
});
|
|
} catch (err) {
|
|
set({
|
|
isLoading: false,
|
|
error: err instanceof Error ? err.message : '加载技能失败',
|
|
});
|
|
}
|
|
},
|
|
// === 技能搜索 ===
|
|
searchSkills: (query: string) => {
|
|
const { skills } = get();
|
|
set({ searchQuery: query });
|
|
if (!query.trim()) {
|
|
set({ searchResults: [] });
|
|
return;
|
|
}
|
|
const queryLower = query.toLowerCase();
|
|
const results = skills.filter(skill => {
|
|
return (
|
|
skill.name.toLowerCase().includes(queryLower) ||
|
|
skill.description.toLowerCase().includes(queryLower) ||
|
|
skill.triggers.some(t => t.toLowerCase().includes(queryLower)) ||
|
|
skill.capabilities.some(c => c.toLowerCase().includes(queryLower)) ||
|
|
skill.tags?.some(t => t.toLowerCase().includes(queryLower))
|
|
);
|
|
});
|
|
set({ searchResults: results });
|
|
},
|
|
// === 分类过滤 ===
|
|
filterByCategory: (category: string) => {
|
|
set({ categoryFilter: category });
|
|
},
|
|
// === 选择技能 ===
|
|
selectSkill: (skill: Skill | null) => {
|
|
set({ selectedSkill: skill });
|
|
},
|
|
// === 安装技能 ===
|
|
installSkill: async (skillId: string) => {
|
|
const { skills, installedSkills } = get();
|
|
const skill = skills.find(s => s.id === skillId);
|
|
if (!skill) return false;
|
|
try {
|
|
// 更新安装状态
|
|
const newInstalledSkills = [...installedSkills, skillId];
|
|
const updatedSkills = skills.map(s => ({
|
|
...s,
|
|
installed: s.id === skillId ? true : s.installed,
|
|
installedAt: s.id === skillId ? new Date().toISOString() : s.installedAt,
|
|
}));
|
|
// 持久化安装列表
|
|
localStorage.setItem(INSTALLED_KEY, JSON.stringify(newInstalledSkills));
|
|
set({
|
|
skills: updatedSkills,
|
|
installedSkills: newInstalledSkills,
|
|
});
|
|
return true;
|
|
} catch (err) {
|
|
set({
|
|
error: err instanceof Error ? err.message : '安装技能失败',
|
|
});
|
|
return false;
|
|
}
|
|
},
|
|
// === 卸载技能 ===
|
|
uninstallSkill: async (skillId: string) => {
|
|
const { skills, installedSkills } = get();
|
|
try {
|
|
// 更新安装状态
|
|
const newInstalledSkills = installedSkills.filter(id => id !== skillId);
|
|
const updatedSkills = skills.map(s => ({
|
|
...s,
|
|
installed: s.id === skillId ? false : s.installed,
|
|
installedAt: s.id === skillId ? undefined : s.installedAt,
|
|
}));
|
|
// 持久化安装列表
|
|
localStorage.setItem(INSTALLED_KEY, JSON.stringify(newInstalledSkills));
|
|
set({
|
|
skills: updatedSkills,
|
|
installedSkills: newInstalledSkills,
|
|
});
|
|
return true;
|
|
} catch (err) {
|
|
set({
|
|
error: err instanceof Error ? err.message : '卸载技能失败',
|
|
});
|
|
return false;
|
|
}
|
|
},
|
|
// === 获取技能详情 ===
|
|
getSkillDetails: async (skillId: string) => {
|
|
const { skills } = get();
|
|
return skills.find(s => s.id === skillId) || null;
|
|
},
|
|
// === 加载评论 ===
|
|
loadReviews: async (skillId: string) => {
|
|
// MVP: 从 localStorage 模拟加载评论
|
|
const reviewsKey = `zclaw-skill-reviews-${skillId}`;
|
|
const stored = localStorage.getItem(reviewsKey);
|
|
const reviews: SkillReview[] = stored ? JSON.parse(stored) : [];
|
|
return reviews;
|
|
},
|
|
// === 添加评论 ===
|
|
addReview: async (skillId: string, review: Omit<SkillReview, 'id' | 'skillId' | 'createdAt'>) => {
|
|
const reviews = await get().loadReviews(skillId);
|
|
const newReview: SkillReview = {
|
|
...review,
|
|
id: `review-${Date.now()}`,
|
|
skillId,
|
|
createdAt: new Date().toISOString(),
|
|
};
|
|
const updatedReviews = [...reviews, newReview];
|
|
// 更新技能的评分和评论数
|
|
const { skills } = get();
|
|
const updatedSkills = skills.map(s => {
|
|
if (s.id === skillId) {
|
|
const totalRating = updatedReviews.reduce((sum, r) => sum + r.rating, 0);
|
|
const avgRating = totalRating / updatedReviews.length;
|
|
return {
|
|
...s,
|
|
rating: Math.round(avgRating * 10) / 10,
|
|
reviewCount: updatedReviews.length,
|
|
};
|
|
}
|
|
return s;
|
|
});
|
|
// 持久化评论
|
|
const reviewsKey = `zclaw-skill-reviews-${skillId}`;
|
|
localStorage.setItem(reviewsKey, JSON.stringify(updatedReviews));
|
|
set({ skills: updatedSkills });
|
|
},
|
|
// === 刷新技能列表 ===
|
|
refreshSkills: async () => {
|
|
// 清除缓存并重新加载
|
|
localStorage.removeItem(STORAGE_KEY);
|
|
await get().loadSkills();
|
|
},
|
|
// === 清除错误 ===
|
|
clearError: () => {
|
|
set({ error: null });
|
|
},
|
|
// === 重置状态 ===
|
|
reset: () => {
|
|
localStorage.removeItem(STORAGE_KEY);
|
|
localStorage.removeItem(INSTALLED_KEY);
|
|
set(initialState);
|
|
},
|
|
}
|
|
);
|
|
|
|
// === 辅助函数 ===
|
|
|
|
/**
|
|
* 扫描 skills 目录获取可用技能
|
|
*/
|
|
async function scanSkillsDirectory(): Promise<Skill[]> {
|
|
// 这里我们模拟扫描,实际实现需要通过 Tauri API 访问文件系统
|
|
// 或者从预定义的技能列表中加载
|
|
const skills: Skill[] = [
|
|
// 开发类
|
|
{
|
|
id: 'code-review',
|
|
name: '代码审查',
|
|
description: '审查代码、分析代码质量、提供改进建议',
|
|
triggers: ['审查代码', '代码审查', 'code review', 'PR Review', '检查代码', '分析代码'],
|
|
capabilities: ['代码质量分析', '架构评估', '最佳实践检查', '安全审计'],
|
|
toolDeps: ['read', 'grep', 'glob'],
|
|
category: 'development',
|
|
installed: false,
|
|
tags: ['代码', '审查', '质量'],
|
|
},
|
|
{
|
|
id: 'translation',
|
|
name: '翻译助手',
|
|
description: '翻译文本、多语言转换、保持语言风格一致性',
|
|
triggers: ['翻译', 'translate', '中译英', '英译中', '翻译成', '转换成'],
|
|
capabilities: ['多语言翻译', '技术文档翻译', '代码注释翻译', 'UI 文本翻译', '风格保持'],
|
|
toolDeps: ['read', 'write'],
|
|
category: 'content',
|
|
installed: false,
|
|
tags: ['翻译', '语言', '国际化'],
|
|
},
|
|
{
|
|
id: 'chinese-writing',
|
|
name: '中文写作',
|
|
description: '中文写作助手 - 帮助撰写各类中文文档、文章、报告',
|
|
triggers: ['写一篇', '帮我写', '撰写', '起草', '润色', '中文写作'],
|
|
capabilities: ['撰写文档', '润色修改', '调整语气', '中英文翻译'],
|
|
toolDeps: ['read', 'write'],
|
|
category: 'content',
|
|
installed: false,
|
|
tags: ['写作', '文档', '中文'],
|
|
},
|
|
{
|
|
id: 'web-search',
|
|
name: '网络搜索',
|
|
description: '搜索互联网信息、整合多方来源',
|
|
triggers: ['搜索', 'search', '查找信息', '查询', '搜索网络'],
|
|
capabilities: ['搜索引擎集成', '信息提取', '来源验证', '结果整合'],
|
|
toolDeps: ['web_search'],
|
|
category: 'research',
|
|
installed: false,
|
|
tags: ['搜索', '互联网', '信息'],
|
|
},
|
|
{
|
|
id: 'data-analysis',
|
|
name: '数据分析',
|
|
description: '数据清洗、统计分析、可视化图表',
|
|
triggers: ['数据分析', '统计', '可视化', '图表', 'analytics'],
|
|
capabilities: ['数据清洗', '统计分析', '可视化图表', '报告生成'],
|
|
toolDeps: ['read', 'write', 'shell'],
|
|
category: 'analytics',
|
|
installed: false,
|
|
tags: ['数据', '分析', '可视化'],
|
|
},
|
|
{
|
|
id: 'git',
|
|
name: 'Git 操作',
|
|
description: 'Git 版本控制操作、分支管理、冲突解决',
|
|
triggers: ['git', '版本控制', '分支', '合并', 'commit', 'merge'],
|
|
capabilities: ['分支管理', '冲突解决', 'rebase', 'cherry-pick'],
|
|
toolDeps: ['shell'],
|
|
category: 'development',
|
|
installed: false,
|
|
tags: ['git', '版本控制', '分支'],
|
|
},
|
|
{
|
|
id: 'shell-command',
|
|
name: 'Shell 命令',
|
|
description: '执行 Shell 命令、系统操作',
|
|
triggers: ['shell', '命令行', '终端', 'terminal', 'bash'],
|
|
capabilities: ['命令执行', '管道操作', '脚本运行', '环境管理'],
|
|
toolDeps: ['shell'],
|
|
category: 'ops',
|
|
installed: false,
|
|
tags: ['shell', '命令', '系统'],
|
|
},
|
|
{
|
|
id: 'file-operations',
|
|
name: '文件操作',
|
|
description: '文件读写、目录管理、文件搜索',
|
|
triggers: ['文件', 'file', '读取', '写入', '目录', '文件夹'],
|
|
capabilities: ['文件读写', '目录管理', '文件搜索', '批量操作'],
|
|
toolDeps: ['read', 'write', 'glob'],
|
|
category: 'ops',
|
|
installed: false,
|
|
tags: ['文件', '目录', '读写'],
|
|
},
|
|
{
|
|
id: 'security-engineer',
|
|
name: '安全工程师',
|
|
description: '安全工程师 - 负责安全审计、漏洞检测、合规检查',
|
|
triggers: ['安全审计', '漏洞检测', '安全检查', 'security', '渗透测试'],
|
|
capabilities: ['漏洞扫描', '合规检查', '安全加固', '威胁建模'],
|
|
toolDeps: ['read', 'grep', 'shell'],
|
|
category: 'security',
|
|
installed: false,
|
|
tags: ['安全', '审计', '漏洞'],
|
|
},
|
|
{
|
|
id: 'ai-engineer',
|
|
name: 'AI 工程师',
|
|
description: 'AI/ML 工程师 - 专注机器学习模型开发、LLM 集成和生产系统部署',
|
|
triggers: ['AI工程师', '机器学习', 'ML模型', 'LLM集成', '深度学习', '模型训练'],
|
|
capabilities: ['ML 框架', 'LLM 集成', 'RAG 系统', '向量数据库'],
|
|
toolDeps: ['bash', 'read', 'write', 'grep', 'glob'],
|
|
category: 'development',
|
|
installed: false,
|
|
tags: ['AI', 'ML', 'LLM'],
|
|
},
|
|
{
|
|
id: 'senior-developer',
|
|
name: '高级开发',
|
|
description: '高级开发工程师 - 端到端功能实现、复杂问题解决',
|
|
triggers: ['高级开发', 'senior developer', '端到端', '复杂功能', '架构实现'],
|
|
capabilities: ['端到端实现', '架构设计', '性能优化', '代码重构'],
|
|
toolDeps: ['bash', 'read', 'write', 'grep', 'glob'],
|
|
category: 'development',
|
|
installed: false,
|
|
tags: ['开发', '架构', '实现'],
|
|
},
|
|
{
|
|
id: 'frontend-developer',
|
|
name: '前端开发',
|
|
description: '前端开发专家 - 擅长 React/Vue/CSS/TypeScript',
|
|
triggers: ['前端开发', '页面开发', 'UI开发', 'React', 'Vue', 'CSS'],
|
|
capabilities: ['组件开发', '样式调整', '性能优化', '响应式设计'],
|
|
toolDeps: ['read', 'write', 'shell'],
|
|
category: 'development',
|
|
installed: false,
|
|
types: ['前端', 'UI', '组件'],
|
|
},
|
|
{
|
|
id: 'backend-architect',
|
|
name: '后端架构',
|
|
description: '后端架构设计、API设计、数据库建模',
|
|
triggers: ['后端架构', 'API设计', '数据库设计', '系统架构', '微服务'],
|
|
capabilities: ['架构设计', 'API规范', '数据库建模', '性能优化'],
|
|
toolDeps: ['read', 'write', 'shell'],
|
|
category: 'development',
|
|
installed: false,
|
|
tags: ['后端', '架构', 'API'],
|
|
},
|
|
{
|
|
id: 'devops-automator',
|
|
name: 'DevOps 自动化',
|
|
description: 'CI/CD、Docker、K8s、自动化部署',
|
|
triggers: ['DevOps', 'CI/CD', 'Docker', '部署', '自动化', 'K8s'],
|
|
capabilities: ['CI/CD配置', '容器化', '自动化部署', '监控告警'],
|
|
toolDeps: ['shell', 'read', 'write'],
|
|
category: 'ops',
|
|
installed: false,
|
|
tags: ['DevOps', 'Docker', 'CI/CD'],
|
|
},
|
|
{
|
|
id: 'senior-pm',
|
|
name: '高级PM',
|
|
description: '项目管理、需求分析、迭代规划',
|
|
triggers: ['项目管理', '需求分析', '迭代规划', '产品设计', 'PRD'],
|
|
capabilities: ['需求拆解', '迭代排期', '风险评估', '文档撰写'],
|
|
toolDeps: ['read', 'write'],
|
|
category: 'management',
|
|
installed: false,
|
|
tags: ['PM', '需求', '迭代'],
|
|
},
|
|
];
|
|
return skills;
|
|
}
|