Skip to content

Commit 23cb7a2

Browse files
committed
feat: release v0.9.5 - polished help text, add optional repos to README
1 parent 95996e2 commit 23cb7a2

File tree

10 files changed

+178
-68
lines changed

10 files changed

+178
-68
lines changed

README.md

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -128,14 +128,27 @@ ASK comes pre-configured with trusted sources:
128128
| Source | Description |
129129
| :--- | :--- |
130130
| **Anthropic** | Official [anthropics/skills](https://github.com/anthropics/skills) |
131-
| **Community** | Top-rated community skills (GitHub `agent-skill` topic) |
131+
| **Community** | Top-rated community skills (GitHub `agent-skill` and `agent-skills` topics) |
132132
| **Composio** | [ComposioHQ/awesome-claude-skills](https://github.com/ComposioHQ/awesome-claude-skills) collection |
133-
| **MATLAB** | Official [matlab/skills](https://github.com/matlab/skills) |
134133
| **OpenAI** | Official [openai/skills](https://github.com/openai/skills) |
135-
| **Superpowers** | [obra/superpowers](https://github.com/obra/superpowers) core library |
136-
| **SkillHub** | [SkillHub.club](https://www.skillhub.club) |
137134
| **Vercel** | [vercel-labs/agent-skills](https://github.com/vercel-labs/agent-skills) AI SDK skills |
138135

136+
### Optional Repositories
137+
138+
For specific needs, you can add these additional sources:
139+
140+
| Repository | Command to Add | Description |
141+
| :--- | :--- | :--- |
142+
| **SkillHub** | `ask repo add skillhub/skills` | [SkillHub.club](https://www.skillhub.club) index |
143+
| **Scientific** | `ask repo add K-Dense-AI/claude-scientific-skills` | Data science & research skills |
144+
| **MATLAB** | `ask repo add matlab/skills` | Official MATLAB integration |
145+
| **Superpowers** | `ask repo add obra/superpowers` | Full dev workflow with sub-agents |
146+
| **Planning** | `ask repo add OthmanAdi/planning-with-files` | File-based persistent planning |
147+
| **UI/UX Pro** | `ask repo add nextlevelbuilder/ui-ux-pro-max-skill` | 57 UI styles, 95 color schemes |
148+
| **NotebookLM** | `ask repo add PleasePrompto/notebooklm-skill` | Auto-upload to NotebookLM |
149+
| **AI DrawIO** | `ask repo add GBSOSS/ai-drawio` | Flowchart & diagram generation |
150+
| **PPT Skills** | `ask repo add op7418/NanoBanana-PPT-Skills` | Dynamic PPT generation |
151+
139152
## 📂 Installation Layout
140153

141154
Default structure after installation:

README_zh.md

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,13 +131,27 @@ ASK 默认内置了以下受信源:
131131
| 来源 | 说明 |
132132
| :--- | :--- |
133133
| **Anthropic** | 官方库 [anthropics/skills](https://github.com/anthropics/skills) |
134-
| **Community** | GitHub 社区高分技能 (`agent-skill` topic) |
134+
| **Community** | GitHub 社区高分技能 (`agent-skill` `agent-skills` topics) |
135135
| **Composio** | 精选集 [ComposioHQ/awesome-claude-skills](https://github.com/ComposioHQ/awesome-claude-skills) |
136-
| **MATLAB** | 官方库 [matlab/skills](https://github.com/matlab/skills) |
137136
| **OpenAI** | 官方库 [openai/skills](https://github.com/openai/skills) |
138-
| **Superpowers** | 核心库 [obra/superpowers](https://github.com/obra/superpowers) |
139137
| **Vercel** | AI SDK [vercel-labs/agent-skills](https://github.com/vercel-labs/agent-skills) |
140138

139+
### 可选技能仓库
140+
141+
如有特定需求,您可以添加以下额外来源:
142+
143+
| 仓库 | 添加命令 | 说明 |
144+
| :--- | :--- | :--- |
145+
| **SkillHub** | `ask repo add skillhub/skills` | [SkillHub.club](https://www.skillhub.club) 索引 |
146+
| **Scientific** | `ask repo add K-Dense-AI/claude-scientific-skills` | 数据科学与研究技能 |
147+
| **MATLAB** | `ask repo add matlab/skills` | 官方 MATLAB 集成 |
148+
| **Superpowers** | `ask repo add obra/superpowers` | 全链路开发工作流 |
149+
| **Planning** | `ask repo add OthmanAdi/planning-with-files` | 文件持久化规划 |
150+
| **UI/UX Pro** | `ask repo add nextlevelbuilder/ui-ux-pro-max-skill` | 57种UI风格,95种配色 |
151+
| **NotebookLM** | `ask repo add PleasePrompto/notebooklm-skill` | 自动上传到NotebookLM |
152+
| **AI DrawIO** | `ask repo add GBSOSS/ai-drawio` | 流程图自动生成 |
153+
| **PPT Skills** | `ask repo add op7418/NanoBanana-PPT-Skills` | 动态PPT生成 |
154+
141155
## 📂 目录结构
142156

143157
安装后的默认结构:

cmd/repo.go

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import (
99
"text/tabwriter"
1010

1111
"github.com/spf13/cobra"
12+
"github.com/yeasy/ask/internal/cache"
1213
"github.com/yeasy/ask/internal/config"
13-
"github.com/yeasy/ask/internal/github"
1414
"github.com/yeasy/ask/internal/repository"
1515
"github.com/yeasy/ask/internal/ui"
1616
)
@@ -147,6 +147,18 @@ Examples:
147147
return
148148
}
149149

150+
// Load cached star counts
151+
starCache := make(map[string]int)
152+
reposCache, err := cache.NewReposCache()
153+
if err == nil {
154+
repoInfos, err := reposCache.LoadIndex()
155+
if err == nil {
156+
for _, info := range repoInfos {
157+
starCache[info.Name] = info.Stars
158+
}
159+
}
160+
}
161+
150162
fmt.Println("Configured Repositories:")
151163
fmt.Println()
152164
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
@@ -161,15 +173,10 @@ Examples:
161173
stars = "-" // Topics don't have star counts
162174
} else {
163175
fullURL = fmt.Sprintf("https://github.com/%s", r.URL)
164-
// Fetch star count for repo
165-
parts := strings.Split(r.URL, "/")
166-
if len(parts) >= 2 {
167-
repoInfo, err := github.FetchRepoDetails(parts[0], parts[1])
168-
if err == nil && repoInfo != nil {
169-
stars = fmt.Sprintf("%d", repoInfo.StargazersCount)
170-
} else {
171-
stars = "-"
172-
}
176+
// Use cached star count
177+
repoName := buildRepoName(r.URL)
178+
if cachedStars, ok := starCache[repoName]; ok && cachedStars > 0 {
179+
stars = fmt.Sprintf("%d", cachedStars)
173180
} else {
174181
stars = "-"
175182
}
@@ -179,6 +186,7 @@ Examples:
179186
_ = w.Flush()
180187
fmt.Printf("\nTotal: %d repositories\n", len(cfg.Repos))
181188
fmt.Println("\nUse 'ask repo list <name>' to view skills in a repository.")
189+
fmt.Println("Run 'ask repo sync' to update star counts.")
182190
return
183191
}
184192

cmd/root.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ import (
1212
var cfgFile string
1313

1414
// Custom help template with subcommand details at the end
15-
const rootHelpTemplate = `{{with (or .Long .Short)}}{{. | trimTrailingWhitespaces}}
15+
const rootHelpTemplate = `{{with .Version}}ASK v{{.}}
16+
{{end}}{{with (or .Long .Short)}}{{. | trimTrailingWhitespaces}}
1617
1718
{{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}
1819
Skill Commands (ask skill <command>):
@@ -37,16 +38,15 @@ Supported Agents: Claude, Cursor, Codex, OpenCode, Antigravity, Gemini CLI, GitH
3738
// rootCmd represents the base command when called without any subcommands
3839
var rootCmd = &cobra.Command{
3940
Use: "ask",
40-
Short: "Agent Skills Kit - The Package Manager for Agent Skills",
41-
Long: `ASK (Agent Skills Kit) is a CLI tool designed to help you discover,
42-
install, and manage skills for your AI Agents.
41+
Short: "The package manager for AI Agent skills",
42+
Long: `The package manager for AI Agent skills.
4343
44-
It works similarly to package managers like Homebrew or npm, but specified for
45-
the Agent ecosystem.`,
44+
Discover, install, and manage capabilities for your AI Agents (Claude, Cursor,
45+
Codex, etc.) with a familiar CLI experience, just like Homebrew or npm.`,
4646
// Uncomment the following line if your bare application
4747
// has an action associated with it:
4848
// Run: func(cmd *cobra.Command, args []string) { },
49-
Version: "0.9.3",
49+
Version: "0.9.5",
5050
}
5151

5252
// Execute adds all child commands to the root command and sets flags appropriately.

cmd/search.go

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ Use --remote to force remote API search.`,
3939

4040
forceLocal, _ := cmd.Flags().GetBool("local")
4141
forceRemote, _ := cmd.Flags().GetBool("remote")
42+
minStars, _ := cmd.Flags().GetInt("min-stars")
4243

4344
// Load config or use default
4445
cfg, err := config.LoadConfig()
@@ -80,7 +81,7 @@ Use --remote to force remote API search.`,
8081

8182
if len(allRepos) > 0 || forceLocal {
8283
// Display results from local cache
83-
displaySearchResults(allRepos, installedSkills, searchSource)
84+
displaySearchResults(allRepos, installedSkills, searchSource, minStars)
8485
if forceLocal && len(allRepos) == 0 {
8586
fmt.Println("\nTip: Run 'ask repo sync' to populate local cache.")
8687
}
@@ -117,10 +118,13 @@ Use --remote to force remote API search.`,
117118
repos, err = github.SearchTopic(r.URL, keyword)
118119
case "dir":
119120
parts := strings.Split(r.URL, "/")
120-
if len(parts) >= 3 {
121+
if len(parts) >= 2 {
121122
owner := parts[0]
122123
repoName := parts[1]
123-
path := strings.Join(parts[2:], "/")
124+
path := ""
125+
if len(parts) > 2 {
126+
path = strings.Join(parts[2:], "/")
127+
}
124128
repos, err = github.SearchDir(owner, repoName, path)
125129

126130
// Filter client-side by keyword
@@ -166,14 +170,31 @@ Use --remote to force remote API search.`,
166170
fmt.Println()
167171
}
168172

169-
displaySearchResults(allRepos, installedSkills, searchSource)
173+
// Filter by min-stars if specified
174+
if minStars > 0 {
175+
// Filtering is handled in displaySearchResults to ensure consistent counting
176+
}
177+
178+
displaySearchResults(allRepos, installedSkills, searchSource, minStars)
170179
},
171180
}
172181

173-
func displaySearchResults(repos []github.Repository, installedSkills map[string]bool, source string) {
182+
func displaySearchResults(repos []github.Repository, installedSkills map[string]bool, source string, minStars int) {
183+
// Filter repos if minStars > 0
184+
var displayRepos []github.Repository
185+
if minStars > 0 {
186+
for _, repo := range repos {
187+
if repo.StargazersCount >= minStars {
188+
displayRepos = append(displayRepos, repo)
189+
}
190+
}
191+
} else {
192+
displayRepos = repos
193+
}
194+
174195
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
175196
_, _ = fmt.Fprintln(w, "NAME\tSOURCE\tINSTALLED\tSTARS\tDESCRIPTION")
176-
for _, repo := range repos {
197+
for _, repo := range displayRepos {
177198
// Truncate description if too long
178199
desc := repo.Description
179200
if len(desc) > 40 {
@@ -186,7 +207,7 @@ func displaySearchResults(repos []github.Repository, installedSkills map[string]
186207
installed = "✓"
187208
}
188209

189-
// Format stars (use "-" for local or dir-based)
210+
// Format stars (use "-" for local or dir-based if actually 0, but dir-based now have stars)
190211
stars := fmt.Sprintf("%d", repo.StargazersCount)
191212
if repo.StargazersCount == 0 {
192213
stars = "-"
@@ -196,7 +217,12 @@ func displaySearchResults(repos []github.Repository, installedSkills map[string]
196217
}
197218
_ = w.Flush()
198219

199-
fmt.Printf("\nFound %d skills.\n", len(repos))
220+
fmt.Printf("\nFound %d skills", len(displayRepos))
221+
if minStars > 0 {
222+
fmt.Printf(" (filtered from %d results by stars >= %d)", len(repos), minStars)
223+
}
224+
fmt.Println(".")
225+
200226
if source == "local" {
201227
fmt.Println("(from local cache - run 'ask repo sync' to update)")
202228
}
@@ -206,4 +232,5 @@ func init() {
206232
skillCmd.AddCommand(searchCmd)
207233
searchCmd.Flags().Bool("local", false, "search only local cache (offline)")
208234
searchCmd.Flags().Bool("remote", false, "force remote API search")
235+
searchCmd.Flags().Int("min-stars", 0, "filter skills by minimum integer number of GitHub stars")
209236
}

cmd/sync.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/spf13/cobra"
99
"github.com/yeasy/ask/internal/cache"
1010
"github.com/yeasy/ask/internal/config"
11+
"github.com/yeasy/ask/internal/github"
1112
)
1213

1314
// syncCmd represents the sync command
@@ -71,6 +72,7 @@ If no repo name is specified, syncs all configured repositories.`,
7172
fmt.Printf("Syncing %d repositories to ~/.ask/repos/...\n\n", len(targetRepos))
7273

7374
successCount := 0
75+
starCounts := make(map[string]int)
7476
for _, repo := range targetRepos {
7577
repoURL := buildRepoURL(repo.URL)
7678
repoName := buildRepoName(repo.URL)
@@ -81,13 +83,22 @@ If no repo name is specified, syncs all configured repositories.`,
8183
} else {
8284
fmt.Printf(" ✓ Synced %s\n", repo.Name)
8385
successCount++
86+
87+
// Fetch star count from GitHub API
88+
parts := strings.Split(repo.URL, "/")
89+
if len(parts) >= 2 {
90+
repoDetails, err := github.FetchRepoDetails(parts[0], parts[1])
91+
if err == nil {
92+
starCounts[repoName] = repoDetails.StargazersCount
93+
}
94+
}
8495
}
8596
}
8697

8798
fmt.Printf("\nSynced %d/%d repositories.\n", successCount, len(targetRepos))
8899

89-
// Save index
90-
if err := reposCache.SaveIndex(); err != nil {
100+
// Save index with star counts
101+
if err := reposCache.SaveIndexWithStars(starCounts); err != nil {
91102
fmt.Printf("Warning: Failed to save index: %v\n", err)
92103
}
93104

cmd/version.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/spf13/cobra"
7+
)
8+
9+
var versionCmd = &cobra.Command{
10+
Use: "version",
11+
Short: "Print the version number of ask",
12+
Long: `All software has versions. This is ask's`,
13+
Run: func(cmd *cobra.Command, args []string) {
14+
fmt.Printf("ask version %s\n", rootCmd.Version)
15+
},
16+
}
17+
18+
func init() {
19+
rootCmd.AddCommand(versionCmd)
20+
}

internal/cache/repos.go

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ type RepoInfo struct {
2121
URL string `json:"url"`
2222
LocalPath string `json:"local_path"`
2323
UpdatedAt time.Time `json:"updated_at"`
24+
Stars int `json:"stars"`
2425
}
2526

2627
// SkillEntry represents a skill found in local cache
@@ -205,19 +206,45 @@ func extractDescription(skillMDPath string) string {
205206
return ""
206207
}
207208

208-
// SaveIndex saves the current repo index to disk
209+
// SaveIndex saves the current repo index to disk (without stars)
209210
func (c *ReposCache) SaveIndex() error {
211+
return c.SaveIndexWithStars(nil)
212+
}
213+
214+
// SaveIndexWithStars saves the current repo index to disk with star counts
215+
func (c *ReposCache) SaveIndexWithStars(starCounts map[string]int) error {
210216
indexPath := filepath.Join(c.baseDir, "index.json")
211217
repos := c.GetCachedRepos()
212218

219+
// Load existing index to preserve stars for repos not synced in this run
220+
existingStars := make(map[string]int)
221+
existingInfos, _ := c.LoadIndex()
222+
for _, info := range existingInfos {
223+
existingStars[info.Name] = info.Stars
224+
}
225+
213226
var repoInfos []RepoInfo
214227
for _, repo := range repos {
215228
repoPath := filepath.Join(c.baseDir, repo)
216229
info, _ := os.Stat(repoPath)
230+
231+
// Use new star count if provided, otherwise use existing
232+
stars := 0
233+
if starCounts != nil {
234+
if count, ok := starCounts[repo]; ok {
235+
stars = count
236+
} else if existingCount, ok := existingStars[repo]; ok {
237+
stars = existingCount
238+
}
239+
} else if existingCount, ok := existingStars[repo]; ok {
240+
stars = existingCount
241+
}
242+
217243
repoInfos = append(repoInfos, RepoInfo{
218244
Name: repo,
219245
LocalPath: repoPath,
220246
UpdatedAt: info.ModTime(),
247+
Stars: stars,
221248
})
222249
}
223250

@@ -227,3 +254,17 @@ func (c *ReposCache) SaveIndex() error {
227254
}
228255
return os.WriteFile(indexPath, data, 0644)
229256
}
257+
258+
// LoadIndex loads the repo index from disk
259+
func (c *ReposCache) LoadIndex() ([]RepoInfo, error) {
260+
indexPath := filepath.Join(c.baseDir, "index.json")
261+
data, err := os.ReadFile(indexPath)
262+
if err != nil {
263+
return nil, err
264+
}
265+
var repoInfos []RepoInfo
266+
if err := json.Unmarshal(data, &repoInfos); err != nil {
267+
return nil, err
268+
}
269+
return repoInfos, nil
270+
}

0 commit comments

Comments
 (0)