FetchBlob retrieves the content of a blob by SHA.
(client *api.Client, host, owner, repo, sha string)
| 869 | |
| 870 | // FetchBlob retrieves the content of a blob by SHA. |
| 871 | func FetchBlob(client *api.Client, host, owner, repo, sha string) (string, error) { |
| 872 | apiPath := fmt.Sprintf("repos/%s/%s/git/blobs/%s", url.PathEscape(owner), url.PathEscape(repo), url.PathEscape(sha)) |
| 873 | var resp struct { |
| 874 | SHA string `json:"sha"` |
| 875 | Content string `json:"content"` |
| 876 | Encoding string `json:"encoding"` |
| 877 | } |
| 878 | if err := client.REST(host, "GET", apiPath, nil, &resp); err != nil { |
| 879 | return "", fmt.Errorf("could not fetch blob: %w", err) |
| 880 | } |
| 881 | |
| 882 | if resp.Encoding != "base64" { |
| 883 | return "", fmt.Errorf("unexpected blob encoding: %s", resp.Encoding) |
| 884 | } |
| 885 | |
| 886 | // GitHub API returns base64 with embedded newlines; use the StdEncoding |
| 887 | // decoder via a reader to handle them transparently. |
| 888 | decoded, err := io.ReadAll(base64.NewDecoder(base64.StdEncoding, strings.NewReader(resp.Content))) |
| 889 | if err != nil { |
| 890 | return "", fmt.Errorf("could not decode blob content: %w", err) |
| 891 | } |
| 892 | |
| 893 | return string(decoded), nil |
| 894 | } |
| 895 | |
| 896 | // DiscoverLocalSkills finds non-hidden-dir skills in a local directory using |
| 897 | // the same conventions as remote discovery. Hidden-dir skills are excluded; use |