itismyskillmarket 1.3.0 → 1.3.2
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/.github/workflows/publish-npm.yml +59 -0
- package/.github/workflows/publish-skill.yml +72 -0
- package/5e51cb7aa8b8e60d49d86f4689f5d4d1.png +0 -0
- package/CHANGELOG.md +410 -0
- package/DEVELOPMENT.md +376 -0
- package/README.md +75 -6
- package/SKILLMARKET-GUIDE.md +288 -0
- package/dist/index.js +733 -212
- package/docs/WEEKLY-UPDATE-2026-04-23.md +43 -0
- package/docs/plans/2026-04-01-skillmarket-design.md +267 -0
- package/docs/plans/2026-04-01-skillmarket-implementation.md +1031 -0
- package/docs/plans/2026-04-15-cross-platform-adapter-design.md +416 -0
- package/docs/plans/2026-04-15-cross-platform-adapter-plan.md +833 -0
- package/docs/plans/2026-04-16-keyword-search-design.md +143 -0
- package/docs/plans/2026-04-29-weekly-update.md +57 -0
- package/package.json +1 -6
- package/skills/README.md +54 -0
- package/skills/test-skill/SKILL.md +25 -0
- package/skills/test-skill/index.js +66 -0
- package/skills/test-skill/metadata.json +9 -0
- package/skills/test-skill/package.json +19 -0
- package/skills/test-skill-1/SKILL.md +24 -0
- package/skills/test-skill-1/index.js +13 -0
- package/skills/test-skill-1/metadata.json +9 -0
- package/skills/test-skill-1/package.json +16 -0
- package/skills/test-skill-2/SKILL.md +25 -0
- package/skills/test-skill-2/index.js +13 -0
- package/skills/test-skill-2/metadata.json +9 -0
- package/skills/test-skill-2/package.json +16 -0
- package/src/adapters/base.ts +87 -0
- package/src/adapters/claude.ts +31 -0
- package/src/adapters/index.ts +9 -0
- package/src/adapters/opencode.ts +40 -0
- package/src/adapters/registry.ts +77 -0
- package/src/adapters/vscode.ts +62 -0
- package/src/cli.ts +189 -75
- package/src/commands/info.ts +4 -15
- package/src/commands/install.ts +93 -54
- package/src/commands/ls.ts +182 -17
- package/src/commands/npm.ts +118 -16
- package/src/commands/search.ts +12 -7
- package/src/commands/sync.ts +6 -27
- package/src/commands/uninstall.ts +313 -15
- package/src/commands/update.ts +2 -2
- package/src/index.ts +27 -0
- package/src/types.ts +35 -0
- package/tsconfig.json +10 -0
- package/tsup.config.ts +22 -0
- package/wanxuchen-skillmarket-1.0.1.tgz +0 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* =============================================================================
|
|
3
|
+
* OpenCode Platform Adapter
|
|
4
|
+
* =============================================================================
|
|
5
|
+
*
|
|
6
|
+
* Handles skill installation for OpenCode AI coding tool.
|
|
7
|
+
* Skills are installed to ~/.config/opencode/skills/<skill-id>/
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import path from 'path';
|
|
11
|
+
import os from 'os';
|
|
12
|
+
import fs from 'fs-extra';
|
|
13
|
+
import { BaseAdapter } from './base.js';
|
|
14
|
+
|
|
15
|
+
export class OpenCodeAdapter extends BaseAdapter {
|
|
16
|
+
readonly id = 'opencode';
|
|
17
|
+
readonly name = 'OpenCode';
|
|
18
|
+
|
|
19
|
+
get skillDir(): string {
|
|
20
|
+
// Respect OPENCODE_CONFIG_DIR environment variable
|
|
21
|
+
const configDir = process.env.OPENCODE_CONFIG_DIR
|
|
22
|
+
|| path.join(os.homedir(), '.config', 'opencode');
|
|
23
|
+
return path.join(configDir, 'skills');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async isAvailable(): Promise<boolean> {
|
|
27
|
+
// Check for environment variable or directory
|
|
28
|
+
if (process.env.OPENCODE) return true;
|
|
29
|
+
|
|
30
|
+
const configDir = process.env.OPENCODE_CONFIG_DIR
|
|
31
|
+
|| path.join(os.homedir(), '.config', 'opencode');
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
await fs.ensureDir(path.join(configDir, 'skills'));
|
|
35
|
+
return true;
|
|
36
|
+
} catch {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* =============================================================================
|
|
3
|
+
* Platform Registry
|
|
4
|
+
* =============================================================================
|
|
5
|
+
*
|
|
6
|
+
* Central registry for platform adapters.
|
|
7
|
+
* Handles platform detection and selection.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { OpenCodeAdapter } from './opencode.js';
|
|
11
|
+
import { ClaudeAdapter } from './claude.js';
|
|
12
|
+
import { VSCodeAdapter } from './vscode.js';
|
|
13
|
+
import type { PlatformAdapter } from '../types.js';
|
|
14
|
+
import type { Platform } from '../constants.js';
|
|
15
|
+
|
|
16
|
+
const adapters: Map<string, PlatformAdapter> = new Map();
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Register all built-in platform adapters
|
|
20
|
+
*/
|
|
21
|
+
function registerAdapters(): void {
|
|
22
|
+
const opencode = new OpenCodeAdapter();
|
|
23
|
+
const claude = new ClaudeAdapter();
|
|
24
|
+
const vscode = new VSCodeAdapter();
|
|
25
|
+
|
|
26
|
+
adapters.set(opencode.id, opencode);
|
|
27
|
+
adapters.set(claude.id, claude);
|
|
28
|
+
adapters.set(vscode.id, vscode);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Register adapters on module load
|
|
32
|
+
registerAdapters();
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Detect which platforms are available on the current system
|
|
36
|
+
*/
|
|
37
|
+
export async function detectPlatforms(): Promise<PlatformAdapter[]> {
|
|
38
|
+
const available: PlatformAdapter[] = [];
|
|
39
|
+
|
|
40
|
+
for (const adapter of adapters.values()) {
|
|
41
|
+
if (await adapter.isAvailable()) {
|
|
42
|
+
available.push(adapter);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return available;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Get adapter for a specific platform
|
|
51
|
+
*/
|
|
52
|
+
export function getPlatformAdapter(platformId: string): PlatformAdapter | undefined {
|
|
53
|
+
return adapters.get(platformId);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Get all registered adapters
|
|
58
|
+
*/
|
|
59
|
+
export function getAllAdapters(): PlatformAdapter[] {
|
|
60
|
+
return Array.from(adapters.values());
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Get adapter by platform type
|
|
65
|
+
*/
|
|
66
|
+
export function getAdapterByPlatform(platform: Platform): PlatformAdapter | undefined {
|
|
67
|
+
const idMap: Record<Platform, string> = {
|
|
68
|
+
opencode: 'opencode',
|
|
69
|
+
claude: 'claude',
|
|
70
|
+
vscode: 'vscode',
|
|
71
|
+
cursor: 'opencode', // Cursor uses OpenCode-compatible structure
|
|
72
|
+
codex: 'opencode', // Codex uses OpenCode-compatible structure
|
|
73
|
+
antigravity: 'opencode', // Antigravity uses OpenCode-compatible structure
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
return adapters.get(idMap[platform]);
|
|
77
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* =============================================================================
|
|
3
|
+
* VSCode (Copilot) Platform Adapter
|
|
4
|
+
* =============================================================================
|
|
5
|
+
*
|
|
6
|
+
* Handles skill installation for VSCode GitHub Copilot Agent Skills.
|
|
7
|
+
* Skills are installed to ~/.copilot/skills/<skill-id>/
|
|
8
|
+
*
|
|
9
|
+
* Note: Also supports ~/.claude/skills/ for cross-compatibility.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import path from 'path';
|
|
13
|
+
import os from 'os';
|
|
14
|
+
import fs from 'fs-extra';
|
|
15
|
+
import { BaseAdapter } from './base.js';
|
|
16
|
+
|
|
17
|
+
export class VSCodeAdapter extends BaseAdapter {
|
|
18
|
+
readonly id = 'vscode';
|
|
19
|
+
readonly name = 'VSCode';
|
|
20
|
+
|
|
21
|
+
get skillDir(): string {
|
|
22
|
+
// Try ~/.copilot/skills first, fallback to ~/.claude/skills
|
|
23
|
+
return path.join(os.homedir(), '.copilot', 'skills');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async isAvailable(): Promise<boolean> {
|
|
27
|
+
// Check multiple possible locations
|
|
28
|
+
const possibleDirs = [
|
|
29
|
+
path.join(os.homedir(), '.copilot', 'skills'),
|
|
30
|
+
path.join(os.homedir(), '.claude', 'skills'),
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
for (const dir of possibleDirs) {
|
|
34
|
+
try {
|
|
35
|
+
await fs.ensureDir(dir);
|
|
36
|
+
return true;
|
|
37
|
+
} catch {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async install(skillId: string, sourceDir: string): Promise<void> {
|
|
46
|
+
// Install to ~/.copilot/skills, but also create symlink in ~/.claude/skills
|
|
47
|
+
await super.install(skillId, sourceDir);
|
|
48
|
+
|
|
49
|
+
// Create cross-compatible symlink in ~/.claude/skills
|
|
50
|
+
const claudeSkillDir = path.join(os.homedir(), '.claude', 'skills');
|
|
51
|
+
const targetPath = this.getSkillPath(skillId);
|
|
52
|
+
const claudeTargetPath = path.join(claudeSkillDir, skillId);
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
await fs.ensureDir(claudeSkillDir);
|
|
56
|
+
await fs.remove(claudeTargetPath);
|
|
57
|
+
await fs.symlink(targetPath, claudeTargetPath, 'junction');
|
|
58
|
+
} catch {
|
|
59
|
+
// Silently fail if symlink not possible (cross-platform compatibility)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
package/src/cli.ts
CHANGED
|
@@ -14,10 +14,11 @@
|
|
|
14
14
|
* - skm ls 列出可用的 skills
|
|
15
15
|
* - skm ls --installed 列出已安装的 skills
|
|
16
16
|
* - skm info <skill> 显示 skill 详情
|
|
17
|
-
* - skm install <skill> 安装 skill
|
|
18
|
-
* - skm uninstall <skill> 卸载 skill
|
|
17
|
+
* - skm install <skill> 安装 skill(支持 --platform)
|
|
18
|
+
* - skm uninstall <skill> 卸载 skill(支持 --platform)
|
|
19
19
|
* - skm update [skill] 更新 skill(s)
|
|
20
20
|
* - skm sync 同步平台链接
|
|
21
|
+
* - skm platforms 显示可用平台
|
|
21
22
|
*
|
|
22
23
|
* @module cli
|
|
23
24
|
*/
|
|
@@ -28,16 +29,26 @@
|
|
|
28
29
|
|
|
29
30
|
// Commander.js - 轻量级的命令行界面框架
|
|
30
31
|
import { Command } from 'commander';
|
|
32
|
+
import { readFileSync } from 'fs';
|
|
33
|
+
import { fileURLToPath } from 'url';
|
|
34
|
+
import { dirname, resolve } from 'path';
|
|
35
|
+
|
|
36
|
+
// 获取 package.json 中的版本号
|
|
37
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
38
|
+
const __dirname = dirname(__filename);
|
|
39
|
+
const packageJson = JSON.parse(readFileSync(resolve(__dirname, '../package.json'), 'utf-8'));
|
|
40
|
+
const VERSION = packageJson.version || '1.3.1';
|
|
31
41
|
|
|
32
42
|
// 内部模块导入
|
|
33
43
|
import { PLATFORMS } from './constants.js'; // 平台常量
|
|
34
44
|
import { listSkills } from './commands/ls.js'; // 列表命令
|
|
45
|
+
import { searchSkills } from './commands/search.js'; // 搜索命令
|
|
35
46
|
import { showSkillInfo } from './commands/info.js'; // 信息命令
|
|
36
47
|
import { installSkill } from './commands/install.js'; // 安装命令
|
|
37
48
|
import { syncPlatformLinks } from './commands/sync.js'; // 同步命令
|
|
38
49
|
import { updateSkill } from './commands/update.js'; // 更新命令
|
|
39
|
-
import { uninstallSkill } from './commands/uninstall.js'; // 卸载命令
|
|
40
|
-
import {
|
|
50
|
+
import { uninstallSkill, uninstallAll } from './commands/uninstall.js'; // 卸载命令
|
|
51
|
+
import { detectPlatforms, getAllAdapters, OpenCodeAdapter, ClaudeAdapter, VSCodeAdapter } from './adapters/index.js'; // 平台适配器
|
|
41
52
|
|
|
42
53
|
// -----------------------------------------------------------------------------
|
|
43
54
|
// 创建命令程序实例
|
|
@@ -64,7 +75,7 @@ const program = new Command();
|
|
|
64
75
|
program
|
|
65
76
|
.name('skm')
|
|
66
77
|
.description('SkillMarket - Cross-platform skill manager for AI coding tools')
|
|
67
|
-
.version(
|
|
78
|
+
.version(VERSION);
|
|
68
79
|
|
|
69
80
|
// -----------------------------------------------------------------------------
|
|
70
81
|
// 帮助命令 (-h, --help)
|
|
@@ -75,38 +86,58 @@ program
|
|
|
75
86
|
*
|
|
76
87
|
* 显示详细的使用说明和命令示例
|
|
77
88
|
*/
|
|
78
|
-
|
|
79
|
-
|
|
89
|
+
program
|
|
90
|
+
.hook('preAction', (thisCommand) => {
|
|
91
|
+
if (thisCommand.opts().help) {
|
|
80
92
|
console.log(`
|
|
81
93
|
SkillMarket CLI
|
|
82
94
|
|
|
83
95
|
Usage: skm <command> [options]
|
|
84
96
|
|
|
85
97
|
Commands:
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
98
|
+
ls [options] List available skills
|
|
99
|
+
--installed Show only installed skills
|
|
100
|
+
--updates Check for updates
|
|
101
|
+
--page <n> Page number (default: 1)
|
|
102
|
+
--limit <n> Items per page (default: 20)
|
|
103
|
+
-s, --search Search by keyword
|
|
104
|
+
info <skill-id> Display skill information
|
|
105
|
+
install <skill> Install a skill
|
|
106
|
+
@version Install specific version
|
|
107
|
+
--platform Target platforms (opencode,claude,vscode)
|
|
108
|
+
--force Overwrite if already installed
|
|
109
|
+
uninstall <skill> Remove an installed skill
|
|
110
|
+
--platform Target platforms
|
|
111
|
+
--all Uninstall ALL installed skills
|
|
112
|
+
--dry-run Preview without deleting
|
|
113
|
+
-y, --yes Skip confirmation
|
|
114
|
+
update [options] Update skills
|
|
115
|
+
--all Update all skills
|
|
116
|
+
sync Synchronize platform links
|
|
117
|
+
platforms Show available platforms
|
|
99
118
|
|
|
100
119
|
Examples:
|
|
101
|
-
skm
|
|
102
|
-
skm
|
|
103
|
-
skm --
|
|
104
|
-
skm --
|
|
105
|
-
skm
|
|
106
|
-
skm
|
|
107
|
-
skm --
|
|
108
|
-
|
|
109
|
-
|
|
120
|
+
skm ls List all available skills (page 1)
|
|
121
|
+
skm ls --page 2 Go to page 2
|
|
122
|
+
skm ls --limit 10 Show 10 items per page
|
|
123
|
+
skm ls --search brain Search skills by keyword
|
|
124
|
+
skm ls -s brain Search with short form
|
|
125
|
+
skm ls --installed Show installed skills only
|
|
126
|
+
skm ls --installed --search test Search installed skills
|
|
127
|
+
skm ls --installed --page 2
|
|
128
|
+
skm info brainstorming View skill details
|
|
129
|
+
skm install brainstorming Install to all platforms
|
|
130
|
+
skm install brainstorming --platform opencode Install to OpenCode only
|
|
131
|
+
skm install brainstorming --platform claude,vscode Install to multiple
|
|
132
|
+
skm uninstall brainstorming
|
|
133
|
+
skm uninstall --all Uninstall all skills (with confirmation)
|
|
134
|
+
skm uninstall --all --yes Force uninstall all without confirmation
|
|
135
|
+
skm uninstall brainstorming --dry-run Preview uninstall
|
|
136
|
+
skm platforms Show available platforms
|
|
137
|
+
`);
|
|
138
|
+
process.exit(0);
|
|
139
|
+
}
|
|
140
|
+
});
|
|
110
141
|
|
|
111
142
|
// -----------------------------------------------------------------------------
|
|
112
143
|
// 列表命令 (skm ls)
|
|
@@ -126,8 +157,41 @@ const lsCmd = program.command('ls').description('List available skills');
|
|
|
126
157
|
lsCmd
|
|
127
158
|
.option('--installed', 'Show only installed skills')
|
|
128
159
|
.option('--updates', 'Check for updates')
|
|
160
|
+
.option('-p, --page <number>', 'Page number (default: 1)', parseInt)
|
|
161
|
+
.option('-l, --limit <number>', 'Items per page (default: 20)', parseInt)
|
|
162
|
+
.option('-s, --search <keyword>', 'Search by keyword (id, displayName, description)')
|
|
129
163
|
.action((opts) => {
|
|
130
|
-
|
|
164
|
+
// Ensure numeric options have default values if not provided
|
|
165
|
+
const options = {
|
|
166
|
+
...opts,
|
|
167
|
+
page: opts.page ?? 1,
|
|
168
|
+
limit: opts.limit ?? 20,
|
|
169
|
+
search: opts.search
|
|
170
|
+
};
|
|
171
|
+
listSkills(options);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
// -----------------------------------------------------------------------------
|
|
175
|
+
// 搜索命令 (skm search)
|
|
176
|
+
// -----------------------------------------------------------------------------
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* 搜索命令
|
|
180
|
+
*
|
|
181
|
+
* 独立搜索 npm 上的 skills
|
|
182
|
+
*
|
|
183
|
+
* 用法: skm search <keyword>
|
|
184
|
+
*
|
|
185
|
+
* @example
|
|
186
|
+
* skm search brain
|
|
187
|
+
*/
|
|
188
|
+
const searchCmd = program.command('search').description('Search skills from npm registry');
|
|
189
|
+
searchCmd
|
|
190
|
+
.argument('<keyword>', 'Keyword to search')
|
|
191
|
+
.option('-l, --limit <number>', 'Max results to show (default: 20)', parseInt)
|
|
192
|
+
.action(async (keyword, opts) => {
|
|
193
|
+
const limit = opts.limit ?? 20;
|
|
194
|
+
await searchSkills(keyword, limit);
|
|
131
195
|
});
|
|
132
196
|
|
|
133
197
|
// -----------------------------------------------------------------------------
|
|
@@ -158,25 +222,36 @@ infoCmd
|
|
|
158
222
|
/**
|
|
159
223
|
* 安装命令
|
|
160
224
|
*
|
|
161
|
-
* 从 npm 安装指定的 skill
|
|
225
|
+
* 从 npm 安装指定的 skill 到本地和跨平台目录
|
|
162
226
|
*
|
|
163
227
|
* 用法:
|
|
164
|
-
* - skm install <skill>
|
|
228
|
+
* - skm install <skill> 安装到所有检测到的平台
|
|
165
229
|
* - skm install <skill>@<ver> 安装指定版本
|
|
166
|
-
* - skm install --
|
|
230
|
+
* - skm install --platform opencode 安装到特定平台
|
|
231
|
+
* - skm install --platform claude,vscode 安装到多个平台
|
|
232
|
+
* - skm install --force 强制覆盖
|
|
167
233
|
*
|
|
168
234
|
* @example
|
|
169
235
|
* skm install brainstorming
|
|
170
236
|
* skm install brainstorming@1.0.0
|
|
237
|
+
* skm install brainstorming --platform opencode
|
|
171
238
|
*/
|
|
172
|
-
const installCmd = program.command('install').description('Install a skill');
|
|
239
|
+
const installCmd = program.command('install').description('Install a skill to local and platform directories');
|
|
173
240
|
installCmd
|
|
174
241
|
.argument('<skill>', 'Skill ID to install (e.g., brainstorming or @scope/name)')
|
|
175
|
-
.option('--
|
|
176
|
-
.option('-
|
|
242
|
+
.option('-p, --platform <platforms>', 'Target platforms (comma-separated: opencode,claude,vscode)')
|
|
243
|
+
.option('-f, --force', 'Overwrite if already installed')
|
|
244
|
+
.option('-v, --version <version>', 'Specific version to install')
|
|
177
245
|
.action(async (skill, opts) => {
|
|
178
246
|
try {
|
|
179
|
-
|
|
247
|
+
const platforms = opts.platform
|
|
248
|
+
? opts.platform.split(',').map((p: string) => p.trim())
|
|
249
|
+
: undefined;
|
|
250
|
+
|
|
251
|
+
await installSkill(skill, opts.version, {
|
|
252
|
+
platforms,
|
|
253
|
+
force: opts.force
|
|
254
|
+
});
|
|
180
255
|
} catch (err) {
|
|
181
256
|
console.error('Installation failed:', err);
|
|
182
257
|
process.exit(1);
|
|
@@ -190,19 +265,60 @@ installCmd
|
|
|
190
265
|
/**
|
|
191
266
|
* 卸载命令
|
|
192
267
|
*
|
|
193
|
-
* 移除本地已安装的 skill
|
|
268
|
+
* 移除本地已安装的 skill 及各平台的文件
|
|
194
269
|
*
|
|
195
|
-
* 用法:
|
|
270
|
+
* 用法:
|
|
271
|
+
* - skm uninstall <skill> 卸载所有平台
|
|
272
|
+
* - skm uninstall <skill> --platform opencode 卸载特定平台
|
|
273
|
+
* - skm uninstall --all 卸载所有已安装的 skills
|
|
274
|
+
* - skm uninstall --dry-run 预览删除内容
|
|
275
|
+
*
|
|
276
|
+
* 新增 (v1.4.0):
|
|
277
|
+
* --all: 卸载所有已安装的 skills(需要确认)
|
|
278
|
+
* --dry-run: 预览模式,不实际删除
|
|
279
|
+
* -y, --yes: 跳过确认提示
|
|
196
280
|
*
|
|
197
281
|
* @example
|
|
198
282
|
* skm uninstall brainstorming
|
|
283
|
+
* skm uninstall brainstorming --platform claude
|
|
284
|
+
* skm uninstall --all
|
|
285
|
+
* skm uninstall --all --yes
|
|
286
|
+
* skm uninstall brainstorming --dry-run
|
|
199
287
|
*/
|
|
200
|
-
const uninstallCmd = program.command('uninstall').description('Remove an installed skill');
|
|
288
|
+
const uninstallCmd = program.command('uninstall').description('Remove an installed skill from local and platform directories');
|
|
201
289
|
uninstallCmd
|
|
202
|
-
.argument('
|
|
203
|
-
.
|
|
290
|
+
.argument('[skill]', 'Skill ID to uninstall (required unless using --all)')
|
|
291
|
+
.option('-p, --platform <platforms>', 'Target platforms (comma-separated)')
|
|
292
|
+
.option('-a, --all', 'Uninstall ALL installed skills (requires confirmation)')
|
|
293
|
+
.option('-d, --dry-run', 'Preview what would be uninstalled without actually deleting')
|
|
294
|
+
.option('-y, --yes', 'Skip confirmation prompts')
|
|
295
|
+
.action(async (skill, opts) => {
|
|
204
296
|
try {
|
|
205
|
-
|
|
297
|
+
const platforms = opts.platform
|
|
298
|
+
? opts.platform.split(',').map((p: string) => p.trim())
|
|
299
|
+
: undefined;
|
|
300
|
+
|
|
301
|
+
// 处理 --all 选项
|
|
302
|
+
if (opts.all) {
|
|
303
|
+
await uninstallAll({
|
|
304
|
+
platforms,
|
|
305
|
+
dryRun: opts.dryRun,
|
|
306
|
+
yes: opts.yes
|
|
307
|
+
});
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// skill 参数是必需的(除非使用 --all)
|
|
312
|
+
if (!skill) {
|
|
313
|
+
console.error('Error: Skill ID is required (or use --all to uninstall all)');
|
|
314
|
+
process.exit(1);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
await uninstallSkill(skill, {
|
|
318
|
+
platforms,
|
|
319
|
+
dryRun: opts.dryRun,
|
|
320
|
+
yes: opts.yes
|
|
321
|
+
});
|
|
206
322
|
} catch (err) {
|
|
207
323
|
console.error('Uninstall failed:', err);
|
|
208
324
|
process.exit(1);
|
|
@@ -269,46 +385,44 @@ program
|
|
|
269
385
|
});
|
|
270
386
|
|
|
271
387
|
// -----------------------------------------------------------------------------
|
|
272
|
-
// 平台命令 (skm
|
|
388
|
+
// 平台命令 (skm platforms)
|
|
273
389
|
// -----------------------------------------------------------------------------
|
|
274
390
|
|
|
275
391
|
/**
|
|
276
|
-
*
|
|
392
|
+
* 平台命令
|
|
277
393
|
*
|
|
278
|
-
*
|
|
394
|
+
* 显示所有支持的平台及其状态
|
|
279
395
|
*
|
|
280
|
-
* 用法: skm
|
|
396
|
+
* 用法: skm platforms
|
|
281
397
|
*/
|
|
282
|
-
const
|
|
283
|
-
|
|
284
|
-
.
|
|
285
|
-
.action((name) => {
|
|
286
|
-
console.log('Platform command - name:', name);
|
|
287
|
-
});
|
|
288
|
-
|
|
289
|
-
// -----------------------------------------------------------------------------
|
|
290
|
-
// 搜索命令 (skm search)
|
|
291
|
-
// -----------------------------------------------------------------------------
|
|
292
|
-
|
|
293
|
-
/**
|
|
294
|
-
* 搜索命令
|
|
295
|
-
*
|
|
296
|
-
* 在 npm registry 上搜索匹配的 skills
|
|
297
|
-
* 只返回包名包含关键词的 skill
|
|
298
|
-
*
|
|
299
|
-
* 用法: skm search <keyword>
|
|
300
|
-
*
|
|
301
|
-
* @example
|
|
302
|
-
* skm search test
|
|
303
|
-
*/
|
|
304
|
-
const searchCmd = program.command('search').description('Search skills from npm registry');
|
|
305
|
-
searchCmd
|
|
306
|
-
.argument('<keyword>', 'Keyword to search')
|
|
307
|
-
.action(async (keyword) => {
|
|
398
|
+
const platformsCmd = program.command('platforms').description('Show available platforms');
|
|
399
|
+
platformsCmd
|
|
400
|
+
.action(async () => {
|
|
308
401
|
try {
|
|
309
|
-
await
|
|
402
|
+
const available = await detectPlatforms();
|
|
403
|
+
|
|
404
|
+
console.log('\n📍 Available Platforms:\n');
|
|
405
|
+
|
|
406
|
+
const allPlatforms = [
|
|
407
|
+
{ name: 'OpenCode', adapter: new OpenCodeAdapter() },
|
|
408
|
+
{ name: 'Claude Code', adapter: new ClaudeAdapter() },
|
|
409
|
+
{ name: 'VSCode', adapter: new VSCodeAdapter() },
|
|
410
|
+
];
|
|
411
|
+
|
|
412
|
+
for (const { name, adapter } of allPlatforms) {
|
|
413
|
+
const isAvailable = available.find(a => a.id === adapter.id);
|
|
414
|
+
const installed = await adapter.listInstalled();
|
|
415
|
+
|
|
416
|
+
if (isAvailable) {
|
|
417
|
+
console.log(`${name.padEnd(12)} ✅ Available (${installed.length} skills installed)`);
|
|
418
|
+
} else {
|
|
419
|
+
console.log(`${name.padEnd(12)} ❌ Not detected`);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
console.log('');
|
|
310
424
|
} catch (err) {
|
|
311
|
-
console.error('
|
|
425
|
+
console.error('Failed to list platforms:', err);
|
|
312
426
|
process.exit(1);
|
|
313
427
|
}
|
|
314
428
|
});
|
package/src/commands/info.ts
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
// 导入依赖
|
|
20
20
|
// -----------------------------------------------------------------------------
|
|
21
21
|
|
|
22
|
-
import {
|
|
22
|
+
import { fetchSkillPackage } from './npm.js'; // npm registry 查询
|
|
23
23
|
import {
|
|
24
24
|
isSkillInstalled, // 检查 skill 是否已安装
|
|
25
25
|
getInstalledSkills // 获取已安装 skills 列表
|
|
@@ -49,25 +49,14 @@ export async function showSkillInfo(skillId: string): Promise<void> {
|
|
|
49
49
|
// 处理包名格式
|
|
50
50
|
// -------------------------------------------------------------------------
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
* 转换 skillId 为完整的 npm 包名格式
|
|
54
|
-
*
|
|
55
|
-
* 支持两种输入格式:
|
|
56
|
-
* 1. 短格式: "brainstorming" → "@skillmarket/brainstorming"
|
|
57
|
-
* 2. 完整格式: "@custom/skill" → "@custom/skill"
|
|
58
|
-
*/
|
|
59
|
-
const packageName = skillId.startsWith('@')
|
|
60
|
-
? skillId // 已经是 scoped 包名
|
|
61
|
-
: `@skillmarket/${skillId}`; // 转换为 scoped 包名
|
|
62
|
-
|
|
63
|
-
console.log(`Fetching info for: ${packageName}\n`);
|
|
52
|
+
console.log(`Fetching info for: ${skillId}\n`);
|
|
64
53
|
|
|
65
54
|
try {
|
|
66
55
|
// -------------------------------------------------------------------------
|
|
67
|
-
// 从 npm
|
|
56
|
+
// 从 npm 获取包信息(自动尝试多个可能的 scope)
|
|
68
57
|
// -------------------------------------------------------------------------
|
|
69
58
|
|
|
70
|
-
const info = await
|
|
59
|
+
const info = await fetchSkillPackage(skillId);
|
|
71
60
|
|
|
72
61
|
// 包不存在
|
|
73
62
|
if (!info) {
|