fix command error
This commit is contained in:
parent
3bd1851aa6
commit
9d0954b5c5
5 changed files with 48 additions and 30 deletions
|
|
@ -12,7 +12,6 @@ import (
|
||||||
|
|
||||||
type deps struct {
|
type deps struct {
|
||||||
workspace string
|
workspace string
|
||||||
installer *skills.SkillInstaller
|
|
||||||
skillsLoader *skills.SkillsLoader
|
skillsLoader *skills.SkillsLoader
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -43,20 +42,6 @@ func NewSkillsCommand() *cobra.Command {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
installerFn := func() (*skills.SkillInstaller, error) {
|
|
||||||
if d.installer == nil {
|
|
||||||
installer, err := skills.NewSkillInstaller(d.workspace, "", "")
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error creating skills installer: %w", err)
|
|
||||||
}
|
|
||||||
d.installer = installer
|
|
||||||
}
|
|
||||||
if d.installer == nil {
|
|
||||||
return nil, fmt.Errorf("skills installer is not initialized")
|
|
||||||
}
|
|
||||||
return d.installer, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
loaderFn := func() (*skills.SkillsLoader, error) {
|
loaderFn := func() (*skills.SkillsLoader, error) {
|
||||||
if d.skillsLoader == nil {
|
if d.skillsLoader == nil {
|
||||||
return nil, fmt.Errorf("skills loader is not initialized")
|
return nil, fmt.Errorf("skills loader is not initialized")
|
||||||
|
|
@ -76,7 +61,7 @@ func NewSkillsCommand() *cobra.Command {
|
||||||
newInstallCommand(),
|
newInstallCommand(),
|
||||||
newInstallBuiltinCommand(workspaceFn),
|
newInstallBuiltinCommand(workspaceFn),
|
||||||
newListBuiltinCommand(),
|
newListBuiltinCommand(),
|
||||||
newRemoveCommand(installerFn),
|
newRemoveCommand(workspaceFn),
|
||||||
newSearchCommand(),
|
newSearchCommand(),
|
||||||
newShowCommand(loaderFn),
|
newShowCommand(loaderFn),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -100,15 +100,24 @@ func skillsInstallFromRegistry(cfg *config.Config, registryName, target string)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func skillsRemoveCmd(installer *skills.SkillInstaller, skillName string) {
|
func skillsRemoveFromWorkspace(workspace, skillName string) error {
|
||||||
fmt.Printf("Removing skill '%s'...\n", skillName)
|
name := strings.TrimSpace(skillName)
|
||||||
|
name = strings.Trim(name, "/")
|
||||||
if err := installer.Uninstall(skillName); err != nil {
|
if name == "" {
|
||||||
fmt.Printf("✗ Failed to remove skill: %v\n", err)
|
return fmt.Errorf("skill name is required")
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
if strings.Contains(name, "/") {
|
||||||
fmt.Printf("✓ Skill '%s' removed successfully!\n", skillName)
|
parts := strings.Split(name, "/")
|
||||||
|
name = parts[len(parts)-1]
|
||||||
|
}
|
||||||
|
skillDir := filepath.Join(workspace, "skills", name)
|
||||||
|
if _, err := os.Stat(skillDir); os.IsNotExist(err) {
|
||||||
|
return fmt.Errorf("skill '%s' not found", name)
|
||||||
|
}
|
||||||
|
if err := os.RemoveAll(skillDir); err != nil {
|
||||||
|
return fmt.Errorf("failed to remove skill '%s': %w", name, err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func skillsInstallBuiltinCmd(workspace string) {
|
func skillsInstallBuiltinCmd(workspace string) {
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,9 @@ package skills
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"github.com/sipeed/picoclaw/pkg/skills"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func newRemoveCommand(installerFn func() (*skills.SkillInstaller, error)) *cobra.Command {
|
func newRemoveCommand(workspaceFn func() (string, error)) *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "remove",
|
Use: "remove",
|
||||||
Aliases: []string{"rm", "uninstall"},
|
Aliases: []string{"rm", "uninstall"},
|
||||||
|
|
@ -14,12 +12,11 @@ func newRemoveCommand(installerFn func() (*skills.SkillInstaller, error)) *cobra
|
||||||
Args: cobra.ExactArgs(1),
|
Args: cobra.ExactArgs(1),
|
||||||
Example: `picoclaw skills remove weather`,
|
Example: `picoclaw skills remove weather`,
|
||||||
RunE: func(_ *cobra.Command, args []string) error {
|
RunE: func(_ *cobra.Command, args []string) error {
|
||||||
installer, err := installerFn()
|
workspace, err := workspaceFn()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
skillsRemoveCmd(installer, args[0])
|
return skillsRemoveFromWorkspace(workspace, args[0])
|
||||||
return nil
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -140,6 +140,9 @@ func (r *GitHubRegistry) Search(ctx context.Context, query string, limit int) ([
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to read github search response: %w", err)
|
return nil, fmt.Errorf("failed to read github search response: %w", err)
|
||||||
}
|
}
|
||||||
|
if resp.StatusCode == http.StatusUnauthorized && r.installer.githubToken == "" && isGitHubAuthRequiredError(body) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
if resp.StatusCode == http.StatusForbidden && r.installer.githubToken == "" && isGitHubRateLimitError(body) {
|
if resp.StatusCode == http.StatusForbidden && r.installer.githubToken == "" && isGitHubRateLimitError(body) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
@ -193,6 +196,12 @@ func isGitHubRateLimitError(body []byte) bool {
|
||||||
return strings.Contains(message, "rate limit exceeded")
|
return strings.Contains(message, "rate limit exceeded")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isGitHubAuthRequiredError(body []byte) bool {
|
||||||
|
message := strings.ToLower(string(body))
|
||||||
|
return strings.Contains(message, "requires authentication") ||
|
||||||
|
strings.Contains(message, "must be authenticated to access the code search api")
|
||||||
|
}
|
||||||
|
|
||||||
func githubSearchSlug(item gitHubCodeSearchItem) (string, bool) {
|
func githubSearchSlug(item gitHubCodeSearchItem) (string, bool) {
|
||||||
fullName := strings.TrimSpace(item.Repository.FullName)
|
fullName := strings.TrimSpace(item.Repository.FullName)
|
||||||
if fullName == "" {
|
if fullName == "" {
|
||||||
|
|
|
||||||
|
|
@ -118,3 +118,21 @@ func TestGitHubRegistrySearchReturnsEmptyOnUnauthenticatedRateLimit(t *testing.T
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Empty(t, results)
|
assert.Empty(t, results)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGitHubRegistrySearchReturnsEmptyOnUnauthenticatedAuthRequired(t *testing.T) {
|
||||||
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
assert.Empty(t, r.Header.Get("Authorization"))
|
||||||
|
w.WriteHeader(http.StatusUnauthorized)
|
||||||
|
_, _ = w.Write([]byte(
|
||||||
|
`{"message":"Requires authentication","errors":[{"message":"Must be authenticated to access the code search API"}]}`,
|
||||||
|
))
|
||||||
|
}))
|
||||||
|
defer server.Close()
|
||||||
|
|
||||||
|
registry := GitHubRegistryConfig{Enabled: true, BaseURL: server.URL}.BuildRegistry()
|
||||||
|
require.NotNil(t, registry)
|
||||||
|
|
||||||
|
results, err := registry.Search(context.Background(), "pr review", 5)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Empty(t, results)
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue