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,833 @@
|
|
|
1
|
+
# Cross-Platform Skill Adapter Implementation Plan
|
|
2
|
+
|
|
3
|
+
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
|
4
|
+
|
|
5
|
+
**Goal:** Enable users to install skills to OpenCode, Claude Code, and VSCode platforms with a single `skm install` command.
|
|
6
|
+
|
|
7
|
+
**Architecture:** Create platform adapter classes that follow a common interface, detect available platforms automatically, and install skills to each platform's native skill directory.
|
|
8
|
+
|
|
9
|
+
**Tech Stack:** TypeScript, Node.js, fs-extra
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Task 1: Create Platform Adapter Base Class
|
|
14
|
+
|
|
15
|
+
**Files:**
|
|
16
|
+
- Create: `src/adapters/base.ts`
|
|
17
|
+
- Create: `src/adapters/index.ts`
|
|
18
|
+
- Modify: `src/types.ts`
|
|
19
|
+
|
|
20
|
+
**Step 1: Add PlatformAdapter type to types.ts**
|
|
21
|
+
|
|
22
|
+
Add to `src/types.ts`:
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
/**
|
|
26
|
+
* Platform adapter interface for cross-platform skill installation
|
|
27
|
+
*/
|
|
28
|
+
export interface PlatformAdapter {
|
|
29
|
+
/** Unique platform identifier */
|
|
30
|
+
readonly id: string;
|
|
31
|
+
|
|
32
|
+
/** Human-readable platform name */
|
|
33
|
+
readonly name: string;
|
|
34
|
+
|
|
35
|
+
/** Platform's skill directory path */
|
|
36
|
+
readonly skillDir: string;
|
|
37
|
+
|
|
38
|
+
/** Check if this platform is available on the current system */
|
|
39
|
+
isAvailable(): Promise<boolean>;
|
|
40
|
+
|
|
41
|
+
/** Check if a skill is installed on this platform */
|
|
42
|
+
isInstalled(skillId: string): Promise<boolean>;
|
|
43
|
+
|
|
44
|
+
/** Install a skill to this platform */
|
|
45
|
+
install(skillId: string, sourceDir: string): Promise<void>;
|
|
46
|
+
|
|
47
|
+
/** Uninstall a skill from this platform */
|
|
48
|
+
uninstall(skillId: string): Promise<void>;
|
|
49
|
+
|
|
50
|
+
/** List all skills installed on this platform */
|
|
51
|
+
listInstalled(): Promise<string[]>;
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Step 2: Create base adapter class**
|
|
56
|
+
|
|
57
|
+
Create `src/adapters/base.ts`:
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
/**
|
|
61
|
+
* =============================================================================
|
|
62
|
+
* Base Platform Adapter
|
|
63
|
+
* =============================================================================
|
|
64
|
+
*
|
|
65
|
+
* Abstract base class for platform-specific skill adapters.
|
|
66
|
+
* Provides common functionality for all platforms.
|
|
67
|
+
*/
|
|
68
|
+
|
|
69
|
+
import fs from 'fs-extra';
|
|
70
|
+
import path from 'path';
|
|
71
|
+
import type { PlatformAdapter } from '../types.js';
|
|
72
|
+
|
|
73
|
+
export abstract class BaseAdapter implements PlatformAdapter {
|
|
74
|
+
abstract readonly id: string;
|
|
75
|
+
abstract readonly name: string;
|
|
76
|
+
abstract readonly skillDir: string;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Get the path where a specific skill should be installed
|
|
80
|
+
*/
|
|
81
|
+
protected getSkillPath(skillId: string): string {
|
|
82
|
+
return path.join(this.skillDir, skillId);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Get the path to the SKILL.md file for a skill
|
|
87
|
+
*/
|
|
88
|
+
protected getSkillFilePath(skillId: string): string {
|
|
89
|
+
return path.join(this.getSkillPath(skillId), 'SKILL.md');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async isAvailable(): Promise<boolean> {
|
|
93
|
+
// Check if skill directory is writable or can be created
|
|
94
|
+
try {
|
|
95
|
+
await fs.ensureDir(this.skillDir);
|
|
96
|
+
return true;
|
|
97
|
+
} catch {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async isInstalled(skillId: string): Promise<boolean> {
|
|
103
|
+
const skillFile = this.getSkillFilePath(skillId);
|
|
104
|
+
return fs.pathExists(skillFile);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async install(skillId: string, sourceDir: string): Promise<void> {
|
|
108
|
+
const targetDir = this.getSkillPath(skillId);
|
|
109
|
+
const targetFile = this.getSkillFilePath(skillId);
|
|
110
|
+
|
|
111
|
+
// Ensure target directory exists
|
|
112
|
+
await fs.ensureDir(targetDir);
|
|
113
|
+
|
|
114
|
+
// Check if SKILL.md exists in source
|
|
115
|
+
const sourceFile = path.join(sourceDir, 'SKILL.md');
|
|
116
|
+
if (!(await fs.pathExists(sourceFile))) {
|
|
117
|
+
throw new Error(`SKILL.md not found in ${sourceDir}`);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Copy SKILL.md to target
|
|
121
|
+
await fs.copy(sourceFile, targetFile, { overwrite: true });
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async uninstall(skillId: string): Promise<void> {
|
|
125
|
+
const targetDir = this.getSkillPath(skillId);
|
|
126
|
+
if (await fs.pathExists(targetDir)) {
|
|
127
|
+
await fs.remove(targetDir);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
async listInstalled(): Promise<string[]> {
|
|
132
|
+
if (!(await fs.pathExists(this.skillDir))) {
|
|
133
|
+
return [];
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const entries = await fs.readdir(this.skillDir, { withFileTypes: true });
|
|
137
|
+
const skills: string[] = [];
|
|
138
|
+
|
|
139
|
+
for (const entry of entries) {
|
|
140
|
+
if (entry.isDirectory()) {
|
|
141
|
+
const skillFile = path.join(this.skillDir, entry.name, 'SKILL.md');
|
|
142
|
+
if (await fs.pathExists(skillFile)) {
|
|
143
|
+
skills.push(entry.name);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return skills;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
**Step 3: Create index file**
|
|
154
|
+
|
|
155
|
+
Create `src/adapters/index.ts`:
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
/**
|
|
159
|
+
* Platform adapters index
|
|
160
|
+
*/
|
|
161
|
+
|
|
162
|
+
export { BaseAdapter } from './base.js';
|
|
163
|
+
export { OpenCodeAdapter } from './opencode.js';
|
|
164
|
+
export { ClaudeAdapter } from './claude.js';
|
|
165
|
+
export { VSCodeAdapter } from './vscode.js';
|
|
166
|
+
export { detectPlatforms, getPlatformAdapter } from './registry.js';
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
**Step 4: Commit**
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
git add src/adapters/base.ts src/adapters/index.ts src/types.ts
|
|
173
|
+
git commit -m "feat: add base platform adapter class"
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Task 2: Create OpenCode Adapter
|
|
179
|
+
|
|
180
|
+
**Files:**
|
|
181
|
+
- Create: `src/adapters/opencode.ts`
|
|
182
|
+
|
|
183
|
+
**Step 1: Create OpenCode adapter**
|
|
184
|
+
|
|
185
|
+
Create `src/adapters/opencode.ts`:
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
/**
|
|
189
|
+
* =============================================================================
|
|
190
|
+
* OpenCode Platform Adapter
|
|
191
|
+
* =============================================================================
|
|
192
|
+
*
|
|
193
|
+
* Handles skill installation for OpenCode AI coding tool.
|
|
194
|
+
* Skills are installed to ~/.config/opencode/skills/<skill-id>/
|
|
195
|
+
*/
|
|
196
|
+
|
|
197
|
+
import path from 'path';
|
|
198
|
+
import os from 'os';
|
|
199
|
+
import { BaseAdapter } from './base.js';
|
|
200
|
+
|
|
201
|
+
export class OpenCodeAdapter extends BaseAdapter {
|
|
202
|
+
readonly id = 'opencode';
|
|
203
|
+
readonly name = 'OpenCode';
|
|
204
|
+
|
|
205
|
+
get skillDir(): string {
|
|
206
|
+
// Respect OPENCODE_CONFIG_DIR environment variable
|
|
207
|
+
const configDir = process.env.OPENCODE_CONFIG_DIR
|
|
208
|
+
|| path.join(os.homedir(), '.config', 'opencode');
|
|
209
|
+
return path.join(configDir, 'skills');
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
async isAvailable(): Promise<boolean> {
|
|
213
|
+
// Check for environment variable or directory
|
|
214
|
+
if (process.env.OPENCODE) return true;
|
|
215
|
+
|
|
216
|
+
const configDir = process.env.OPENCODE_CONFIG_DIR
|
|
217
|
+
|| path.join(os.homedir(), '.config', 'opencode');
|
|
218
|
+
|
|
219
|
+
try {
|
|
220
|
+
await fs.ensureDir(path.join(configDir, 'skills'));
|
|
221
|
+
return true;
|
|
222
|
+
} catch {
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
import fs from 'fs-extra';
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
**Step 2: Commit**
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
git add src/adapters/opencode.ts
|
|
235
|
+
git commit -m "feat: add OpenCode platform adapter"
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## Task 3: Create Claude Code Adapter
|
|
241
|
+
|
|
242
|
+
**Files:**
|
|
243
|
+
- Create: `src/adapters/claude.ts`
|
|
244
|
+
|
|
245
|
+
**Step 1: Create Claude adapter**
|
|
246
|
+
|
|
247
|
+
Create `src/adapters/claude.ts`:
|
|
248
|
+
|
|
249
|
+
```typescript
|
|
250
|
+
/**
|
|
251
|
+
* =============================================================================
|
|
252
|
+
* Claude Code Platform Adapter
|
|
253
|
+
* =============================================================================
|
|
254
|
+
*
|
|
255
|
+
* Handles skill installation for Claude Code CLI.
|
|
256
|
+
* Skills are installed to ~/.claude/skills/<skill-id>/
|
|
257
|
+
*/
|
|
258
|
+
|
|
259
|
+
import path from 'path';
|
|
260
|
+
import os from 'os';
|
|
261
|
+
import fs from 'fs-extra';
|
|
262
|
+
import { BaseAdapter } from './base.js';
|
|
263
|
+
|
|
264
|
+
export class ClaudeAdapter extends BaseAdapter {
|
|
265
|
+
readonly id = 'claude';
|
|
266
|
+
readonly name = 'Claude Code';
|
|
267
|
+
|
|
268
|
+
get skillDir(): string {
|
|
269
|
+
return path.join(os.homedir(), '.claude', 'skills');
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
async isAvailable(): Promise<boolean> {
|
|
273
|
+
// Check for environment variable or directory
|
|
274
|
+
if (process.env.CLAUDE_CODE) return true;
|
|
275
|
+
|
|
276
|
+
// Check if .claude directory exists
|
|
277
|
+
const claudeDir = path.join(os.homedir(), '.claude');
|
|
278
|
+
return fs.pathExists(claudeDir);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
**Step 2: Commit**
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
git add src/adapters/claude.ts
|
|
287
|
+
git commit -m "feat: add Claude Code platform adapter"
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
## Task 4: Create VSCode Adapter
|
|
293
|
+
|
|
294
|
+
**Files:**
|
|
295
|
+
- Create: `src/adapters/vscode.ts`
|
|
296
|
+
|
|
297
|
+
**Step 1: Create VSCode adapter**
|
|
298
|
+
|
|
299
|
+
Create `src/adapters/vscode.ts`:
|
|
300
|
+
|
|
301
|
+
```typescript
|
|
302
|
+
/**
|
|
303
|
+
* =============================================================================
|
|
304
|
+
* VSCode (Copilot) Platform Adapter
|
|
305
|
+
* =============================================================================
|
|
306
|
+
*
|
|
307
|
+
* Handles skill installation for VSCode GitHub Copilot Agent Skills.
|
|
308
|
+
* Skills are installed to ~/.copilot/skills/<skill-id>/
|
|
309
|
+
*
|
|
310
|
+
* Note: Also supports ~/.claude/skills/ for cross-compatibility.
|
|
311
|
+
*/
|
|
312
|
+
|
|
313
|
+
import path from 'path';
|
|
314
|
+
import os from 'os';
|
|
315
|
+
import fs from 'fs-extra';
|
|
316
|
+
import { BaseAdapter } from './base.js';
|
|
317
|
+
|
|
318
|
+
export class VSCodeAdapter extends BaseAdapter {
|
|
319
|
+
readonly id = 'vscode';
|
|
320
|
+
readonly name = 'VSCode';
|
|
321
|
+
|
|
322
|
+
get skillDir(): string {
|
|
323
|
+
// Try ~/.copilot/skills first, fallback to ~/.claude/skills
|
|
324
|
+
return path.join(os.homedir(), '.copilot', 'skills');
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
async isAvailable(): Promise<boolean> {
|
|
328
|
+
// Check multiple possible locations
|
|
329
|
+
const possibleDirs = [
|
|
330
|
+
path.join(os.homedir(), '.copilot', 'skills'),
|
|
331
|
+
path.join(os.homedir(), '.claude', 'skills'),
|
|
332
|
+
];
|
|
333
|
+
|
|
334
|
+
for (const dir of possibleDirs) {
|
|
335
|
+
try {
|
|
336
|
+
await fs.ensureDir(dir);
|
|
337
|
+
return true;
|
|
338
|
+
} catch {
|
|
339
|
+
continue;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
return false;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
async install(skillId: string, sourceDir: string): Promise<void> {
|
|
347
|
+
// Install to ~/.copilot/skills, but also create symlink in ~/.claude/skills
|
|
348
|
+
await super.install(skillId, sourceDir);
|
|
349
|
+
|
|
350
|
+
// Create cross-compatible symlink in ~/.claude/skills
|
|
351
|
+
const claudeSkillDir = path.join(os.homedir(), '.claude', 'skills');
|
|
352
|
+
const targetPath = this.getSkillPath(skillId);
|
|
353
|
+
const claudeTargetPath = path.join(claudeSkillDir, skillId);
|
|
354
|
+
|
|
355
|
+
try {
|
|
356
|
+
await fs.ensureDir(claudeSkillDir);
|
|
357
|
+
await fs.remove(claudeTargetPath);
|
|
358
|
+
await fs.symlink(targetPath, claudeTargetPath, 'junction');
|
|
359
|
+
} catch {
|
|
360
|
+
// Silently fail if symlink not possible (cross-platform compatibility)
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
**Step 2: Commit**
|
|
367
|
+
|
|
368
|
+
```bash
|
|
369
|
+
git add src/adapters/vscode.ts
|
|
370
|
+
git commit -m "feat: add VSCode platform adapter"
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
---
|
|
374
|
+
|
|
375
|
+
## Task 5: Create Platform Registry
|
|
376
|
+
|
|
377
|
+
**Files:**
|
|
378
|
+
- Create: `src/adapters/registry.ts`
|
|
379
|
+
|
|
380
|
+
**Step 1: Create platform registry**
|
|
381
|
+
|
|
382
|
+
Create `src/adapters/registry.ts`:
|
|
383
|
+
|
|
384
|
+
```typescript
|
|
385
|
+
/**
|
|
386
|
+
* =============================================================================
|
|
387
|
+
* Platform Registry
|
|
388
|
+
* =============================================================================
|
|
389
|
+
*
|
|
390
|
+
* Central registry for platform adapters.
|
|
391
|
+
* Handles platform detection and selection.
|
|
392
|
+
*/
|
|
393
|
+
|
|
394
|
+
import { OpenCodeAdapter } from './opencode.js';
|
|
395
|
+
import { ClaudeAdapter } from './claude.js';
|
|
396
|
+
import { VSCodeAdapter } from './vscode.js';
|
|
397
|
+
import type { PlatformAdapter } from '../types.js';
|
|
398
|
+
import type { Platform } from '../constants.js';
|
|
399
|
+
|
|
400
|
+
const adapters: Map<string, PlatformAdapter> = new Map();
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Register all built-in platform adapters
|
|
404
|
+
*/
|
|
405
|
+
function registerAdapters(): void {
|
|
406
|
+
const opencode = new OpenCodeAdapter();
|
|
407
|
+
const claude = new ClaudeAdapter();
|
|
408
|
+
const vscode = new VSCodeAdapter();
|
|
409
|
+
|
|
410
|
+
adapters.set(opencode.id, opencode);
|
|
411
|
+
adapters.set(claude.id, claude);
|
|
412
|
+
adapters.set(vscode.id, vscode);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// Register adapters on module load
|
|
416
|
+
registerAdapters();
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Detect which platforms are available on the current system
|
|
420
|
+
*/
|
|
421
|
+
export async function detectPlatforms(): Promise<PlatformAdapter[]> {
|
|
422
|
+
const available: PlatformAdapter[] = [];
|
|
423
|
+
|
|
424
|
+
for (const adapter of adapters.values()) {
|
|
425
|
+
if (await adapter.isAvailable()) {
|
|
426
|
+
available.push(adapter);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
return available;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Get adapter for a specific platform
|
|
435
|
+
*/
|
|
436
|
+
export function getPlatformAdapter(platformId: string): PlatformAdapter | undefined {
|
|
437
|
+
return adapters.get(platformId);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* Get all registered adapters
|
|
442
|
+
*/
|
|
443
|
+
export function getAllAdapters(): PlatformAdapter[] {
|
|
444
|
+
return Array.from(adapters.values());
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Get adapter by platform type
|
|
449
|
+
*/
|
|
450
|
+
export function getAdapterByPlatform(platform: Platform): PlatformAdapter | undefined {
|
|
451
|
+
const idMap: Record<Platform, string> = {
|
|
452
|
+
opencode: 'opencode',
|
|
453
|
+
claude: 'claude',
|
|
454
|
+
vscode: 'vscode',
|
|
455
|
+
cursor: 'opencode', // Cursor uses OpenCode-compatible structure
|
|
456
|
+
codex: 'opencode', // Codex uses OpenCode-compatible structure
|
|
457
|
+
antigravity: 'opencode', // Antigravity uses OpenCode-compatible structure
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
return adapters.get(idMap[platform]);
|
|
461
|
+
}
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
**Step 2: Commit**
|
|
465
|
+
|
|
466
|
+
```bash
|
|
467
|
+
git add src/adapters/registry.ts
|
|
468
|
+
git commit -m "feat: add platform registry and detection"
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
---
|
|
472
|
+
|
|
473
|
+
## Task 6: Update Install Command
|
|
474
|
+
|
|
475
|
+
**Files:**
|
|
476
|
+
- Modify: `src/commands/install.ts`
|
|
477
|
+
|
|
478
|
+
**Step 1: Update install command with platform support**
|
|
479
|
+
|
|
480
|
+
Modify `src/commands/install.ts`, add these imports and functions:
|
|
481
|
+
|
|
482
|
+
```typescript
|
|
483
|
+
// Add to imports
|
|
484
|
+
import { detectPlatforms, getAdapterByPlatform } from '../adapters/index.js';
|
|
485
|
+
import type { PlatformAdapter } from '../types.js';
|
|
486
|
+
import type { Platform } from '../constants.js';
|
|
487
|
+
|
|
488
|
+
// Add platform option parsing to installSkill function
|
|
489
|
+
export async function installSkill(
|
|
490
|
+
skillId: string,
|
|
491
|
+
version?: string,
|
|
492
|
+
options?: {
|
|
493
|
+
platforms?: string[];
|
|
494
|
+
force?: boolean;
|
|
495
|
+
}
|
|
496
|
+
): Promise<void> {
|
|
497
|
+
// ... existing code until step 3 ...
|
|
498
|
+
|
|
499
|
+
// ==========================================================================
|
|
500
|
+
// Step 4 (NEW): Determine target platforms
|
|
501
|
+
// ==========================================================================
|
|
502
|
+
|
|
503
|
+
let targetAdapters: PlatformAdapter[] = [];
|
|
504
|
+
|
|
505
|
+
if (options?.platforms && options.platforms.length > 0) {
|
|
506
|
+
// User specified platforms
|
|
507
|
+
for (const platformStr of options.platforms) {
|
|
508
|
+
const platform = platformStr as Platform;
|
|
509
|
+
const adapter = getAdapterByPlatform(platform);
|
|
510
|
+
if (adapter) {
|
|
511
|
+
targetAdapters.push(adapter);
|
|
512
|
+
} else {
|
|
513
|
+
console.warn(`⚠️ Unknown platform: ${platformStr}`);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
} else {
|
|
517
|
+
// Auto-detect available platforms
|
|
518
|
+
targetAdapters = await detectPlatforms();
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
if (targetAdapters.length === 0) {
|
|
522
|
+
console.log('No target platforms found.');
|
|
523
|
+
console.log('Use --platform to specify platforms manually.');
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
console.log(`\nInstalling to ${targetAdapters.length} platform(s)...\n`);
|
|
528
|
+
|
|
529
|
+
// ==========================================================================
|
|
530
|
+
// Step 5 (NEW): Install to each platform
|
|
531
|
+
// ==========================================================================
|
|
532
|
+
|
|
533
|
+
const results: { adapter: PlatformAdapter; status: 'installed' | 'skipped' | 'failed'; error?: string }[] = [];
|
|
534
|
+
|
|
535
|
+
for (const adapter of targetAdapters) {
|
|
536
|
+
try {
|
|
537
|
+
const isInstalled = await adapter.isInstalled(skillId);
|
|
538
|
+
|
|
539
|
+
if (isInstalled && !options?.force) {
|
|
540
|
+
console.log(`${adapter.name} ⚠️ Already installed (use --force to overwrite)`);
|
|
541
|
+
results.push({ adapter, status: 'skipped' });
|
|
542
|
+
continue;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
// Install skill
|
|
546
|
+
await adapter.install(skillId, skillVersionDir);
|
|
547
|
+
console.log(`${adapter.name} ✅ Installed successfully`);
|
|
548
|
+
results.push({ adapter, status: 'installed' });
|
|
549
|
+
} catch (error) {
|
|
550
|
+
console.log(`${adapter.name} ❌ Failed: ${error}`);
|
|
551
|
+
results.push({ adapter, status: 'failed', error: String(error) });
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
// ==========================================================================
|
|
556
|
+
// Step 6 (NEW): Display summary
|
|
557
|
+
// ==========================================================================
|
|
558
|
+
|
|
559
|
+
const installed = results.filter(r => r.status === 'installed').length;
|
|
560
|
+
const skipped = results.filter(r => r.status === 'skipped').length;
|
|
561
|
+
const failed = results.filter(r => r.status === 'failed').length;
|
|
562
|
+
|
|
563
|
+
console.log(`\n📊 Summary: ${installed} installed, ${skipped} skipped, ${failed} failed`);
|
|
564
|
+
}
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
**Step 2: Commit**
|
|
568
|
+
|
|
569
|
+
```bash
|
|
570
|
+
git add src/commands/install.ts
|
|
571
|
+
git commit -m "feat: add platform support to install command"
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
---
|
|
575
|
+
|
|
576
|
+
## Task 7: Update CLI Parser
|
|
577
|
+
|
|
578
|
+
**Files:**
|
|
579
|
+
- Modify: `src/cli.ts`
|
|
580
|
+
|
|
581
|
+
**Step 1: Update CLI to parse --platform flag**
|
|
582
|
+
|
|
583
|
+
Modify `src/cli.ts`, update the install command handler:
|
|
584
|
+
|
|
585
|
+
```typescript
|
|
586
|
+
// In the install command section, update the handler:
|
|
587
|
+
|
|
588
|
+
.command('install <skill>')
|
|
589
|
+
.description('Install a skill to local and/or platform directories')
|
|
590
|
+
.option('-p, --platform <platforms>', 'Target platforms (comma-separated: opencode,claude,vscode)')
|
|
591
|
+
.option('-f, --force', 'Overwrite if already installed')
|
|
592
|
+
.option('-v, --version <version>', 'Specific version to install')
|
|
593
|
+
.action(async (skill, options) => {
|
|
594
|
+
const platforms = options.platform
|
|
595
|
+
? options.platform.split(',').map(p => p.trim())
|
|
596
|
+
: undefined;
|
|
597
|
+
|
|
598
|
+
await installSkill(skill, options.version, {
|
|
599
|
+
platforms,
|
|
600
|
+
force: options.force
|
|
601
|
+
});
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
// Also add new platforms command
|
|
605
|
+
.command('platforms', 'Show available platforms')
|
|
606
|
+
.action(async () => {
|
|
607
|
+
const { detectPlatforms } = await import('./adapters/index.js');
|
|
608
|
+
const adapters = await detectPlatforms();
|
|
609
|
+
|
|
610
|
+
console.log('\n📍 Available Platforms:\n');
|
|
611
|
+
|
|
612
|
+
const { OpenCodeAdapter, ClaudeAdapter, VSCodeAdapter } = await import('./adapters/index.js');
|
|
613
|
+
|
|
614
|
+
const allPlatforms = [
|
|
615
|
+
{ name: 'OpenCode', adapter: new OpenCodeAdapter() },
|
|
616
|
+
{ name: 'Claude Code', adapter: new ClaudeAdapter() },
|
|
617
|
+
{ name: 'VSCode', adapter: new VSCodeAdapter() },
|
|
618
|
+
];
|
|
619
|
+
|
|
620
|
+
for (const { name, adapter } of allPlatforms) {
|
|
621
|
+
const available = adapters.find(a => a.id === adapter.id);
|
|
622
|
+
const installed = await adapter.listInstalled();
|
|
623
|
+
|
|
624
|
+
if (available) {
|
|
625
|
+
console.log(`${name.padEnd(12)} ✅ Available (${installed.length} skills installed)`);
|
|
626
|
+
} else {
|
|
627
|
+
console.log(`${name.padEnd(12)} ❌ Not detected`);
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
console.log('');
|
|
632
|
+
});
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
**Step 2: Commit**
|
|
636
|
+
|
|
637
|
+
```bash
|
|
638
|
+
git add src/cli.ts
|
|
639
|
+
git commit -m "feat: add --platform flag and platforms command"
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
---
|
|
643
|
+
|
|
644
|
+
## Task 8: Update Uninstall Command
|
|
645
|
+
|
|
646
|
+
**Files:**
|
|
647
|
+
- Modify: `src/commands/uninstall.ts`
|
|
648
|
+
|
|
649
|
+
**Step 1: Update uninstall to support platforms**
|
|
650
|
+
|
|
651
|
+
Modify `src/commands/uninstall.ts`:
|
|
652
|
+
|
|
653
|
+
```typescript
|
|
654
|
+
// Add platform support to uninstall
|
|
655
|
+
|
|
656
|
+
import { detectPlatforms, getAdapterByPlatform } from '../adapters/index.js';
|
|
657
|
+
import type { Platform } from '../constants.js';
|
|
658
|
+
|
|
659
|
+
export async function uninstallSkill(
|
|
660
|
+
skillId: string,
|
|
661
|
+
options?: {
|
|
662
|
+
platforms?: string[];
|
|
663
|
+
}
|
|
664
|
+
): Promise<void> {
|
|
665
|
+
// ... existing registry code ...
|
|
666
|
+
|
|
667
|
+
let targetAdapters = options?.platforms
|
|
668
|
+
? options.platforms.map(p => getAdapterByPlatform(p as Platform)).filter(Boolean)
|
|
669
|
+
: await detectPlatforms();
|
|
670
|
+
|
|
671
|
+
console.log(`\nUninstalling from ${targetAdapters.length} platform(s)...\n`);
|
|
672
|
+
|
|
673
|
+
for (const adapter of targetAdapters) {
|
|
674
|
+
if (!adapter) continue;
|
|
675
|
+
|
|
676
|
+
try {
|
|
677
|
+
await adapter.uninstall(skillId);
|
|
678
|
+
console.log(`${adapter.name} ✅ Uninstalled`);
|
|
679
|
+
} catch (error) {
|
|
680
|
+
console.log(`${adapter.name} ❌ Failed: ${error}`);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
// ... rest of existing code ...
|
|
685
|
+
}
|
|
686
|
+
```
|
|
687
|
+
|
|
688
|
+
**Step 2: Update CLI to pass platform option**
|
|
689
|
+
|
|
690
|
+
Update `src/cli.ts` uninstall handler to pass platforms:
|
|
691
|
+
|
|
692
|
+
```typescript
|
|
693
|
+
.option('-p, --platform <platforms>', 'Target platforms (comma-separated)')
|
|
694
|
+
.action(async (skill, options) => {
|
|
695
|
+
const platforms = options.platform
|
|
696
|
+
? options.platform.split(',').map(p => p.trim())
|
|
697
|
+
: undefined;
|
|
698
|
+
|
|
699
|
+
await uninstallSkill(skill, { platforms });
|
|
700
|
+
});
|
|
701
|
+
```
|
|
702
|
+
|
|
703
|
+
**Step 3: Commit**
|
|
704
|
+
|
|
705
|
+
```bash
|
|
706
|
+
git add src/commands/uninstall.ts src/cli.ts
|
|
707
|
+
git commit -m "feat: add platform support to uninstall command"
|
|
708
|
+
```
|
|
709
|
+
|
|
710
|
+
---
|
|
711
|
+
|
|
712
|
+
## Task 9: Build and Test
|
|
713
|
+
|
|
714
|
+
**Step 1: Build the project**
|
|
715
|
+
|
|
716
|
+
```bash
|
|
717
|
+
npm run build
|
|
718
|
+
```
|
|
719
|
+
|
|
720
|
+
**Step 2: Test platform detection**
|
|
721
|
+
|
|
722
|
+
```bash
|
|
723
|
+
npx skillmarket platforms
|
|
724
|
+
```
|
|
725
|
+
|
|
726
|
+
Expected output:
|
|
727
|
+
```
|
|
728
|
+
📍 Available Platforms:
|
|
729
|
+
|
|
730
|
+
OpenCode ✅ Available (X skills installed)
|
|
731
|
+
Claude Code ✅/❌ Available/Not detected
|
|
732
|
+
VSCode ✅/❌ Available/Not detected
|
|
733
|
+
```
|
|
734
|
+
|
|
735
|
+
**Step 3: Test install with platform flag**
|
|
736
|
+
|
|
737
|
+
```bash
|
|
738
|
+
# Test install to specific platform
|
|
739
|
+
npx skillmarket install test-skill --platform opencode
|
|
740
|
+
|
|
741
|
+
# Test install to all platforms
|
|
742
|
+
npx skillmarket install test-skill
|
|
743
|
+
```
|
|
744
|
+
|
|
745
|
+
**Step 4: Test uninstall**
|
|
746
|
+
|
|
747
|
+
```bash
|
|
748
|
+
npx skillmarket uninstall test-skill --platform opencode
|
|
749
|
+
```
|
|
750
|
+
|
|
751
|
+
---
|
|
752
|
+
|
|
753
|
+
## Task 10: Update Documentation
|
|
754
|
+
|
|
755
|
+
**Files:**
|
|
756
|
+
- Modify: `README.md`
|
|
757
|
+
- Create: `docs/CROSS-PLATFORM.md`
|
|
758
|
+
|
|
759
|
+
**Step 1: Update README with new commands**
|
|
760
|
+
|
|
761
|
+
Add to README.md:
|
|
762
|
+
|
|
763
|
+
```markdown
|
|
764
|
+
## Cross-Platform Installation
|
|
765
|
+
|
|
766
|
+
Install skills to multiple AI coding platforms with one command:
|
|
767
|
+
|
|
768
|
+
```bash
|
|
769
|
+
# Install to all detected platforms
|
|
770
|
+
skm install brainstorming
|
|
771
|
+
|
|
772
|
+
# Install to specific platform
|
|
773
|
+
skm install brainstorming --platform opencode
|
|
774
|
+
|
|
775
|
+
# Install to multiple platforms
|
|
776
|
+
skm install brainstorming --platform opencode,claude,vscode
|
|
777
|
+
|
|
778
|
+
# Show available platforms
|
|
779
|
+
skm platforms
|
|
780
|
+
```
|
|
781
|
+
```
|
|
782
|
+
|
|
783
|
+
**Step 2: Create cross-platform guide**
|
|
784
|
+
|
|
785
|
+
Create `docs/CROSS-PLATFORM.md` with detailed documentation.
|
|
786
|
+
|
|
787
|
+
**Step 3: Commit**
|
|
788
|
+
|
|
789
|
+
```bash
|
|
790
|
+
git add README.md docs/CROSS-PLATFORM.md
|
|
791
|
+
git commit -m "docs: add cross-platform installation guide"
|
|
792
|
+
```
|
|
793
|
+
|
|
794
|
+
---
|
|
795
|
+
|
|
796
|
+
## Task 11: Final Verification and Push
|
|
797
|
+
|
|
798
|
+
**Step 1: Run full build**
|
|
799
|
+
|
|
800
|
+
```bash
|
|
801
|
+
npm run build && npm run test
|
|
802
|
+
```
|
|
803
|
+
|
|
804
|
+
**Step 2: Check git status**
|
|
805
|
+
|
|
806
|
+
```bash
|
|
807
|
+
git status
|
|
808
|
+
```
|
|
809
|
+
|
|
810
|
+
**Step 3: Push to GitHub**
|
|
811
|
+
|
|
812
|
+
```bash
|
|
813
|
+
git push
|
|
814
|
+
```
|
|
815
|
+
|
|
816
|
+
---
|
|
817
|
+
|
|
818
|
+
## Summary of Changes
|
|
819
|
+
|
|
820
|
+
| Task | Files | Description |
|
|
821
|
+
|------|-------|-------------|
|
|
822
|
+
| 1 | `src/adapters/base.ts`, `src/types.ts` | Base adapter class |
|
|
823
|
+
| 2 | `src/adapters/opencode.ts` | OpenCode adapter |
|
|
824
|
+
| 3 | `src/adapters/claude.ts` | Claude Code adapter |
|
|
825
|
+
| 4 | `src/adapters/vscode.ts` | VSCode adapter |
|
|
826
|
+
| 5 | `src/adapters/registry.ts`, `src/adapters/index.ts` | Registry and detection |
|
|
827
|
+
| 6 | `src/commands/install.ts` | Enhanced install with platform support |
|
|
828
|
+
| 7 | `src/cli.ts` | CLI parser updates |
|
|
829
|
+
| 8 | `src/commands/uninstall.ts` | Enhanced uninstall with platform support |
|
|
830
|
+
| 9 | - | Build and test |
|
|
831
|
+
| 10 | `README.md`, `docs/CROSS-PLATFORM.md` | Documentation |
|
|
832
|
+
|
|
833
|
+
**Total: ~11 tasks, estimated 2-3 hours**
|