mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-16 04:18:17 +08:00
fix(skill): merge partial PUT into existing row so SKILL.md saves stop 500ing (#93)
This commit is contained in:
parent
9cac7a31d1
commit
b7f69dbefe
@ -300,6 +300,29 @@ public class SkillService {
|
|||||||
* </ul>
|
* </ul>
|
||||||
* 仍不允许:name / version / author / skillType / builtin —— 这些是身份字段,
|
* 仍不允许:name / version / author / skillType / builtin —— 这些是身份字段,
|
||||||
* 改动会破坏绑定与解析。
|
* 改动会破坏绑定与解析。
|
||||||
|
*
|
||||||
|
* <p>The UI sends a partial body that only contains the fields the
|
||||||
|
* user edited (Identity edit → {@code nameZh/nameEn/description/tags/icon};
|
||||||
|
* Body edit → {@code skillContent}, plus optional {@code sourceCode}).
|
||||||
|
* Every other field on the deserialized entity is {@code null}.
|
||||||
|
*
|
||||||
|
* <p>{@link SkillEntity} declares several
|
||||||
|
* {@code @TableField(updateStrategy = FieldStrategy.ALWAYS)} columns
|
||||||
|
* — {@code name_zh}, {@code name_en}, {@code config_json},
|
||||||
|
* {@code source_code}, {@code skill_content}, {@code manifest_json},
|
||||||
|
* {@code security_scan_result}. Calling
|
||||||
|
* {@code skillMapper.updateById(partial)} would tell MyBatis Plus to
|
||||||
|
* write {@code NULL} into every ALWAYS column missing from the
|
||||||
|
* partial, wiping perfectly valid content on every save. The earlier
|
||||||
|
* #45 fix only protected the resolver's scan write-back; this path
|
||||||
|
* was still exposed (and surfaced as issue #93 when a partial PUT
|
||||||
|
* also took the workspace-sync branch with a {@code null} name and
|
||||||
|
* NPE'd inside {@code sanitizeName}).
|
||||||
|
*
|
||||||
|
* <p>Fix: merge non-null fields from the partial onto a copy of the
|
||||||
|
* existing row, then persist the merged entity. Same shape as the
|
||||||
|
* builtin branch above, just with a wider whitelist for dynamic
|
||||||
|
* skills.
|
||||||
*/
|
*/
|
||||||
public SkillEntity updateSkill(SkillEntity skill) {
|
public SkillEntity updateSkill(SkillEntity skill) {
|
||||||
SkillEntity existing = getSkill(skill.getId());
|
SkillEntity existing = getSkill(skill.getId());
|
||||||
@ -307,7 +330,7 @@ public class SkillService {
|
|||||||
if (Boolean.TRUE.equals(existing.getBuiltin())) {
|
if (Boolean.TRUE.equals(existing.getBuiltin())) {
|
||||||
// Functional fields
|
// Functional fields
|
||||||
existing.setEnabled(skill.getEnabled() != null ? skill.getEnabled() : existing.getEnabled());
|
existing.setEnabled(skill.getEnabled() != null ? skill.getEnabled() : existing.getEnabled());
|
||||||
existing.setConfigJson(skill.getConfigJson());
|
if (skill.getConfigJson() != null) existing.setConfigJson(skill.getConfigJson());
|
||||||
existing.setDescription(skill.getDescription() != null ? skill.getDescription() : existing.getDescription());
|
existing.setDescription(skill.getDescription() != null ? skill.getDescription() : existing.getDescription());
|
||||||
if (skill.getSkillContent() != null) {
|
if (skill.getSkillContent() != null) {
|
||||||
existing.setSkillContent(skill.getSkillContent());
|
existing.setSkillContent(skill.getSkillContent());
|
||||||
@ -335,20 +358,36 @@ public class SkillService {
|
|||||||
return existing;
|
return existing;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 非内置技能:允许修改所有字段,但不允许改为 builtin
|
// 非内置技能:merge non-null fields from the partial onto the
|
||||||
skill.setBuiltin(false);
|
// existing row. name / skillType / builtin stay locked because
|
||||||
skillMapper.updateById(skill);
|
// they're identity fields whose change would orphan bindings
|
||||||
log.info("Updated skill: {}", skill.getName());
|
// and break the resolver.
|
||||||
|
if (skill.getDescription() != null) existing.setDescription(skill.getDescription());
|
||||||
|
if (skill.getIcon() != null) existing.setIcon(skill.getIcon());
|
||||||
|
if (skill.getVersion() != null && !skill.getVersion().isBlank()) existing.setVersion(skill.getVersion());
|
||||||
|
if (skill.getAuthor() != null) existing.setAuthor(skill.getAuthor());
|
||||||
|
if (skill.getEnabled() != null) existing.setEnabled(skill.getEnabled());
|
||||||
|
if (skill.getTags() != null) existing.setTags(skill.getTags());
|
||||||
|
if (skill.getNameZh() != null) existing.setNameZh(skill.getNameZh());
|
||||||
|
if (skill.getNameEn() != null) existing.setNameEn(skill.getNameEn());
|
||||||
|
if (skill.getConfigJson() != null) existing.setConfigJson(skill.getConfigJson());
|
||||||
|
if (skill.getSourceCode() != null) existing.setSourceCode(skill.getSourceCode());
|
||||||
|
if (skill.getSkillContent() != null) existing.setSkillContent(skill.getSkillContent());
|
||||||
|
if (skill.getManifestJson() != null) existing.setManifestJson(skill.getManifestJson());
|
||||||
|
existing.setBuiltin(false);
|
||||||
|
|
||||||
|
skillMapper.updateById(existing);
|
||||||
|
log.info("Updated skill: {}", existing.getName());
|
||||||
|
|
||||||
// 若 skillContent 变更且约定工作区存在,同步 SKILL.md
|
// 若 skillContent 变更且约定工作区存在,同步 SKILL.md
|
||||||
syncSkillContentToWorkspace(skill);
|
syncSkillContentToWorkspace(existing);
|
||||||
|
|
||||||
// 刷新 runtime cache
|
// 刷新 runtime cache
|
||||||
if (runtimeService != null) {
|
if (runtimeService != null) {
|
||||||
runtimeService.refreshActiveSkills();
|
runtimeService.refreshActiveSkills();
|
||||||
}
|
}
|
||||||
|
|
||||||
return skill;
|
return existing;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user