itismyskillmarket 1.2.6 → 1.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +112 -0
- package/dist/index.js +52 -13
- package/docs/plans/2026-04-16-keyword-search-design.md +143 -0
- package/package.json +1 -1
- package/src/cli.ts +4 -1
- package/src/commands/ls.ts +66 -10
- package/src/commands/npm.ts +11 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,115 @@
|
|
|
1
|
+
# SkillMarket v1.2.6 更新日志
|
|
2
|
+
|
|
3
|
+
**日期**: 2026-04-22
|
|
4
|
+
**版本**: 1.2.6
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 🔍 新功能:skm ls 搜索支持
|
|
9
|
+
|
|
10
|
+
### 功能说明
|
|
11
|
+
|
|
12
|
+
新增搜索功能,可以通过关键字搜索 skills。
|
|
13
|
+
|
|
14
|
+
### 新增选项
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# 搜索 npm 上的 skills
|
|
18
|
+
skm ls --search brain
|
|
19
|
+
skm ls -s brain
|
|
20
|
+
|
|
21
|
+
# 搜索已安装的 skills
|
|
22
|
+
skm ls --installed --search test
|
|
23
|
+
|
|
24
|
+
# 组合分页和搜索
|
|
25
|
+
skm ls --search brain --page 1 --limit 10
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### 搜索字段
|
|
29
|
+
|
|
30
|
+
- skill ID
|
|
31
|
+
- displayName(显示名称)
|
|
32
|
+
- description(描述)
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## 🎉 新功能:skm ls 分页支持
|
|
37
|
+
|
|
38
|
+
### 功能说明
|
|
39
|
+
|
|
40
|
+
当 skill 数量较多时,现在支持分页浏览。
|
|
41
|
+
|
|
42
|
+
### 新增选项
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# 默认每页 20 个
|
|
46
|
+
skm ls
|
|
47
|
+
|
|
48
|
+
# 指定页码
|
|
49
|
+
skm ls --page 2
|
|
50
|
+
|
|
51
|
+
# 指定每页数量
|
|
52
|
+
skm ls --limit 10
|
|
53
|
+
|
|
54
|
+
# 组合使用
|
|
55
|
+
skm ls --page 2 --limit 10
|
|
56
|
+
|
|
57
|
+
# 已安装的 skills 也支持分页
|
|
58
|
+
skm ls --installed --page 2
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 输出示例
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
Found 85 skill(s):
|
|
65
|
+
|
|
66
|
+
📦 @skillmarket/brainstorming@1.2.0
|
|
67
|
+
名称: Brainstorming
|
|
68
|
+
描述: Feature brainstorming skill
|
|
69
|
+
平台: opencode, cursor, vscode, claude
|
|
70
|
+
链接: https://www.npmjs.com/package/@skillmarket/brainstorming
|
|
71
|
+
|
|
72
|
+
Page 1/5 (20 per page) | Use --page N to navigate
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 实现细节
|
|
76
|
+
|
|
77
|
+
- npm search API 使用 `from` 和 `size` 参数实现服务端分页
|
|
78
|
+
- 本地已安装 skills 使用数组 slice 实现客户端分页
|
|
79
|
+
- 默认每页 20 个,可自定义
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## 🔧 改进
|
|
84
|
+
|
|
85
|
+
1. **文档更新**
|
|
86
|
+
- 更新 README.md 添加分页使用示例
|
|
87
|
+
- 更新 SKILLMARKET-GUIDE.md 修复安装命令
|
|
88
|
+
- 更新 skills/README.md 添加 test-skill-1/2
|
|
89
|
+
|
|
90
|
+
2. **版本管理优化**
|
|
91
|
+
- 版本号现在从 `package.json` 动态读取
|
|
92
|
+
- 不再需要手动同步版本号
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## 📦 完整版本历史
|
|
97
|
+
|
|
98
|
+
| 版本 | 日期 | 描述 |
|
|
99
|
+
|------|------|------|
|
|
100
|
+
| 1.2.6 | 2026-04-16 | 修复版本号动态读取 |
|
|
101
|
+
| 1.2.5 | 2026-04-16 | 文档更新 |
|
|
102
|
+
| 1.2.4 | 2026-04-16 | 修复版本号硬编码问题 |
|
|
103
|
+
| 1.2.3 | 2026-04-15 | 跨平台 Skill 安装支持 |
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## 贡献者
|
|
108
|
+
|
|
109
|
+
- wxc2004 (wanxuchen)
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
1
113
|
# SkillMarket v1.2.3 发布总结
|
|
2
114
|
|
|
3
115
|
**日期**: 2026-04-15
|
package/dist/index.js
CHANGED
|
@@ -174,12 +174,16 @@ async function fetchSkillPackage(skillId) {
|
|
|
174
174
|
return null;
|
|
175
175
|
}
|
|
176
176
|
async function searchSkillmarketPackages(options = {}) {
|
|
177
|
-
const { from = 0, size = 100 } = options;
|
|
177
|
+
const { from = 0, size = 100, keyword } = options;
|
|
178
178
|
const packages = [];
|
|
179
179
|
let total = 0;
|
|
180
180
|
return new Promise((resolve2, reject) => {
|
|
181
181
|
const url = new URL("https://registry.npmjs.org/-/v1/search");
|
|
182
|
-
|
|
182
|
+
if (keyword) {
|
|
183
|
+
url.searchParams.set("text", `${keyword} keywords:skillmarket`);
|
|
184
|
+
} else {
|
|
185
|
+
url.searchParams.set("text", "keywords:skillmarket");
|
|
186
|
+
}
|
|
183
187
|
url.searchParams.set("size", String(size));
|
|
184
188
|
url.searchParams.set("from", String(from));
|
|
185
189
|
const req = https.get(url.toString(), { timeout: 1e4 }, (res) => {
|
|
@@ -213,22 +217,40 @@ async function searchSkillmarketPackages(options = {}) {
|
|
|
213
217
|
}
|
|
214
218
|
|
|
215
219
|
// src/commands/ls.ts
|
|
220
|
+
function filterInstalledSkills(skills, keyword) {
|
|
221
|
+
const lower = keyword.toLowerCase();
|
|
222
|
+
return skills.filter(
|
|
223
|
+
(s) => s.id.toLowerCase().includes(lower) || s.displayName && s.displayName.toLowerCase().includes(lower) || s.description && s.description.toLowerCase().includes(lower)
|
|
224
|
+
);
|
|
225
|
+
}
|
|
216
226
|
async function listSkills(options) {
|
|
217
|
-
const { installed, updates, page = 1, limit = 20 } = options;
|
|
227
|
+
const { installed, updates, page = 1, limit = 20, search } = options;
|
|
218
228
|
if (installed) {
|
|
219
|
-
|
|
229
|
+
let skills = await getInstalledSkills();
|
|
230
|
+
if (search) {
|
|
231
|
+
skills = filterInstalledSkills(skills, search);
|
|
232
|
+
}
|
|
220
233
|
const total = skills.length;
|
|
221
234
|
const totalPages = Math.ceil(total / limit) || 1;
|
|
222
235
|
const currentPage = Math.min(Math.max(1, page), totalPages);
|
|
223
236
|
if (skills.length === 0) {
|
|
224
|
-
|
|
237
|
+
if (search) {
|
|
238
|
+
console.log(`No skills found matching "${search}".`);
|
|
239
|
+
} else {
|
|
240
|
+
console.log('No skills installed yet. Run "skm ls" to see available skills.');
|
|
241
|
+
}
|
|
225
242
|
return;
|
|
226
243
|
}
|
|
244
|
+
if (search) {
|
|
245
|
+
console.log(`Found ${total} match(es) for "${search}":
|
|
246
|
+
`);
|
|
247
|
+
} else {
|
|
248
|
+
console.log(`Installed Skills (${total}):
|
|
249
|
+
`);
|
|
250
|
+
}
|
|
227
251
|
const start = (currentPage - 1) * limit;
|
|
228
252
|
const end = Math.min(start + limit, total);
|
|
229
253
|
const pageSkills = skills.slice(start, end);
|
|
230
|
-
console.log(`Installed Skills (${total}):
|
|
231
|
-
`);
|
|
232
254
|
for (const skill of pageSkills) {
|
|
233
255
|
console.log(` ${skill.id}@${skill.version}`);
|
|
234
256
|
console.log(` Platforms: ${skill.platforms.join(", ")}`);
|
|
@@ -238,21 +260,36 @@ async function listSkills(options) {
|
|
|
238
260
|
console.log(`Page ${currentPage}/${totalPages} (${limit} per page) | Use --page N to navigate`);
|
|
239
261
|
return;
|
|
240
262
|
}
|
|
241
|
-
|
|
263
|
+
if (search) {
|
|
264
|
+
console.log(`Searching npm for "${search}"...
|
|
265
|
+
`);
|
|
266
|
+
} else {
|
|
267
|
+
console.log("Searching npm registry...\n");
|
|
268
|
+
}
|
|
242
269
|
try {
|
|
243
270
|
const offset = (page - 1) * limit;
|
|
244
271
|
const { packages, total } = await searchSkillmarketPackages({
|
|
245
272
|
from: offset,
|
|
246
|
-
size: limit
|
|
273
|
+
size: limit,
|
|
274
|
+
keyword: search
|
|
247
275
|
});
|
|
248
276
|
const totalPages = Math.ceil(total / limit) || 1;
|
|
249
277
|
const currentPage = Math.min(Math.max(1, page), totalPages);
|
|
250
278
|
if (packages.length === 0) {
|
|
251
|
-
|
|
279
|
+
if (search) {
|
|
280
|
+
console.log(`No skills found matching "${search}".`);
|
|
281
|
+
} else {
|
|
282
|
+
console.log("No skills found. Check back later!");
|
|
283
|
+
}
|
|
252
284
|
return;
|
|
253
285
|
}
|
|
254
|
-
|
|
286
|
+
if (search) {
|
|
287
|
+
console.log(`Found ${total} match(es) for "${search}":
|
|
288
|
+
`);
|
|
289
|
+
} else {
|
|
290
|
+
console.log(`Found ${total} skill(s):
|
|
255
291
|
`);
|
|
292
|
+
}
|
|
256
293
|
for (const pkgName of packages) {
|
|
257
294
|
try {
|
|
258
295
|
const info = await fetchNpmPackage(pkgName);
|
|
@@ -774,6 +811,7 @@ Commands:
|
|
|
774
811
|
--updates Check for updates
|
|
775
812
|
--page <n> Page number (default: 1)
|
|
776
813
|
--limit <n> Items per page (default: 20)
|
|
814
|
+
-s, --search Search by keyword
|
|
777
815
|
info <skill-id> Display skill information
|
|
778
816
|
install <skill> Install a skill
|
|
779
817
|
@version Install specific version
|
|
@@ -803,11 +841,12 @@ Examples:
|
|
|
803
841
|
}
|
|
804
842
|
});
|
|
805
843
|
var lsCmd = program.command("ls").description("List available skills");
|
|
806
|
-
lsCmd.option("--installed", "Show only installed skills").option("--updates", "Check for updates").option("-p, --page <number>", "Page number (default: 1)", parseInt).option("-l, --limit <number>", "Items per page (default: 20)", parseInt).action((opts) => {
|
|
844
|
+
lsCmd.option("--installed", "Show only installed skills").option("--updates", "Check for updates").option("-p, --page <number>", "Page number (default: 1)", parseInt).option("-l, --limit <number>", "Items per page (default: 20)", parseInt).option("-s, --search <keyword>", "Search by keyword (id, displayName, description)").action((opts) => {
|
|
807
845
|
const options = {
|
|
808
846
|
...opts,
|
|
809
847
|
page: opts.page ?? 1,
|
|
810
|
-
limit: opts.limit ?? 20
|
|
848
|
+
limit: opts.limit ?? 20,
|
|
849
|
+
search: opts.search
|
|
811
850
|
};
|
|
812
851
|
listSkills(options);
|
|
813
852
|
});
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# SkillMarket 关键字搜索功能设计方案
|
|
2
|
+
|
|
3
|
+
**版本**: 1.0
|
|
4
|
+
**日期**: 2026-04-16
|
|
5
|
+
**状态**: 待开发
|
|
6
|
+
|
|
7
|
+
## 1. 功能概述
|
|
8
|
+
|
|
9
|
+
为 SkillMarket CLI 添加关键字搜索功能,支持在 npm registry 和本地已安装 skills 中按关键字检索。
|
|
10
|
+
|
|
11
|
+
## 2. 推荐方案
|
|
12
|
+
|
|
13
|
+
### 2.1 新增命令
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# 搜索 npm registry(默认行为,与现有 skm ls 等效但带过滤)
|
|
17
|
+
skm search <keyword>
|
|
18
|
+
|
|
19
|
+
# 搜索本地已安装的 skills
|
|
20
|
+
skm search <keyword> --installed
|
|
21
|
+
|
|
22
|
+
# 组合:分页 + 搜索关键字
|
|
23
|
+
skm search <keyword> --page 1 --limit 20
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### 2.2 搜索字段
|
|
27
|
+
|
|
28
|
+
支持匹配以下字段:
|
|
29
|
+
- `id`: skill 包名(精确匹配 + 模糊匹配)
|
|
30
|
+
- `displayName`: 显示名称
|
|
31
|
+
- `description`: 描述
|
|
32
|
+
|
|
33
|
+
### 2.3 实现方式
|
|
34
|
+
|
|
35
|
+
复用现有 `skm ls` 命令,添加 `--search` / `-s` 选项:
|
|
36
|
+
|
|
37
|
+
| 命令 | 说明 |
|
|
38
|
+
|------|------|
|
|
39
|
+
| `skm ls --search <keyword>` | 在 npm registry 中搜索 |
|
|
40
|
+
| `skm ls --search <keyword> --installed` | 在本地已安装 skills 中搜索 |
|
|
41
|
+
| `skm ls -s <keyword>` | 简写形式 |
|
|
42
|
+
|
|
43
|
+
**推荐**:将搜索功能作为 `skm ls` 的选项,而不是新增独立命令。原因:
|
|
44
|
+
- 代码复用度高
|
|
45
|
+
- 用户学习成本低
|
|
46
|
+
- 与分页功能自然组合
|
|
47
|
+
|
|
48
|
+
## 3. 技术方案
|
|
49
|
+
|
|
50
|
+
### 3.1 代码修改
|
|
51
|
+
|
|
52
|
+
**文件**: `src/commands/ls.ts`
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
interface LsOptions {
|
|
56
|
+
// ... 现有字段
|
|
57
|
+
search?: string; // 新增:搜索关键字
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 3.2 npm search 实现
|
|
62
|
+
|
|
63
|
+
修改 `searchSkillmarketPackages` 函数,添加关键字过滤参数:
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
interface SearchOptions {
|
|
67
|
+
from: number;
|
|
68
|
+
size: number;
|
|
69
|
+
keyword?: string; // 新增
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**注意**:npm search API 本身支持通过 `q` 参数进行关键字搜索,可以直接传入。
|
|
74
|
+
|
|
75
|
+
### 3.3 本地搜索实现
|
|
76
|
+
|
|
77
|
+
在已有本地 skills 列表上进行内存过滤:
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
function filterInstalledSkills(skills: InstalledSkill[], keyword: string): InstalledSkill[] {
|
|
81
|
+
const lower = keyword.toLowerCase();
|
|
82
|
+
return skills.filter(s =>
|
|
83
|
+
s.id.toLowerCase().includes(lower) ||
|
|
84
|
+
s.displayName?.toLowerCase().includes(lower) ||
|
|
85
|
+
s.description?.toLowerCase().includes(lower)
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### 3.4 UI 输出
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
# npm 搜索结果
|
|
94
|
+
$ skm ls -s "brainstorm"
|
|
95
|
+
|
|
96
|
+
📦 brainstorming@1.0.0 (Found 1 match for "brainstorm")
|
|
97
|
+
名称: Brainstorming
|
|
98
|
+
描述: 多智能体头脑风暴能力
|
|
99
|
+
平台: opencode
|
|
100
|
+
链接: https://npmjs.com/package/brainstorming
|
|
101
|
+
|
|
102
|
+
# 本地搜索结果
|
|
103
|
+
$ skm ls --installed -s "test"
|
|
104
|
+
|
|
105
|
+
🟢 test-skill-1@1.0.0
|
|
106
|
+
Platforms: opencode
|
|
107
|
+
Installed: 2026-04-16
|
|
108
|
+
|
|
109
|
+
🟢 test-skill-2@1.0.0
|
|
110
|
+
Platforms: opencode
|
|
111
|
+
Installed: 2026-04-15
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## 4. 实施步骤
|
|
115
|
+
|
|
116
|
+
1. **修改 `ls.ts` 命令模块**
|
|
117
|
+
- 添加 `search` 选项到 `LsOptions` 接口
|
|
118
|
+
- 实现关键字过滤逻辑
|
|
119
|
+
- 支持 npm search API 和本地过滤
|
|
120
|
+
|
|
121
|
+
2. **修改 `cli.ts`**
|
|
122
|
+
- 在 `ls` 命令中添加 `--search` / `-s` 选项
|
|
123
|
+
|
|
124
|
+
3. **测试**
|
|
125
|
+
- `skm ls -s <keyword>`
|
|
126
|
+
- `skm ls --installed -s <keyword>`
|
|
127
|
+
- 边界情况:无结果、分页
|
|
128
|
+
|
|
129
|
+
## 5. 优先级
|
|
130
|
+
|
|
131
|
+
**P1 - 高**
|
|
132
|
+
- 核心搜索功能
|
|
133
|
+
- npm registry 搜索
|
|
134
|
+
|
|
135
|
+
**P2 - 中**
|
|
136
|
+
- 本地已安装 skills 搜索
|
|
137
|
+
- 搜索结果高亮(可选)
|
|
138
|
+
|
|
139
|
+
## 6. 风险与注意事项
|
|
140
|
+
|
|
141
|
+
- npm search API 有速率限制,生产环境考虑缓存
|
|
142
|
+
- 中文关键字搜索需要确认 npm API 支持
|
|
143
|
+
- 大结果集需要分页处理
|
package/package.json
CHANGED
package/src/cli.ts
CHANGED
|
@@ -99,6 +99,7 @@ Commands:
|
|
|
99
99
|
--updates Check for updates
|
|
100
100
|
--page <n> Page number (default: 1)
|
|
101
101
|
--limit <n> Items per page (default: 20)
|
|
102
|
+
-s, --search Search by keyword
|
|
102
103
|
info <skill-id> Display skill information
|
|
103
104
|
install <skill> Install a skill
|
|
104
105
|
@version Install specific version
|
|
@@ -148,12 +149,14 @@ lsCmd
|
|
|
148
149
|
.option('--updates', 'Check for updates')
|
|
149
150
|
.option('-p, --page <number>', 'Page number (default: 1)', parseInt)
|
|
150
151
|
.option('-l, --limit <number>', 'Items per page (default: 20)', parseInt)
|
|
152
|
+
.option('-s, --search <keyword>', 'Search by keyword (id, displayName, description)')
|
|
151
153
|
.action((opts) => {
|
|
152
154
|
// Ensure numeric options have default values if not provided
|
|
153
155
|
const options = {
|
|
154
156
|
...opts,
|
|
155
157
|
page: opts.page ?? 1,
|
|
156
|
-
limit: opts.limit ?? 20
|
|
158
|
+
limit: opts.limit ?? 20,
|
|
159
|
+
search: opts.search
|
|
157
160
|
};
|
|
158
161
|
listSkills(options);
|
|
159
162
|
});
|
package/src/commands/ls.ts
CHANGED
|
@@ -43,6 +43,9 @@ interface LsOptions {
|
|
|
43
43
|
|
|
44
44
|
/** 每页数量 */
|
|
45
45
|
limit?: number;
|
|
46
|
+
|
|
47
|
+
/** 搜索关键字(支持 id, displayName, description) */
|
|
48
|
+
search?: string;
|
|
46
49
|
}
|
|
47
50
|
|
|
48
51
|
// -----------------------------------------------------------------------------
|
|
@@ -65,32 +68,72 @@ interface LsOptions {
|
|
|
65
68
|
* // 列出已安装的 skills
|
|
66
69
|
* await listSkills({ installed: true });
|
|
67
70
|
*/
|
|
71
|
+
// -----------------------------------------------------------------------------
|
|
72
|
+
// 搜索过滤函数
|
|
73
|
+
// -----------------------------------------------------------------------------
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* 过滤已安装的 skills(按关键字)
|
|
77
|
+
*
|
|
78
|
+
* 匹配 id, displayName, description 字段
|
|
79
|
+
*
|
|
80
|
+
* @param skills - 已安装的 skills 列表
|
|
81
|
+
* @param keyword - 搜索关键字
|
|
82
|
+
* @returns 过滤后的 skills 列表
|
|
83
|
+
*/
|
|
84
|
+
function filterInstalledSkills(skills: any[], keyword: string): any[] {
|
|
85
|
+
const lower = keyword.toLowerCase();
|
|
86
|
+
return skills.filter(s =>
|
|
87
|
+
s.id.toLowerCase().includes(lower) ||
|
|
88
|
+
(s.displayName && s.displayName.toLowerCase().includes(lower)) ||
|
|
89
|
+
(s.description && s.description.toLowerCase().includes(lower))
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// -----------------------------------------------------------------------------
|
|
94
|
+
// 命令实现
|
|
95
|
+
// -----------------------------------------------------------------------------
|
|
96
|
+
|
|
68
97
|
export async function listSkills(options: LsOptions): Promise<void> {
|
|
69
|
-
const { installed, updates, page = 1, limit = 20 } = options;
|
|
98
|
+
const { installed, updates, page = 1, limit = 20, search } = options;
|
|
70
99
|
|
|
71
100
|
// -------------------------------------------------------------------------
|
|
72
101
|
// 模式1: 显示已安装的 skills
|
|
73
102
|
// -------------------------------------------------------------------------
|
|
74
103
|
if (installed) {
|
|
75
|
-
|
|
104
|
+
let skills = await getInstalledSkills();
|
|
105
|
+
|
|
106
|
+
// 搜索关键字过滤(仅本地)
|
|
107
|
+
if (search) {
|
|
108
|
+
skills = filterInstalledSkills(skills, search);
|
|
109
|
+
}
|
|
110
|
+
|
|
76
111
|
const total = skills.length;
|
|
77
112
|
const totalPages = Math.ceil(total / limit) || 1;
|
|
78
113
|
const currentPage = Math.min(Math.max(1, page), totalPages);
|
|
79
114
|
|
|
80
115
|
// 无已安装 skills 时给出提示
|
|
81
116
|
if (skills.length === 0) {
|
|
82
|
-
|
|
117
|
+
if (search) {
|
|
118
|
+
console.log(`No skills found matching "${search}".`);
|
|
119
|
+
} else {
|
|
120
|
+
console.log('No skills installed yet. Run "skm ls" to see available skills.');
|
|
121
|
+
}
|
|
83
122
|
return;
|
|
84
123
|
}
|
|
85
124
|
|
|
125
|
+
// 搜索结果提示
|
|
126
|
+
if (search) {
|
|
127
|
+
console.log(`Found ${total} match(es) for "${search}":\n`);
|
|
128
|
+
} else {
|
|
129
|
+
console.log(`Installed Skills (${total}):\n`);
|
|
130
|
+
}
|
|
131
|
+
|
|
86
132
|
// 计算分页范围
|
|
87
133
|
const start = (currentPage - 1) * limit;
|
|
88
134
|
const end = Math.min(start + limit, total);
|
|
89
135
|
const pageSkills = skills.slice(start, end);
|
|
90
136
|
|
|
91
|
-
// 打印表头
|
|
92
|
-
console.log(`Installed Skills (${total}):\n`);
|
|
93
|
-
|
|
94
137
|
// 遍历并打印每个 skill 的详细信息
|
|
95
138
|
for (const skill of pageSkills) {
|
|
96
139
|
// skill 名称和版本
|
|
@@ -117,7 +160,11 @@ export async function listSkills(options: LsOptions): Promise<void> {
|
|
|
117
160
|
// -------------------------------------------------------------------------
|
|
118
161
|
|
|
119
162
|
// 提示用户正在搜索
|
|
120
|
-
|
|
163
|
+
if (search) {
|
|
164
|
+
console.log(`Searching npm for "${search}"...\n`);
|
|
165
|
+
} else {
|
|
166
|
+
console.log('Searching npm registry...\n');
|
|
167
|
+
}
|
|
121
168
|
|
|
122
169
|
try {
|
|
123
170
|
// 计算分页偏移量
|
|
@@ -126,7 +173,8 @@ export async function listSkills(options: LsOptions): Promise<void> {
|
|
|
126
173
|
// 调用 npm search API 搜索 skillmarket 相关包
|
|
127
174
|
const { packages, total } = await searchSkillmarketPackages({
|
|
128
175
|
from: offset,
|
|
129
|
-
size: limit
|
|
176
|
+
size: limit,
|
|
177
|
+
keyword: search
|
|
130
178
|
});
|
|
131
179
|
|
|
132
180
|
const totalPages = Math.ceil(total / limit) || 1;
|
|
@@ -134,12 +182,20 @@ export async function listSkills(options: LsOptions): Promise<void> {
|
|
|
134
182
|
|
|
135
183
|
// 无搜索结果时
|
|
136
184
|
if (packages.length === 0) {
|
|
137
|
-
|
|
185
|
+
if (search) {
|
|
186
|
+
console.log(`No skills found matching "${search}".`);
|
|
187
|
+
} else {
|
|
188
|
+
console.log('No skills found. Check back later!');
|
|
189
|
+
}
|
|
138
190
|
return;
|
|
139
191
|
}
|
|
140
192
|
|
|
141
193
|
// 打印找到的包数量
|
|
142
|
-
|
|
194
|
+
if (search) {
|
|
195
|
+
console.log(`Found ${total} match(es) for "${search}":\n`);
|
|
196
|
+
} else {
|
|
197
|
+
console.log(`Found ${total} skill(s):\n`);
|
|
198
|
+
}
|
|
143
199
|
|
|
144
200
|
// 遍历每个包,获取详细信息并显示
|
|
145
201
|
for (const pkgName of packages) {
|
package/src/commands/npm.ts
CHANGED
|
@@ -265,8 +265,9 @@ export async function fetchSkillPackage(skillId: string): Promise<NpmRegistryRes
|
|
|
265
265
|
export async function searchSkillmarketPackages(options: {
|
|
266
266
|
from?: number;
|
|
267
267
|
size?: number;
|
|
268
|
+
keyword?: string;
|
|
268
269
|
} = {}): Promise<{ packages: string[]; total: number }> {
|
|
269
|
-
const { from = 0, size = 100 } = options;
|
|
270
|
+
const { from = 0, size = 100, keyword } = options;
|
|
270
271
|
const packages: string[] = [];
|
|
271
272
|
let total = 0;
|
|
272
273
|
|
|
@@ -278,7 +279,15 @@ export async function searchSkillmarketPackages(options: {
|
|
|
278
279
|
// text: 搜索关键字
|
|
279
280
|
// size: 返回结果数量上限
|
|
280
281
|
// from: 起始位置(分页用)
|
|
281
|
-
|
|
282
|
+
// 如果有关键字,组合搜索条件
|
|
283
|
+
if (keyword) {
|
|
284
|
+
// 组合搜索:keywords:skillmarket AND 关键字
|
|
285
|
+
// 注意:npm search 不直接支持 AND,这里用多个 text 参数
|
|
286
|
+
// 或者直接在 text 中组合
|
|
287
|
+
url.searchParams.set('text', `${keyword} keywords:skillmarket`);
|
|
288
|
+
} else {
|
|
289
|
+
url.searchParams.set('text', 'keywords:skillmarket');
|
|
290
|
+
}
|
|
282
291
|
url.searchParams.set('size', String(size));
|
|
283
292
|
url.searchParams.set('from', String(from));
|
|
284
293
|
|