fix: filter stale flat skills after official discovery

This commit is contained in:
guokexin.02
2026-07-07 14:50:49 +08:00
parent d134da8536
commit 9ea42d1bc6
4 changed files with 27 additions and 27 deletions

View File

@@ -358,15 +358,6 @@ func validateSkillsLayoutOptions(opts *UpdateOptions) errs.TypedError {
if _, ok := skillscheck.NormalizeLayout(opts.SkillsLayout); !ok {
return errs.NewValidationError(errs.SubtypeInvalidArgument, "--skills-layout must be one of separate or hybrid").WithParam("--skills-layout")
}
layout, flat := resolveSkillsSyncOptions(opts.SkillsLayout, opts.FlatSkills, opts.FlatSet)
if layout != skillscheck.LayoutHybrid {
return nil
}
for _, skill := range flat {
if skill == "lark-shared" {
return errs.NewValidationError(errs.SubtypeInvalidArgument, "lark-shared cannot be selected by --flat-skills; it is managed automatically for lark-suite compatibility").WithParam("--flat-skills")
}
}
return nil
}

View File

@@ -1137,21 +1137,14 @@ func TestValidateSkillsLayoutOptionsRejectsSuiteMode(t *testing.T) {
}
}
func TestValidateSkillsLayoutOptionsRejectsSharedFlatInHybrid(t *testing.T) {
func TestValidateSkillsLayoutOptionsAllowsFlatSkillsFilteringAfterOfficialDiscovery(t *testing.T) {
err := validateSkillsLayoutOptions(&UpdateOptions{
SkillsLayout: skillscheck.LayoutHybrid,
FlatSkills: "lark-shared",
FlatSkills: "lark-shared,lark-unknown",
FlatSet: true,
})
if err == nil {
t.Fatal("validateSkillsLayoutOptions() err = nil, want validation error")
}
var validation *errs.ValidationError
if !errors.As(err, &validation) {
t.Fatalf("errors.As(err, *ValidationError) = false for %T", err)
}
if validation.Param != "--flat-skills" {
t.Fatalf("validation.Param = %q, want --flat-skills", validation.Param)
if err != nil {
t.Fatalf("validateSkillsLayoutOptions() err = %v, want nil", err)
}
}

View File

@@ -166,10 +166,10 @@ func resolveHybridSkillSets(layout string, requestedFlat, official []string, ski
effectiveFlat := map[string]bool{}
for _, skill := range uniqueSorted(requestedFlat) {
if skill == sharedSkillName {
return nil, nil, fmt.Errorf("%s cannot be selected by --flat-skills", sharedSkillName)
continue
}
if !officialSet[skill] {
return nil, nil, fmt.Errorf("flat skill %q is not in official skills", skill)
continue
}
configuredFlat[skill] = true
if !deletedSet[skill] {

View File

@@ -867,23 +867,39 @@ func TestSyncSkills_HybridWithNoFlatSkillsDoesNotKeepSharedTopLevel(t *testing.T
}
}
func TestSyncSkills_HybridRejectsSharedFlatSkill(t *testing.T) {
func TestSyncSkills_HybridFiltersNonFlatOfficialSkills(t *testing.T) {
dir := t.TempDir()
t.Setenv("LARKSUITE_CLI_CONFIG_DIR", t.TempDir())
paths := map[string]string{}
for _, name := range []string{"lark-calendar", "lark-shared", "lark-suite"} {
paths[name] = filepath.Join(dir, name)
writeTestSkill(t, paths[name], name)
}
runner := &fakeSkillsRunner{
officialIndexOut: officialSkillsIndexOutput("lark-calendar", "lark-shared"),
globalJSONOut: globalSkillsJSONOutput("lark-calendar", "lark-shared"),
globalJSONOut: globalSkillsJSONFromPaths(paths),
}
result := SyncSkills(SyncOptions{
Version: "1.0.33",
Layout: LayoutHybrid,
FlatSkills: []string{"lark-shared"},
FlatSkills: []string{"lark-calendar", "lark-missing", "lark-shared"},
Runner: runner,
Now: time.Now,
})
if result.Err == nil || !strings.Contains(result.Err.Error(), "lark-shared") {
t.Fatalf("SyncSkills() err = %v, want lark-shared validation error", result.Err)
if result.Err != nil {
t.Fatalf("SyncSkills() err = %v, want nil", result.Err)
}
assertStrings(t, result.Flat, []string{"lark-calendar"})
state, readable, err := ReadState()
if err != nil || !readable {
t.Fatalf("ReadState() = (_, %v, %v), want readable", readable, err)
}
assertStrings(t, state.FlatSkills, []string{"lark-calendar"})
}
func TestSyncSkills_ParseEmptyWithNonEmptyStdoutFallsBack(t *testing.T) {