diff --git a/cmd/update/update.go b/cmd/update/update.go index e639a1de2..129ef4562 100644 --- a/cmd/update/update.go +++ b/cmd/update/update.go @@ -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 } diff --git a/cmd/update/update_test.go b/cmd/update/update_test.go index 3a92dd0b1..9f2904b6f 100644 --- a/cmd/update/update_test.go +++ b/cmd/update/update_test.go @@ -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) } } diff --git a/internal/skillscheck/layout.go b/internal/skillscheck/layout.go index ae15a56f6..224d7c746 100644 --- a/internal/skillscheck/layout.go +++ b/internal/skillscheck/layout.go @@ -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] { diff --git a/internal/skillscheck/sync_test.go b/internal/skillscheck/sync_test.go index d8a1a97da..8e6f06ae7 100644 --- a/internal/skillscheck/sync_test.go +++ b/internal/skillscheck/sync_test.go @@ -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) {