mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-15 03:55:09 +08:00
feat(skill): scope skill dedup, name uniqueness and reinstall/uninstall lookup by workspace
This commit is contained in:
parent
c18ff31ae8
commit
67301c5f7c
@ -82,7 +82,10 @@ public class SkillInstaller {
|
|||||||
* {@code SkillService.hardDeleteSkill} via {@code DELETE /skills/{id}}.
|
* {@code SkillService.hardDeleteSkill} via {@code DELETE /skills/{id}}.
|
||||||
*/
|
*/
|
||||||
public void uninstall(String skillName, Long workspaceId) {
|
public void uninstall(String skillName, Long workspaceId) {
|
||||||
List<SkillEntity> skills = skillService.listSkills();
|
// Scope the lookup to this workspace (+ builtin) so a same-named skill in
|
||||||
|
// another workspace is never picked up (which would wrongly 403 below even
|
||||||
|
// though the current workspace has its own skill to uninstall).
|
||||||
|
List<SkillEntity> skills = skillService.listSkills(workspaceId);
|
||||||
SkillEntity target = skills.stream()
|
SkillEntity target = skills.stream()
|
||||||
.filter(s -> s.getName().equals(skillName))
|
.filter(s -> s.getName().equals(skillName))
|
||||||
.findFirst()
|
.findFirst()
|
||||||
@ -147,8 +150,9 @@ public class SkillInstaller {
|
|||||||
return CompletableFuture.completedFuture(null);
|
return CompletableFuture.completedFuture(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. 检查是否已存在
|
// 3. 检查是否已存在(按工作区隔离:只在本工作区 + builtin 范围内查重,
|
||||||
boolean exists = skillService.listSkills().stream()
|
// 不同工作区的同名技能可以各自独立安装)
|
||||||
|
boolean exists = skillService.listSkills(request.getWorkspaceId()).stream()
|
||||||
.anyMatch(s -> s.getName().equals(skillName));
|
.anyMatch(s -> s.getName().equals(skillName));
|
||||||
if (exists && !Boolean.TRUE.equals(request.getOverwrite())) {
|
if (exists && !Boolean.TRUE.equals(request.getOverwrite())) {
|
||||||
task.markFailed("Skill '" + skillName + "' already exists. Set overwrite=true to replace.");
|
task.markFailed("Skill '" + skillName + "' already exists. Set overwrite=true to replace.");
|
||||||
@ -218,7 +222,8 @@ public class SkillInstaller {
|
|||||||
throw new vip.mate.exception.MateClawException("err.skill.name_required", "Cannot determine skill name from bundle");
|
throw new vip.mate.exception.MateClawException("err.skill.name_required", "Cannot determine skill name from bundle");
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean exists = skillService.listSkills().stream()
|
// Workspace-scoped dedup: same-named skills in different workspaces coexist.
|
||||||
|
boolean exists = skillService.listSkills(workspaceId).stream()
|
||||||
.anyMatch(s -> s.getName().equals(skillName));
|
.anyMatch(s -> s.getName().equals(skillName));
|
||||||
if (exists && !overwrite) {
|
if (exists && !overwrite) {
|
||||||
throw new vip.mate.exception.MateClawException("err.skill.name_exists",
|
throw new vip.mate.exception.MateClawException("err.skill.name_exists",
|
||||||
@ -263,7 +268,9 @@ public class SkillInstaller {
|
|||||||
boolean enable, Long workspaceId) {
|
boolean enable, Long workspaceId) {
|
||||||
SkillEntity skillEntity;
|
SkillEntity skillEntity;
|
||||||
if (exists) {
|
if (exists) {
|
||||||
skillEntity = skillService.listSkills().stream()
|
// Locate the row to update within THIS workspace (+ builtin), so a
|
||||||
|
// reinstall never grabs a same-named skill owned by another workspace.
|
||||||
|
skillEntity = skillService.listSkills(workspaceId).stream()
|
||||||
.filter(s -> s.getName().equals(skillName))
|
.filter(s -> s.getName().equals(skillName))
|
||||||
.findFirst().orElseThrow();
|
.findFirst().orElseThrow();
|
||||||
skillEntity.setSkillContent(bundle.content());
|
skillEntity.setSkillContent(bundle.content());
|
||||||
|
|||||||
@ -274,7 +274,8 @@ public class SkillService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 按名称查找技能(RFC-023:SkillManageTool 重名检查用)
|
* 按名称查找技能(全局,跨所有工作区)。仅用于内置技能同步等全局语义场景;
|
||||||
|
* 工作区相关的重名检查请用 {@link #findByName(String, Long)}。
|
||||||
*/
|
*/
|
||||||
public SkillEntity findByName(String name) {
|
public SkillEntity findByName(String name) {
|
||||||
return skillMapper.selectOne(new LambdaQueryWrapper<SkillEntity>()
|
return skillMapper.selectOne(new LambdaQueryWrapper<SkillEntity>()
|
||||||
@ -282,6 +283,17 @@ public class SkillService {
|
|||||||
.last("LIMIT 1"));
|
.last("LIMIT 1"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按名称在指定工作区内查找技能(含 builtin 全局可见)。用于工作区隔离的
|
||||||
|
* 重名/存在性检查,避免跨工作区错误命中别的工作区的同名技能。
|
||||||
|
*/
|
||||||
|
public SkillEntity findByName(String name, Long workspaceId) {
|
||||||
|
LambdaQueryWrapper<SkillEntity> wrapper = new LambdaQueryWrapper<SkillEntity>()
|
||||||
|
.eq(SkillEntity::getName, name);
|
||||||
|
applyWorkspaceScope(wrapper, workspaceId);
|
||||||
|
return skillMapper.selectOne(wrapper.last("LIMIT 1"));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 按类型获取技能列表
|
* 按类型获取技能列表
|
||||||
*/
|
*/
|
||||||
@ -323,9 +335,12 @@ public class SkillService {
|
|||||||
throw new MateClawException("err.skill.name_required", "技能名称不能为空");
|
throw new MateClawException("err.skill.name_required", "技能名称不能为空");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查名称唯一性
|
// 名称唯一性按工作区隔离:同名技能只要不在同一工作区(且都不是 builtin)即可共存。
|
||||||
Long count = skillMapper.selectCount(new LambdaQueryWrapper<SkillEntity>()
|
// 撞 builtin 名仍视为冲突(builtin 全局可见)。
|
||||||
.eq(SkillEntity::getName, skill.getName()));
|
LambdaQueryWrapper<SkillEntity> dupCheck = new LambdaQueryWrapper<SkillEntity>()
|
||||||
|
.eq(SkillEntity::getName, skill.getName());
|
||||||
|
applyWorkspaceScope(dupCheck, skill.getWorkspaceId());
|
||||||
|
Long count = skillMapper.selectCount(dupCheck);
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
throw new MateClawException("err.skill.name_exists", "技能名称已存在: " + skill.getName());
|
throw new MateClawException("err.skill.name_exists", "技能名称已存在: " + skill.getName());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -95,8 +95,9 @@ public class SkillSynthesisService {
|
|||||||
}
|
}
|
||||||
name = name.strip().toLowerCase().replaceAll("[^a-z0-9._-]", "-");
|
name = name.strip().toLowerCase().replaceAll("[^a-z0-9._-]", "-");
|
||||||
|
|
||||||
// 去重
|
// 去重(按工作区隔离:只与本工作区 + builtin 的同名技能避让,
|
||||||
SkillEntity existing = skillService.findByName(name);
|
// 不同工作区的同名技能不应互相影响命名)
|
||||||
|
SkillEntity existing = skillService.findByName(name, workspaceId);
|
||||||
if (existing != null) {
|
if (existing != null) {
|
||||||
name = name + "-" + (System.currentTimeMillis() % 10000);
|
name = name + "-" + (System.currentTimeMillis() % 10000);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user