新增 install_remote_skills_batch() 函数,利用 npx skills add 原生多 --skill 支持, 将安装 N 个 skill 的仓库克隆次数从 2N 降至 1。 后端: - remote_skill_install_service.py 新增批处理 + _find_skill_dir() - skill_router.py 新增 POST /remote/install-batch 端点 (admin 权限) - 非法 skill 名不阻塞其他合法 skill,结果按请求顺序返回 - CLI 部分失败时仍导入已安装的 skill - import 失败后 rollback session,不影响后续导入 前端: - skill_api.js 新增 installRemoteSkillsBatch() - SkillCardList.vue 改为单次批处理调用 测试: - 4 个单元测试覆盖正常安装/缺失跳过/部分失败/非法名场景 文档: - docs/develop-guides/roadmap.md 更新开发记录 - docs/vibe/2026-05-14-remote-skill-batch-install-plan.md 方案文档(含设计决策)
100 lines
2.7 KiB
JavaScript
100 lines
2.7 KiB
JavaScript
import { apiAdminGet, apiAdminPost, apiAdminPut, apiAdminDelete } from './base'
|
|
|
|
const BASE_URL = '/api/system/skills'
|
|
|
|
export const listSkills = async () => {
|
|
return apiAdminGet(BASE_URL)
|
|
}
|
|
|
|
export const importSkillZip = async (file) => {
|
|
const formData = new FormData()
|
|
formData.append('file', file)
|
|
return apiAdminPost(`${BASE_URL}/import`, formData)
|
|
}
|
|
|
|
export const listRemoteSkills = async (source) => {
|
|
return apiAdminPost(`${BASE_URL}/remote/list`, { source })
|
|
}
|
|
|
|
export const installRemoteSkill = async (payload) => {
|
|
return apiAdminPost(`${BASE_URL}/remote/install`, payload)
|
|
}
|
|
|
|
export const installRemoteSkillsBatch = async (payload) => {
|
|
return apiAdminPost(`${BASE_URL}/remote/install-batch`, payload)
|
|
}
|
|
|
|
export const getSkillDependencyOptions = async () => {
|
|
return apiAdminGet(`${BASE_URL}/dependency-options`)
|
|
}
|
|
|
|
export const listBuiltinSkills = async () => {
|
|
return apiAdminGet(`${BASE_URL}/builtin`)
|
|
}
|
|
|
|
export const installBuiltinSkill = async (slug) => {
|
|
return apiAdminPost(`${BASE_URL}/builtin/${encodeURIComponent(slug)}/install`)
|
|
}
|
|
|
|
export const updateBuiltinSkill = async (slug, force = false) => {
|
|
return apiAdminPost(`${BASE_URL}/builtin/${encodeURIComponent(slug)}/update`, { force })
|
|
}
|
|
|
|
export const getSkillTree = async (slug) => {
|
|
return apiAdminGet(`${BASE_URL}/${encodeURIComponent(slug)}/tree`)
|
|
}
|
|
|
|
export const getSkillFile = async (slug, path) => {
|
|
return apiAdminGet(
|
|
`${BASE_URL}/${encodeURIComponent(slug)}/file?path=${encodeURIComponent(path)}`
|
|
)
|
|
}
|
|
|
|
export const createSkillFile = async (slug, payload) => {
|
|
return apiAdminPost(`${BASE_URL}/${encodeURIComponent(slug)}/file`, payload)
|
|
}
|
|
|
|
export const updateSkillFile = async (slug, payload) => {
|
|
return apiAdminPut(`${BASE_URL}/${encodeURIComponent(slug)}/file`, payload)
|
|
}
|
|
|
|
export const updateSkillDependencies = async (slug, payload) => {
|
|
return apiAdminPut(`${BASE_URL}/${encodeURIComponent(slug)}/dependencies`, payload)
|
|
}
|
|
|
|
export const deleteSkillFile = async (slug, path) => {
|
|
return apiAdminDelete(
|
|
`${BASE_URL}/${encodeURIComponent(slug)}/file?path=${encodeURIComponent(path)}`
|
|
)
|
|
}
|
|
|
|
export const exportSkill = async (slug) => {
|
|
return apiAdminGet(`${BASE_URL}/${encodeURIComponent(slug)}/export`, {}, 'blob')
|
|
}
|
|
|
|
export const deleteSkill = async (slug) => {
|
|
return apiAdminDelete(`${BASE_URL}/${encodeURIComponent(slug)}`)
|
|
}
|
|
|
|
export const skillApi = {
|
|
listSkills,
|
|
importSkillZip,
|
|
listRemoteSkills,
|
|
installRemoteSkill,
|
|
installRemoteSkillsBatch,
|
|
getSkillDependencyOptions,
|
|
listBuiltinSkills,
|
|
installBuiltinSkill,
|
|
updateBuiltinSkill,
|
|
getSkillTree,
|
|
getSkillFile,
|
|
createSkillFile,
|
|
updateSkillFile,
|
|
updateSkillDependencies,
|
|
deleteSkillFile,
|
|
exportSkill,
|
|
deleteSkill
|
|
}
|
|
|
|
export default skillApi
|