@nimblebrain/mpak 0.1.0 → 0.3.0
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/README.md +50 -383
- package/dist/index.d.ts +0 -2
- package/dist/index.js +2117 -4
- package/dist/index.js.map +1 -1
- package/package.json +26 -23
- package/.claude/settings.local.json +0 -19
- package/.env.example +0 -13
- package/.github/workflows/ci.yml +0 -27
- package/CLAUDE.md +0 -283
- package/LICENSE +0 -201
- package/dist/commands/config.d.ts +0 -31
- package/dist/commands/config.d.ts.map +0 -1
- package/dist/commands/config.js +0 -129
- package/dist/commands/config.js.map +0 -1
- package/dist/commands/packages/pull.d.ts +0 -11
- package/dist/commands/packages/pull.d.ts.map +0 -1
- package/dist/commands/packages/pull.js +0 -72
- package/dist/commands/packages/pull.js.map +0 -1
- package/dist/commands/packages/run.d.ts +0 -47
- package/dist/commands/packages/run.d.ts.map +0 -1
- package/dist/commands/packages/run.js +0 -419
- package/dist/commands/packages/run.js.map +0 -1
- package/dist/commands/packages/search.d.ts +0 -12
- package/dist/commands/packages/search.d.ts.map +0 -1
- package/dist/commands/packages/search.js +0 -63
- package/dist/commands/packages/search.js.map +0 -1
- package/dist/commands/packages/show.d.ts +0 -8
- package/dist/commands/packages/show.d.ts.map +0 -1
- package/dist/commands/packages/show.js +0 -109
- package/dist/commands/packages/show.js.map +0 -1
- package/dist/commands/search.d.ts +0 -12
- package/dist/commands/search.d.ts.map +0 -1
- package/dist/commands/search.js +0 -144
- package/dist/commands/search.js.map +0 -1
- package/dist/commands/skills/index.d.ts +0 -8
- package/dist/commands/skills/index.d.ts.map +0 -1
- package/dist/commands/skills/index.js +0 -8
- package/dist/commands/skills/index.js.map +0 -1
- package/dist/commands/skills/install.d.ts +0 -9
- package/dist/commands/skills/install.d.ts.map +0 -1
- package/dist/commands/skills/install.js +0 -110
- package/dist/commands/skills/install.js.map +0 -1
- package/dist/commands/skills/list.d.ts +0 -8
- package/dist/commands/skills/list.d.ts.map +0 -1
- package/dist/commands/skills/list.js +0 -89
- package/dist/commands/skills/list.js.map +0 -1
- package/dist/commands/skills/pack.d.ts +0 -22
- package/dist/commands/skills/pack.d.ts.map +0 -1
- package/dist/commands/skills/pack.js +0 -116
- package/dist/commands/skills/pack.js.map +0 -1
- package/dist/commands/skills/pull.d.ts +0 -9
- package/dist/commands/skills/pull.d.ts.map +0 -1
- package/dist/commands/skills/pull.js +0 -68
- package/dist/commands/skills/pull.js.map +0 -1
- package/dist/commands/skills/search.d.ts +0 -14
- package/dist/commands/skills/search.d.ts.map +0 -1
- package/dist/commands/skills/search.js +0 -53
- package/dist/commands/skills/search.js.map +0 -1
- package/dist/commands/skills/show.d.ts +0 -8
- package/dist/commands/skills/show.d.ts.map +0 -1
- package/dist/commands/skills/show.js +0 -64
- package/dist/commands/skills/show.js.map +0 -1
- package/dist/commands/skills/validate.d.ts +0 -25
- package/dist/commands/skills/validate.d.ts.map +0 -1
- package/dist/commands/skills/validate.js +0 -191
- package/dist/commands/skills/validate.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/lib/api/registry-client.d.ts +0 -63
- package/dist/lib/api/registry-client.d.ts.map +0 -1
- package/dist/lib/api/registry-client.js +0 -167
- package/dist/lib/api/registry-client.js.map +0 -1
- package/dist/lib/api/skills-client.d.ts +0 -30
- package/dist/lib/api/skills-client.d.ts.map +0 -1
- package/dist/lib/api/skills-client.js +0 -110
- package/dist/lib/api/skills-client.js.map +0 -1
- package/dist/program.d.ts +0 -12
- package/dist/program.d.ts.map +0 -1
- package/dist/program.js +0 -186
- package/dist/program.js.map +0 -1
- package/dist/schemas/generated/api-responses.d.ts +0 -541
- package/dist/schemas/generated/api-responses.d.ts.map +0 -1
- package/dist/schemas/generated/api-responses.js +0 -313
- package/dist/schemas/generated/api-responses.js.map +0 -1
- package/dist/schemas/generated/auth.d.ts +0 -18
- package/dist/schemas/generated/auth.d.ts.map +0 -1
- package/dist/schemas/generated/auth.js +0 -18
- package/dist/schemas/generated/auth.js.map +0 -1
- package/dist/schemas/generated/index.d.ts +0 -5
- package/dist/schemas/generated/index.d.ts.map +0 -1
- package/dist/schemas/generated/index.js +0 -6
- package/dist/schemas/generated/index.js.map +0 -1
- package/dist/schemas/generated/package.d.ts +0 -43
- package/dist/schemas/generated/package.d.ts.map +0 -1
- package/dist/schemas/generated/package.js +0 -20
- package/dist/schemas/generated/package.js.map +0 -1
- package/dist/schemas/generated/skill.d.ts +0 -381
- package/dist/schemas/generated/skill.d.ts.map +0 -1
- package/dist/schemas/generated/skill.js +0 -216
- package/dist/schemas/generated/skill.js.map +0 -1
- package/dist/utils/config-manager.d.ts +0 -66
- package/dist/utils/config-manager.d.ts.map +0 -1
- package/dist/utils/config-manager.js +0 -193
- package/dist/utils/config-manager.js.map +0 -1
- package/dist/utils/errors.d.ts +0 -12
- package/dist/utils/errors.d.ts.map +0 -1
- package/dist/utils/errors.js +0 -27
- package/dist/utils/errors.js.map +0 -1
- package/dist/utils/version.d.ts +0 -5
- package/dist/utils/version.d.ts.map +0 -1
- package/dist/utils/version.js +0 -19
- package/dist/utils/version.js.map +0 -1
- package/eslint.config.js +0 -63
- package/src/commands/config.ts +0 -162
- package/src/commands/packages/pull.ts +0 -96
- package/src/commands/packages/run.test.ts +0 -261
- package/src/commands/packages/run.ts +0 -536
- package/src/commands/packages/search.ts +0 -83
- package/src/commands/packages/show.ts +0 -128
- package/src/commands/search.ts +0 -191
- package/src/commands/skills/index.ts +0 -7
- package/src/commands/skills/install.ts +0 -129
- package/src/commands/skills/list.ts +0 -116
- package/src/commands/skills/pack.test.ts +0 -260
- package/src/commands/skills/pack.ts +0 -145
- package/src/commands/skills/pull.ts +0 -88
- package/src/commands/skills/search.ts +0 -73
- package/src/commands/skills/show.ts +0 -72
- package/src/commands/skills/validate.test.ts +0 -466
- package/src/commands/skills/validate.ts +0 -227
- package/src/index.ts +0 -11
- package/src/lib/api/registry-client.ts +0 -223
- package/src/lib/api/schema.d.ts +0 -520
- package/src/lib/api/skills-client.ts +0 -148
- package/src/program.test.ts +0 -22
- package/src/program.ts +0 -226
- package/src/schemas/config.v1.schema.json +0 -37
- package/src/schemas/generated/api-responses.ts +0 -386
- package/src/schemas/generated/auth.ts +0 -21
- package/src/schemas/generated/index.ts +0 -5
- package/src/schemas/generated/package.ts +0 -29
- package/src/schemas/generated/skill.ts +0 -271
- package/src/utils/config-manager.test.ts +0 -330
- package/src/utils/config-manager.ts +0 -272
- package/src/utils/errors.test.ts +0 -25
- package/src/utils/errors.ts +0 -33
- package/src/utils/version.test.ts +0 -16
- package/src/utils/version.ts +0 -18
- package/test/integration/registry-client.test.ts +0 -180
- package/tsconfig.check.json +0 -9
- package/tsconfig.json +0 -25
- package/vitest.config.ts +0 -14
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
import { RegistryClient } from '../../lib/api/registry-client.js';
|
|
2
|
-
|
|
3
|
-
export interface ShowOptions {
|
|
4
|
-
json?: boolean;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Show detailed information about a bundle (v1 API)
|
|
9
|
-
*/
|
|
10
|
-
export async function handleShow(
|
|
11
|
-
packageName: string,
|
|
12
|
-
options: ShowOptions = {}
|
|
13
|
-
): Promise<void> {
|
|
14
|
-
try {
|
|
15
|
-
const client = new RegistryClient();
|
|
16
|
-
|
|
17
|
-
// Fetch bundle details and versions in parallel
|
|
18
|
-
const [bundle, versionsInfo] = await Promise.all([
|
|
19
|
-
client.getBundle(packageName),
|
|
20
|
-
client.getVersions(packageName),
|
|
21
|
-
]);
|
|
22
|
-
|
|
23
|
-
if (options.json) {
|
|
24
|
-
console.log(JSON.stringify({ ...bundle, versions_detail: versionsInfo.versions }, null, 2));
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// Header
|
|
29
|
-
const verified = bundle.verified ? '✓ ' : '';
|
|
30
|
-
const provenance = bundle.provenance ? '🔒 ' : '';
|
|
31
|
-
console.log(`\n${verified}${provenance}${bundle.display_name || bundle.name} v${bundle.latest_version}\n`);
|
|
32
|
-
|
|
33
|
-
// Description
|
|
34
|
-
if (bundle.description) {
|
|
35
|
-
console.log(bundle.description);
|
|
36
|
-
console.log();
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Basic info
|
|
40
|
-
console.log('Bundle Information:');
|
|
41
|
-
console.log(` Name: ${bundle.name}`);
|
|
42
|
-
if (bundle.author?.name) {
|
|
43
|
-
console.log(` Author: ${bundle.author.name}`);
|
|
44
|
-
}
|
|
45
|
-
if (bundle.server_type) {
|
|
46
|
-
console.log(` Type: ${bundle.server_type}`);
|
|
47
|
-
}
|
|
48
|
-
if (bundle.license) {
|
|
49
|
-
console.log(` License: ${bundle.license}`);
|
|
50
|
-
}
|
|
51
|
-
if (bundle.homepage) {
|
|
52
|
-
console.log(` Homepage: ${bundle.homepage}`);
|
|
53
|
-
}
|
|
54
|
-
console.log();
|
|
55
|
-
|
|
56
|
-
// Provenance info
|
|
57
|
-
if (bundle.provenance) {
|
|
58
|
-
console.log('Provenance:');
|
|
59
|
-
console.log(` Repository: ${bundle.provenance.repository}`);
|
|
60
|
-
console.log(` Commit: ${bundle.provenance.sha.substring(0, 12)}`);
|
|
61
|
-
console.log(` Provider: ${bundle.provenance.provider}`);
|
|
62
|
-
console.log();
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// Stats
|
|
66
|
-
console.log('Statistics:');
|
|
67
|
-
console.log(` Downloads: ${bundle.downloads.toLocaleString()}`);
|
|
68
|
-
console.log(` Published: ${new Date(bundle.published_at as string).toLocaleDateString()}`);
|
|
69
|
-
console.log();
|
|
70
|
-
|
|
71
|
-
// Tools
|
|
72
|
-
if (bundle.tools && bundle.tools.length > 0) {
|
|
73
|
-
console.log(`Tools (${bundle.tools.length}):`);
|
|
74
|
-
for (const tool of bundle.tools) {
|
|
75
|
-
console.log(` - ${tool.name}`);
|
|
76
|
-
if (tool.description) {
|
|
77
|
-
console.log(` ${tool.description}`);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
console.log();
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Versions with platforms
|
|
84
|
-
if (versionsInfo.versions && versionsInfo.versions.length > 0) {
|
|
85
|
-
console.log(`Versions (${versionsInfo.versions.length}):`);
|
|
86
|
-
const recentVersions = versionsInfo.versions.slice(0, 5);
|
|
87
|
-
for (const version of recentVersions) {
|
|
88
|
-
const date = new Date(version.published_at as string).toLocaleDateString();
|
|
89
|
-
const downloads = version.downloads.toLocaleString();
|
|
90
|
-
const isLatest = version.version === versionsInfo.latest ? ' (latest)' : '';
|
|
91
|
-
const provTag = version.provenance ? ' 🔒' : '';
|
|
92
|
-
|
|
93
|
-
// Format platforms
|
|
94
|
-
const platformStrs = version.platforms.map((p) => `${p.os}-${p.arch}`);
|
|
95
|
-
const platformsDisplay = platformStrs.length > 0 ? ` [${platformStrs.join(', ')}]` : '';
|
|
96
|
-
|
|
97
|
-
console.log(` ${version.version}${isLatest}${provTag} - ${date} - ${downloads} downloads${platformsDisplay}`);
|
|
98
|
-
}
|
|
99
|
-
if (versionsInfo.versions.length > 5) {
|
|
100
|
-
console.log(` ... and ${versionsInfo.versions.length - 5} more`);
|
|
101
|
-
}
|
|
102
|
-
console.log();
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Available platforms for latest version
|
|
106
|
-
const latestVersion = versionsInfo.versions.find((v) => v.version === versionsInfo.latest);
|
|
107
|
-
if (latestVersion && latestVersion.platforms.length > 0) {
|
|
108
|
-
console.log('Available Platforms:');
|
|
109
|
-
for (const platform of latestVersion.platforms) {
|
|
110
|
-
console.log(` - ${platform.os}-${platform.arch}`);
|
|
111
|
-
}
|
|
112
|
-
console.log();
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// Install instructions
|
|
116
|
-
console.log('Install:');
|
|
117
|
-
console.log(` mpak install ${bundle.name}`);
|
|
118
|
-
console.log();
|
|
119
|
-
console.log('Pull (download only):');
|
|
120
|
-
console.log(` mpak pull ${bundle.name}`);
|
|
121
|
-
} catch (error) {
|
|
122
|
-
console.error('=> Failed to get bundle details');
|
|
123
|
-
if (error instanceof Error) {
|
|
124
|
-
console.error(` ${error.message}`);
|
|
125
|
-
}
|
|
126
|
-
process.exit(1);
|
|
127
|
-
}
|
|
128
|
-
}
|
package/src/commands/search.ts
DELETED
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
import { RegistryClient } from '../lib/api/registry-client.js';
|
|
2
|
-
import { searchSkills } from '../lib/api/skills-client.js';
|
|
3
|
-
|
|
4
|
-
export interface UnifiedSearchOptions {
|
|
5
|
-
type?: 'bundle' | 'skill';
|
|
6
|
-
sort?: 'downloads' | 'recent' | 'name';
|
|
7
|
-
limit?: number;
|
|
8
|
-
offset?: number;
|
|
9
|
-
json?: boolean;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
interface UnifiedResult {
|
|
13
|
-
type: 'bundle' | 'skill';
|
|
14
|
-
name: string;
|
|
15
|
-
description: string;
|
|
16
|
-
downloads: number;
|
|
17
|
-
version: string;
|
|
18
|
-
author?: string;
|
|
19
|
-
// Bundle-specific
|
|
20
|
-
serverType?: string;
|
|
21
|
-
verified?: boolean;
|
|
22
|
-
provenance?: boolean;
|
|
23
|
-
// Skill-specific
|
|
24
|
-
category?: string;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Unified search across bundles and skills
|
|
29
|
-
*/
|
|
30
|
-
export async function handleUnifiedSearch(
|
|
31
|
-
query: string,
|
|
32
|
-
options: UnifiedSearchOptions = {}
|
|
33
|
-
): Promise<void> {
|
|
34
|
-
try {
|
|
35
|
-
const results: UnifiedResult[] = [];
|
|
36
|
-
let bundleTotal = 0;
|
|
37
|
-
let skillTotal = 0;
|
|
38
|
-
|
|
39
|
-
// Search both in parallel (unless filtered by type)
|
|
40
|
-
const searchBundles = !options.type || options.type === 'bundle';
|
|
41
|
-
const searchSkillsFlag = !options.type || options.type === 'skill';
|
|
42
|
-
|
|
43
|
-
const [bundleResult, skillResult] = await Promise.all([
|
|
44
|
-
searchBundles
|
|
45
|
-
? new RegistryClient().searchBundles(query, {
|
|
46
|
-
sort: options.sort,
|
|
47
|
-
limit: options.limit,
|
|
48
|
-
offset: options.offset,
|
|
49
|
-
})
|
|
50
|
-
: null,
|
|
51
|
-
searchSkillsFlag
|
|
52
|
-
? searchSkills({
|
|
53
|
-
q: query,
|
|
54
|
-
sort: options.sort as any,
|
|
55
|
-
limit: options.limit,
|
|
56
|
-
offset: options.offset,
|
|
57
|
-
}).catch(() => null) // Skills API may not be deployed yet
|
|
58
|
-
: null,
|
|
59
|
-
]);
|
|
60
|
-
|
|
61
|
-
// Process bundle results
|
|
62
|
-
if (bundleResult) {
|
|
63
|
-
bundleTotal = bundleResult.total;
|
|
64
|
-
for (const bundle of bundleResult.bundles) {
|
|
65
|
-
results.push({
|
|
66
|
-
type: 'bundle',
|
|
67
|
-
name: bundle.name,
|
|
68
|
-
description: bundle.description || '',
|
|
69
|
-
downloads: bundle.downloads || 0,
|
|
70
|
-
version: bundle.latest_version,
|
|
71
|
-
author: bundle.author?.name || undefined,
|
|
72
|
-
serverType: bundle.server_type || undefined,
|
|
73
|
-
verified: bundle.verified,
|
|
74
|
-
provenance: !!bundle.provenance,
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// Process skill results
|
|
80
|
-
if (skillResult) {
|
|
81
|
-
skillTotal = skillResult.total;
|
|
82
|
-
for (const skill of skillResult.skills) {
|
|
83
|
-
results.push({
|
|
84
|
-
type: 'skill',
|
|
85
|
-
name: skill.name,
|
|
86
|
-
description: skill.description || '',
|
|
87
|
-
downloads: skill.downloads || 0,
|
|
88
|
-
version: skill.latest_version,
|
|
89
|
-
author: skill.author?.name || undefined,
|
|
90
|
-
category: skill.category || undefined,
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Sort combined results
|
|
96
|
-
if (options.sort === 'downloads') {
|
|
97
|
-
results.sort((a, b) => b.downloads - a.downloads);
|
|
98
|
-
} else if (options.sort === 'name') {
|
|
99
|
-
results.sort((a, b) => a.name.localeCompare(b.name));
|
|
100
|
-
}
|
|
101
|
-
// 'recent' sorting would require timestamps, skip for now
|
|
102
|
-
|
|
103
|
-
// JSON output
|
|
104
|
-
if (options.json) {
|
|
105
|
-
console.log(
|
|
106
|
-
JSON.stringify(
|
|
107
|
-
{
|
|
108
|
-
results,
|
|
109
|
-
totals: { bundles: bundleTotal, skills: skillTotal },
|
|
110
|
-
},
|
|
111
|
-
null,
|
|
112
|
-
2
|
|
113
|
-
)
|
|
114
|
-
);
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// No results
|
|
119
|
-
if (results.length === 0) {
|
|
120
|
-
console.log(`\nNo results found for "${query}"`);
|
|
121
|
-
if (!searchBundles) console.log(' (searched skills only)');
|
|
122
|
-
if (!searchSkillsFlag) console.log(' (searched bundles only)');
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// Summary
|
|
127
|
-
const totalResults = bundleTotal + skillTotal;
|
|
128
|
-
const typeFilter = options.type ? ` (${options.type}s only)` : '';
|
|
129
|
-
console.log(`\nFound ${totalResults} result(s) for "${query}"${typeFilter}:\n`);
|
|
130
|
-
|
|
131
|
-
// Table header
|
|
132
|
-
const typeWidth = 10;
|
|
133
|
-
const nameWidth = 38;
|
|
134
|
-
const versionWidth = 12;
|
|
135
|
-
const downloadsWidth = 10;
|
|
136
|
-
|
|
137
|
-
console.log(
|
|
138
|
-
'TYPE'.padEnd(typeWidth) +
|
|
139
|
-
'NAME'.padEnd(nameWidth) +
|
|
140
|
-
'VERSION'.padEnd(versionWidth) +
|
|
141
|
-
'DOWNLOADS'.padStart(downloadsWidth)
|
|
142
|
-
);
|
|
143
|
-
|
|
144
|
-
// Table rows
|
|
145
|
-
for (const result of results) {
|
|
146
|
-
const typeLabel = result.type === 'bundle' ? 'bundle' : 'skill';
|
|
147
|
-
const name =
|
|
148
|
-
result.name.length > nameWidth - 2
|
|
149
|
-
? result.name.slice(0, nameWidth - 5) + '...'
|
|
150
|
-
: result.name;
|
|
151
|
-
const version = result.version || '-';
|
|
152
|
-
const downloads = result.downloads.toLocaleString();
|
|
153
|
-
|
|
154
|
-
console.log(
|
|
155
|
-
typeLabel.padEnd(typeWidth) +
|
|
156
|
-
name.padEnd(nameWidth) +
|
|
157
|
-
version.padEnd(versionWidth) +
|
|
158
|
-
downloads.padStart(downloadsWidth)
|
|
159
|
-
);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
console.log('');
|
|
163
|
-
|
|
164
|
-
// Show breakdown
|
|
165
|
-
if (!options.type) {
|
|
166
|
-
const parts = [];
|
|
167
|
-
if (bundleTotal > 0) parts.push(`${bundleTotal} bundle(s)`);
|
|
168
|
-
if (skillTotal > 0) parts.push(`${skillTotal} skill(s)`);
|
|
169
|
-
if (parts.length > 1) {
|
|
170
|
-
console.log(` ${parts.join(', ')}`);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// Pagination hint
|
|
175
|
-
const currentLimit = options.limit || 20;
|
|
176
|
-
const currentOffset = options.offset || 0;
|
|
177
|
-
if (bundleTotal + skillTotal > currentOffset + results.length) {
|
|
178
|
-
console.log(` Use --offset ${currentOffset + currentLimit} to see more results.`);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// Hint for more details
|
|
182
|
-
console.log('');
|
|
183
|
-
console.log('Use "mpak bundle show <name>" or "mpak skill show <name>" for details.');
|
|
184
|
-
} catch (error) {
|
|
185
|
-
console.error('Search failed');
|
|
186
|
-
if (error instanceof Error) {
|
|
187
|
-
console.error(` ${error.message}`);
|
|
188
|
-
}
|
|
189
|
-
process.exit(1);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
export { handleSkillValidate, validateSkillDirectory } from './validate.js';
|
|
2
|
-
export { handleSkillPack, packSkill } from './pack.js';
|
|
3
|
-
export { handleSkillSearch } from './search.js';
|
|
4
|
-
export { handleSkillShow } from './show.js';
|
|
5
|
-
export { handleSkillPull } from './pull.js';
|
|
6
|
-
export { handleSkillInstall } from './install.js';
|
|
7
|
-
export { handleSkillList } from './list.js';
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, writeFileSync, rmSync } from 'fs';
|
|
2
|
-
import { join, basename } from 'path';
|
|
3
|
-
import { homedir, tmpdir } from 'os';
|
|
4
|
-
import { getSkillDownloadInfo, downloadSkillBundle } from '../../lib/api/skills-client.js';
|
|
5
|
-
import { execSync } from 'child_process';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Get the Claude Code skills directory
|
|
9
|
-
*/
|
|
10
|
-
function getSkillsDir(): string {
|
|
11
|
-
return join(homedir(), '.claude', 'skills');
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Parse skill spec into name and version
|
|
16
|
-
*/
|
|
17
|
-
function parseSkillSpec(spec: string): { name: string; version?: string } {
|
|
18
|
-
const atIndex = spec.lastIndexOf('@');
|
|
19
|
-
if (atIndex <= 0) {
|
|
20
|
-
return { name: spec };
|
|
21
|
-
}
|
|
22
|
-
const slashIndex = spec.indexOf('/');
|
|
23
|
-
if (atIndex > slashIndex) {
|
|
24
|
-
return {
|
|
25
|
-
name: spec.slice(0, atIndex),
|
|
26
|
-
version: spec.slice(atIndex + 1),
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
return { name: spec };
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Extract skill name from scoped name
|
|
34
|
-
* @scope/skill-name -> skill-name
|
|
35
|
-
*/
|
|
36
|
-
function getShortName(scopedName: string): string {
|
|
37
|
-
const parts = scopedName.replace('@', '').split('/');
|
|
38
|
-
return parts[parts.length - 1];
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export interface InstallOptions {
|
|
42
|
-
force?: boolean;
|
|
43
|
-
json?: boolean;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Handle the skill install command
|
|
48
|
-
*/
|
|
49
|
-
export async function handleSkillInstall(skillSpec: string, options: InstallOptions): Promise<void> {
|
|
50
|
-
try {
|
|
51
|
-
const { name, version } = parseSkillSpec(skillSpec);
|
|
52
|
-
|
|
53
|
-
// Get download info
|
|
54
|
-
const downloadInfo = await getSkillDownloadInfo(name, version);
|
|
55
|
-
const shortName = getShortName(downloadInfo.skill.name);
|
|
56
|
-
const skillsDir = getSkillsDir();
|
|
57
|
-
const installPath = join(skillsDir, shortName);
|
|
58
|
-
|
|
59
|
-
// Check if already installed
|
|
60
|
-
if (existsSync(installPath) && !options.force) {
|
|
61
|
-
console.error(`Skill "${shortName}" is already installed at ${installPath}`);
|
|
62
|
-
console.error('Use --force to overwrite');
|
|
63
|
-
process.exit(1);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
console.log(`Pulling ${downloadInfo.skill.name}@${downloadInfo.skill.version}...`);
|
|
67
|
-
|
|
68
|
-
// Download the bundle
|
|
69
|
-
const buffer = await downloadSkillBundle(downloadInfo.url, downloadInfo.skill.sha256);
|
|
70
|
-
|
|
71
|
-
console.log(`Downloaded ${basename(downloadInfo.skill.name)}-${downloadInfo.skill.version}.skill (${formatSize(downloadInfo.skill.size)})`);
|
|
72
|
-
|
|
73
|
-
// Ensure skills directory exists
|
|
74
|
-
if (!existsSync(skillsDir)) {
|
|
75
|
-
mkdirSync(skillsDir, { recursive: true });
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Write to temp file
|
|
79
|
-
const tempPath = join(tmpdir(), `skill-${Date.now()}.skill`);
|
|
80
|
-
writeFileSync(tempPath, buffer);
|
|
81
|
-
|
|
82
|
-
// Remove existing installation if force
|
|
83
|
-
if (existsSync(installPath)) {
|
|
84
|
-
rmSync(installPath, { recursive: true });
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// Extract using unzip
|
|
88
|
-
// The .skill bundle contains: skillName/SKILL.md, skillName/...
|
|
89
|
-
// We extract to the skills directory
|
|
90
|
-
try {
|
|
91
|
-
execSync(`unzip -o "${tempPath}" -d "${skillsDir}"`, { stdio: 'pipe' });
|
|
92
|
-
} catch (err) {
|
|
93
|
-
throw new Error(`Failed to extract skill bundle: ${err}`);
|
|
94
|
-
} finally {
|
|
95
|
-
// Clean up temp file
|
|
96
|
-
rmSync(tempPath, { force: true });
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
if (options.json) {
|
|
100
|
-
console.log(
|
|
101
|
-
JSON.stringify(
|
|
102
|
-
{
|
|
103
|
-
installed: true,
|
|
104
|
-
name: downloadInfo.skill.name,
|
|
105
|
-
shortName,
|
|
106
|
-
version: downloadInfo.skill.version,
|
|
107
|
-
path: installPath,
|
|
108
|
-
},
|
|
109
|
-
null,
|
|
110
|
-
2
|
|
111
|
-
)
|
|
112
|
-
);
|
|
113
|
-
} else {
|
|
114
|
-
console.log(`Extracting to ${installPath}/`);
|
|
115
|
-
console.log(`\u2713 Installed: ${shortName}`);
|
|
116
|
-
console.log('');
|
|
117
|
-
console.log('Skill available in Claude Code. Restart to activate.');
|
|
118
|
-
}
|
|
119
|
-
} catch (err) {
|
|
120
|
-
console.error(`Error: ${err instanceof Error ? err.message : err}`);
|
|
121
|
-
process.exit(1);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function formatSize(bytes: number): string {
|
|
126
|
-
if (bytes < 1024) return `${bytes} B`;
|
|
127
|
-
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
128
|
-
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
129
|
-
}
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import { existsSync, readdirSync, readFileSync, statSync } from 'fs';
|
|
2
|
-
import { join } from 'path';
|
|
3
|
-
import { homedir } from 'os';
|
|
4
|
-
import matter from 'gray-matter';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Get the Claude Code skills directory
|
|
8
|
-
*/
|
|
9
|
-
function getSkillsDir(): string {
|
|
10
|
-
return join(homedir(), '.claude', 'skills');
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
interface InstalledSkill {
|
|
14
|
-
name: string;
|
|
15
|
-
description: string;
|
|
16
|
-
version: string | null;
|
|
17
|
-
path: string;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* List all installed skills
|
|
22
|
-
*/
|
|
23
|
-
function listInstalledSkills(): InstalledSkill[] {
|
|
24
|
-
const skillsDir = getSkillsDir();
|
|
25
|
-
|
|
26
|
-
if (!existsSync(skillsDir)) {
|
|
27
|
-
return [];
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const skills: InstalledSkill[] = [];
|
|
31
|
-
const entries = readdirSync(skillsDir);
|
|
32
|
-
|
|
33
|
-
for (const entry of entries) {
|
|
34
|
-
// Skip hidden files
|
|
35
|
-
if (entry.startsWith('.')) continue;
|
|
36
|
-
|
|
37
|
-
const skillPath = join(skillsDir, entry);
|
|
38
|
-
const stat = statSync(skillPath);
|
|
39
|
-
|
|
40
|
-
if (!stat.isDirectory()) continue;
|
|
41
|
-
|
|
42
|
-
// Check for SKILL.md
|
|
43
|
-
const skillMdPath = join(skillPath, 'SKILL.md');
|
|
44
|
-
if (!existsSync(skillMdPath)) continue;
|
|
45
|
-
|
|
46
|
-
// Parse SKILL.md
|
|
47
|
-
try {
|
|
48
|
-
const content = readFileSync(skillMdPath, 'utf-8');
|
|
49
|
-
const parsed = matter(content);
|
|
50
|
-
|
|
51
|
-
skills.push({
|
|
52
|
-
name: parsed.data.name || entry,
|
|
53
|
-
description: parsed.data.description || '',
|
|
54
|
-
version: parsed.data.metadata?.version || null,
|
|
55
|
-
path: skillPath,
|
|
56
|
-
});
|
|
57
|
-
} catch {
|
|
58
|
-
// If we can't parse, still include with basic info
|
|
59
|
-
skills.push({
|
|
60
|
-
name: entry,
|
|
61
|
-
description: '(unable to parse SKILL.md)',
|
|
62
|
-
version: null,
|
|
63
|
-
path: skillPath,
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
return skills.sort((a, b) => a.name.localeCompare(b.name));
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export interface ListOptions {
|
|
72
|
-
json?: boolean;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Handle the skill list command
|
|
77
|
-
*/
|
|
78
|
-
export async function handleSkillList(options: ListOptions): Promise<void> {
|
|
79
|
-
const skills = listInstalledSkills();
|
|
80
|
-
|
|
81
|
-
if (options.json) {
|
|
82
|
-
console.log(JSON.stringify(skills, null, 2));
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (skills.length === 0) {
|
|
87
|
-
console.log('No skills installed.');
|
|
88
|
-
console.log('');
|
|
89
|
-
console.log('Install skills with: mpak skill install <name>');
|
|
90
|
-
console.log('Or create your own in ~/.claude/skills/');
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
console.log('');
|
|
95
|
-
console.log('Installed skills:');
|
|
96
|
-
console.log('');
|
|
97
|
-
|
|
98
|
-
const nameWidth = Math.max(20, ...skills.map((s) => s.name.length)) + 2;
|
|
99
|
-
const versionWidth = 10;
|
|
100
|
-
|
|
101
|
-
console.log('NAME'.padEnd(nameWidth) + 'VERSION'.padEnd(versionWidth) + 'DESCRIPTION');
|
|
102
|
-
|
|
103
|
-
for (const skill of skills) {
|
|
104
|
-
const name = skill.name.padEnd(nameWidth);
|
|
105
|
-
const version = (skill.version || '-').padEnd(versionWidth);
|
|
106
|
-
const desc =
|
|
107
|
-
skill.description.length > 50
|
|
108
|
-
? skill.description.slice(0, 47) + '...'
|
|
109
|
-
: skill.description;
|
|
110
|
-
|
|
111
|
-
console.log(name + version + desc);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
console.log('');
|
|
115
|
-
console.log(`${skills.length} skill(s) installed in ${getSkillsDir()}`);
|
|
116
|
-
}
|