mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-13 00:14:33 +00:00
135 lines
3.3 KiB
Go
135 lines
3.3 KiB
Go
package cmd
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
"github.com/nextlevelbuilder/goclaw/internal/skills"
|
|
)
|
|
|
|
func skillsGrantUserCmd() *cobra.Command {
|
|
var jsonOutput bool
|
|
cmd := &cobra.Command{
|
|
Use: "user [skill-id] [user-id]",
|
|
Short: "Grant a skill to a user",
|
|
Args: cobra.ExactArgs(2),
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
skillsRequireGateway()
|
|
path := "/v1/skills/" + url.PathEscape(args[0]) + "/grants/users"
|
|
return runSkillsGateway(cmd.OutOrStdout(), http.MethodPost, path, map[string]any{"user_id": args[1]}, jsonOutput)
|
|
},
|
|
}
|
|
cmd.Flags().BoolVar(&jsonOutput, "json", false, "output as JSON")
|
|
return cmd
|
|
}
|
|
|
|
func skillsRevokeCmd() *cobra.Command {
|
|
cmd := &cobra.Command{Use: "revoke", Short: "Revoke skill access"}
|
|
cmd.AddCommand(skillsRevokeAgentCmd())
|
|
cmd.AddCommand(skillsRevokeUserCmd())
|
|
return cmd
|
|
}
|
|
|
|
func skillsRevokeAgentCmd() *cobra.Command {
|
|
return &cobra.Command{
|
|
Use: "agent [skill-id] [agent-id]",
|
|
Short: "Revoke a skill from an agent",
|
|
Args: cobra.ExactArgs(2),
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
skillsRequireGateway()
|
|
path := "/v1/skills/" + url.PathEscape(args[0]) + "/grants/agents/" + url.PathEscape(args[1])
|
|
return runSkillsGatewayDelete(cmd.OutOrStdout(), path)
|
|
},
|
|
}
|
|
}
|
|
|
|
func skillsRevokeUserCmd() *cobra.Command {
|
|
return &cobra.Command{
|
|
Use: "user [skill-id] [user-id]",
|
|
Short: "Revoke a skill from a user",
|
|
Args: cobra.ExactArgs(2),
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
skillsRequireGateway()
|
|
path := "/v1/skills/" + url.PathEscape(args[0]) + "/grants/users/" + url.PathEscape(args[1])
|
|
return runSkillsGatewayDelete(cmd.OutOrStdout(), path)
|
|
},
|
|
}
|
|
}
|
|
|
|
func runSkillsGateway(w io.Writer, method, path string, body any, jsonOutput bool) error {
|
|
resp, err := skillsGatewayDo(method, path, body)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if jsonOutput {
|
|
return writePrettyJSON(w, resp)
|
|
}
|
|
if ok, _ := resp["ok"].(bool); ok {
|
|
_, _ = fmt.Fprintln(w, "ok")
|
|
return nil
|
|
}
|
|
return writePrettyJSON(w, resp)
|
|
}
|
|
|
|
func runSkillsGatewayDelete(w io.Writer, path string) error {
|
|
if err := skillsGatewayDelete(path); err != nil {
|
|
return err
|
|
}
|
|
_, _ = fmt.Fprintln(w, "ok")
|
|
return nil
|
|
}
|
|
|
|
func runLocalSkillDepsStatus(w io.Writer, target string, jsonOutput bool) error {
|
|
dir := target
|
|
if filepath.Base(target) == "SKILL.md" {
|
|
dir = filepath.Dir(target)
|
|
}
|
|
manifest := skills.ScanSkillDeps(dir)
|
|
ok, missing := skills.CheckSkillDeps(manifest)
|
|
resp := map[string]any{
|
|
"skill": map[string]any{"path": dir},
|
|
"ok": ok,
|
|
"status": localDepsStatus(ok),
|
|
"manifest": manifest,
|
|
"missing": missing,
|
|
"missing_count": len(missing),
|
|
}
|
|
if jsonOutput {
|
|
return writePrettyJSON(w, resp)
|
|
}
|
|
if ok {
|
|
_, _ = fmt.Fprintln(w, "all deps satisfied")
|
|
return nil
|
|
}
|
|
_, _ = fmt.Fprintf(w, "missing dependencies: %s\n", skills.FormatMissing(missing))
|
|
return nil
|
|
}
|
|
|
|
func writePrettyJSON(w io.Writer, v any) error {
|
|
data, err := json.MarshalIndent(v, "", " ")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = fmt.Fprintln(w, string(data))
|
|
return err
|
|
}
|
|
|
|
func pathExists(path string) bool {
|
|
_, err := os.Stat(path)
|
|
return err == nil
|
|
}
|
|
|
|
func localDepsStatus(ok bool) string {
|
|
if ok {
|
|
return "ok"
|
|
}
|
|
return "missing"
|
|
}
|