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 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
- url.searchParams.set("text", "keywords:skillmarket");
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
- const skills = await getInstalledSkills();
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
- console.log('No skills installed yet. Run "skm ls" to see available skills.');
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
- console.log("Searching npm registry...\n");
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
- console.log("No skills found. Check back later!");
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
- console.log(`Found ${total} skill(s):
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "itismyskillmarket",
3
- "version": "1.2.6",
3
+ "version": "1.2.7",
4
4
  "description": "Cross-platform skill manager for AI coding tools",
5
5
  "type": "module",
6
6
  "bin": {
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
  });
@@ -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
- const skills = await getInstalledSkills();
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
- console.log('No skills installed yet. Run "skm ls" to see available skills.');
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
- console.log('Searching npm registry...\n');
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
- console.log('No skills found. Check back later!');
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
- console.log(`Found ${total} skill(s):\n`);
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) {
@@ -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
- url.searchParams.set('text', 'keywords:skillmarket');
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