diff --git a/pkg/config/config_struct.go b/pkg/config/config_struct.go index 1bb64356b..58e2b4337 100644 --- a/pkg/config/config_struct.go +++ b/pkg/config/config_struct.go @@ -351,6 +351,20 @@ func (v *SkillsRegistriesConfig) UnmarshalJSON(data []byte) error { return nil } +func (v SkillsRegistriesConfig) MarshalJSON() ([]byte, error) { + if v == nil { + return []byte("null"), nil + } + mm := make(map[string]SkillRegistryConfig, len(v)) + for _, registry := range v { + if registry == nil || registry.Name == "" { + continue + } + mm[registry.Name] = *registry + } + return json.Marshal(mm) +} + func (c *SkillRegistryConfig) UnmarshalJSON(data []byte) error { type alias struct { Name string `json:"name,omitempty"` diff --git a/pkg/config/config_struct_test.go b/pkg/config/config_struct_test.go index 1d60b795f..0b5ad9627 100644 --- a/pkg/config/config_struct_test.go +++ b/pkg/config/config_struct_test.go @@ -203,3 +203,46 @@ func TestSkillsRegistriesConfigMarshalYAMLIncludesRegistryToken(t *testing.T) { assert.True(t, ok) assert.Equal(t, "registry-auth-token", github.AuthToken.String()) } + +func TestSkillsRegistriesConfigMarshalJSONPreservesObjectShape(t *testing.T) { + registries := SkillsRegistriesConfig{ + &SkillRegistryConfig{ + Name: "github", + Enabled: true, + BaseURL: "https://ghe.example.com/git", + Param: map[string]any{ + "proxy": "http://127.0.0.1:7890", + }, + }, + &SkillRegistryConfig{ + Name: "clawhub", + Enabled: true, + BaseURL: "https://clawhub.ai", + }, + } + + data, err := json.Marshal(registries) + assert.NoError(t, err) + assert.Contains(t, string(data), `"github":{`) + assert.Contains(t, string(data), `"clawhub":{`) + assert.NotContains(t, string(data), `[{`) + + var decoded map[string]json.RawMessage + err = json.Unmarshal(data, &decoded) + assert.NoError(t, err) + assert.Contains(t, decoded, "github") + assert.Contains(t, decoded, "clawhub") + + var roundTripped SkillsRegistriesConfig + err = json.Unmarshal(data, &roundTripped) + assert.NoError(t, err) + + github, ok := roundTripped.Get("github") + assert.True(t, ok) + assert.Equal(t, "https://ghe.example.com/git", github.BaseURL) + assert.Equal(t, "http://127.0.0.1:7890", github.Param["proxy"]) + + clawhub, ok := roundTripped.Get("clawhub") + assert.True(t, ok) + assert.Equal(t, "https://clawhub.ai", clawhub.BaseURL) +} diff --git a/pkg/skills/github_registry_test.go b/pkg/skills/github_registry_test.go index a773b533c..1f47bb97a 100644 --- a/pkg/skills/github_registry_test.go +++ b/pkg/skills/github_registry_test.go @@ -155,3 +155,19 @@ func TestGitHubRegistrySkillURLUsesProvidedVersionAndBasePath(t *testing.T) { registry.SkillURL("https://ghe.example.com/git/org/repo/tree/dev/skills/pr-review", ""), ) } + +func TestGitHubRegistryResolveInstallDirNameSupportsFullURLs(t *testing.T) { + registry := GitHubRegistryConfig{ + Enabled: true, + BaseURL: "https://ghe.example.com/git", + }.BuildRegistry() + require.NotNil(t, registry) + + dirName, err := registry.ResolveInstallDirName("https://ghe.example.com/git/org/repo/tree/dev/skills/pr-review") + require.NoError(t, err) + assert.Equal(t, "pr-review", dirName) + + dirName, err = registry.ResolveInstallDirName("https://github.com/org/repo/tree/main/skills/release-checklist") + require.NoError(t, err) + assert.Equal(t, "release-checklist", dirName) +}