fix cli skills install origin metadata
This commit is contained in:
parent
eac37366fa
commit
34eeaf5899
2 changed files with 97 additions and 0 deletions
|
|
@ -2,6 +2,7 @@ package skills
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
|
@ -11,12 +12,23 @@ import (
|
||||||
|
|
||||||
"github.com/sipeed/picoclaw/cmd/picoclaw/internal"
|
"github.com/sipeed/picoclaw/cmd/picoclaw/internal"
|
||||||
"github.com/sipeed/picoclaw/pkg/config"
|
"github.com/sipeed/picoclaw/pkg/config"
|
||||||
|
"github.com/sipeed/picoclaw/pkg/fileutil"
|
||||||
"github.com/sipeed/picoclaw/pkg/skills"
|
"github.com/sipeed/picoclaw/pkg/skills"
|
||||||
"github.com/sipeed/picoclaw/pkg/utils"
|
"github.com/sipeed/picoclaw/pkg/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
const skillsSearchMaxResults = 20
|
const skillsSearchMaxResults = 20
|
||||||
|
|
||||||
|
type installedSkillOriginMeta struct {
|
||||||
|
Version int `json:"version"`
|
||||||
|
OriginKind string `json:"origin_kind,omitempty"`
|
||||||
|
Registry string `json:"registry,omitempty"`
|
||||||
|
Slug string `json:"slug,omitempty"`
|
||||||
|
RegistryURL string `json:"registry_url,omitempty"`
|
||||||
|
InstalledVersion string `json:"installed_version,omitempty"`
|
||||||
|
InstalledAt int64 `json:"installed_at"`
|
||||||
|
}
|
||||||
|
|
||||||
func skillsListCmd(loader *skills.SkillsLoader) {
|
func skillsListCmd(loader *skills.SkillsLoader) {
|
||||||
allSkills := loader.ListSkills()
|
allSkills := loader.ListSkills()
|
||||||
|
|
||||||
|
|
@ -92,6 +104,21 @@ func skillsInstallFromRegistry(cfg *config.Config, registryName, target string)
|
||||||
fmt.Printf("\u26a0\ufe0f Warning: skill '%s' is flagged as suspicious.\n", target)
|
fmt.Printf("\u26a0\ufe0f Warning: skill '%s' is flagged as suspicious.\n", target)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
normalizedSlug := skills.NormalizeInstallTargetForRegistry(cfg.Tools.Skills, registry.Name(), target)
|
||||||
|
installedAt := time.Now().UnixMilli()
|
||||||
|
if err := writeInstalledSkillOriginMeta(targetDir, installedSkillOriginMeta{
|
||||||
|
Version: 1,
|
||||||
|
OriginKind: "third_party",
|
||||||
|
Registry: registry.Name(),
|
||||||
|
Slug: normalizedSlug,
|
||||||
|
RegistryURL: registry.SkillURL(normalizedSlug, result.Version),
|
||||||
|
InstalledVersion: result.Version,
|
||||||
|
InstalledAt: installedAt,
|
||||||
|
}); err != nil {
|
||||||
|
_ = os.RemoveAll(targetDir)
|
||||||
|
return fmt.Errorf("✗ failed to persist skill metadata: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Printf("\u2713 Skill '%s' v%s installed successfully!\n", dirName, result.Version)
|
fmt.Printf("\u2713 Skill '%s' v%s installed successfully!\n", dirName, result.Version)
|
||||||
if result.Summary != "" {
|
if result.Summary != "" {
|
||||||
fmt.Printf(" %s\n", result.Summary)
|
fmt.Printf(" %s\n", result.Summary)
|
||||||
|
|
@ -100,6 +127,14 @@ func skillsInstallFromRegistry(cfg *config.Config, registryName, target string)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func writeInstalledSkillOriginMeta(targetDir string, meta installedSkillOriginMeta) error {
|
||||||
|
data, err := json.MarshalIndent(meta, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return fileutil.WriteFileAtomic(filepath.Join(targetDir, ".skill-origin.json"), data, 0o600)
|
||||||
|
}
|
||||||
|
|
||||||
func skillsRemoveFromWorkspace(workspace, skillName string) error {
|
func skillsRemoveFromWorkspace(workspace, skillName string) error {
|
||||||
name := strings.TrimSpace(skillName)
|
name := strings.TrimSpace(skillName)
|
||||||
name = strings.Trim(name, "/")
|
name = strings.Trim(name, "/")
|
||||||
|
|
|
||||||
62
cmd/picoclaw/internal/skills/helpers_test.go
Normal file
62
cmd/picoclaw/internal/skills/helpers_test.go
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
package skills
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/sipeed/picoclaw/pkg/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSkillsInstallFromRegistryWritesOriginMetadata(t *testing.T) {
|
||||||
|
workspace := t.TempDir()
|
||||||
|
cfg := config.DefaultConfig()
|
||||||
|
cfg.Agents.Defaults.Workspace = workspace
|
||||||
|
|
||||||
|
var server *httptest.Server
|
||||||
|
server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
switch r.URL.Path {
|
||||||
|
case "/api/v3/repos/foo/bar":
|
||||||
|
require.NoError(t, json.NewEncoder(w).Encode(map[string]any{"default_branch": "master"}))
|
||||||
|
case "/api/v3/repos/foo/bar/contents/.agents/skills/pr-review":
|
||||||
|
assert.Equal(t, "ref=master", r.URL.RawQuery)
|
||||||
|
require.NoError(t, json.NewEncoder(w).Encode([]map[string]any{{
|
||||||
|
"type": "file",
|
||||||
|
"name": "SKILL.md",
|
||||||
|
"download_url": server.URL + "/raw/foo/bar/master/.agents/skills/pr-review/SKILL.md",
|
||||||
|
}}))
|
||||||
|
case "/raw/foo/bar/master/.agents/skills/pr-review/SKILL.md":
|
||||||
|
_, _ = w.Write([]byte("---\nname: pr-review\ndescription: PR review skill\n---\n# PR Review\n"))
|
||||||
|
default:
|
||||||
|
http.NotFound(w, r)
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
defer server.Close()
|
||||||
|
|
||||||
|
githubRegistry, ok := cfg.Tools.Skills.Registries.Get("github")
|
||||||
|
require.True(t, ok)
|
||||||
|
githubRegistry.BaseURL = server.URL
|
||||||
|
cfg.Tools.Skills.Registries.Set("github", githubRegistry)
|
||||||
|
|
||||||
|
target := server.URL + "/foo/bar/tree/master/.agents/skills/pr-review"
|
||||||
|
require.NoError(t, skillsInstallFromRegistry(cfg, "github", target))
|
||||||
|
|
||||||
|
metaPath := filepath.Join(workspace, "skills", "pr-review", ".skill-origin.json")
|
||||||
|
data, err := os.ReadFile(metaPath)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var meta installedSkillOriginMeta
|
||||||
|
require.NoError(t, json.Unmarshal(data, &meta))
|
||||||
|
assert.Equal(t, "third_party", meta.OriginKind)
|
||||||
|
assert.Equal(t, "github", meta.Registry)
|
||||||
|
assert.Equal(t, "foo/bar/.agents/skills/pr-review", meta.Slug)
|
||||||
|
assert.Equal(t, server.URL+"/foo/bar/tree/master/.agents/skills/pr-review", meta.RegistryURL)
|
||||||
|
assert.Equal(t, "master", meta.InstalledVersion)
|
||||||
|
assert.NotZero(t, meta.InstalledAt)
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue