@nimblebrain/mpak 0.0.2 → 0.2.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/LICENSE +10 -198
- package/README.md +50 -360
- package/dist/index.d.ts +0 -2
- package/dist/index.js +2113 -4
- package/dist/index.js.map +1 -1
- package/package.json +32 -29
- package/.claude/settings.local.json +0 -19
- package/.env.example +0 -13
- package/.github/workflows/ci.yml +0 -27
- package/CLAUDE.md +0 -271
- 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 -36
- package/dist/commands/packages/run.d.ts.map +0 -1
- package/dist/commands/packages/run.js +0 -348
- 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 -174
- 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 -222
- package/src/commands/packages/run.ts +0 -451
- 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 -212
- 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,260 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
import { mkdirSync, writeFileSync, rmSync, existsSync, readFileSync } from 'fs';
|
|
3
|
-
import { join, basename } from 'path';
|
|
4
|
-
import { tmpdir } from 'os';
|
|
5
|
-
import { packSkill } from './pack.js';
|
|
6
|
-
import { execSync } from 'child_process';
|
|
7
|
-
|
|
8
|
-
describe('packSkill', () => {
|
|
9
|
-
let testDir: string;
|
|
10
|
-
|
|
11
|
-
beforeEach(() => {
|
|
12
|
-
testDir = join(tmpdir(), `skill-pack-test-${Date.now()}`);
|
|
13
|
-
mkdirSync(testDir, { recursive: true });
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
afterEach(() => {
|
|
17
|
-
rmSync(testDir, { recursive: true, force: true });
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
describe('validation before packing', () => {
|
|
21
|
-
it('fails for invalid skill', async () => {
|
|
22
|
-
const skillDir = join(testDir, 'invalid-skill');
|
|
23
|
-
mkdirSync(skillDir);
|
|
24
|
-
// No SKILL.md
|
|
25
|
-
|
|
26
|
-
const result = await packSkill(skillDir);
|
|
27
|
-
expect(result.success).toBe(false);
|
|
28
|
-
expect(result.error).toContain('Validation failed');
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it('fails when name format is invalid', async () => {
|
|
32
|
-
const skillDir = join(testDir, 'BadName');
|
|
33
|
-
mkdirSync(skillDir);
|
|
34
|
-
writeFileSync(
|
|
35
|
-
join(skillDir, 'SKILL.md'),
|
|
36
|
-
`---
|
|
37
|
-
name: BadName
|
|
38
|
-
description: Invalid name
|
|
39
|
-
---
|
|
40
|
-
# Bad`
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
const result = await packSkill(skillDir);
|
|
44
|
-
expect(result.success).toBe(false);
|
|
45
|
-
expect(result.error).toContain('Validation failed');
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
describe('successful packing', () => {
|
|
50
|
-
it('creates a .skill bundle', async () => {
|
|
51
|
-
const skillDir = join(testDir, 'test-skill');
|
|
52
|
-
mkdirSync(skillDir);
|
|
53
|
-
writeFileSync(
|
|
54
|
-
join(skillDir, 'SKILL.md'),
|
|
55
|
-
`---
|
|
56
|
-
name: test-skill
|
|
57
|
-
description: A test skill for packing
|
|
58
|
-
metadata:
|
|
59
|
-
version: "1.0.0"
|
|
60
|
-
---
|
|
61
|
-
# Test Skill
|
|
62
|
-
|
|
63
|
-
Instructions here.`
|
|
64
|
-
);
|
|
65
|
-
|
|
66
|
-
const outputPath = join(testDir, 'test-skill-1.0.0.skill');
|
|
67
|
-
const result = await packSkill(skillDir, outputPath);
|
|
68
|
-
|
|
69
|
-
expect(result.success).toBe(true);
|
|
70
|
-
expect(result.name).toBe('test-skill');
|
|
71
|
-
expect(result.version).toBe('1.0.0');
|
|
72
|
-
expect(result.path).toBe(outputPath);
|
|
73
|
-
expect(result.path!.endsWith('.skill')).toBe(true);
|
|
74
|
-
expect(result.sha256).toMatch(/^[a-f0-9]{64}$/);
|
|
75
|
-
expect(result.size).toBeGreaterThan(0);
|
|
76
|
-
|
|
77
|
-
// Verify bundle exists
|
|
78
|
-
expect(existsSync(result.path!)).toBe(true);
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
it('uses 0.0.0 version when metadata version is missing', async () => {
|
|
82
|
-
const skillDir = join(testDir, 'no-version');
|
|
83
|
-
mkdirSync(skillDir);
|
|
84
|
-
writeFileSync(
|
|
85
|
-
join(skillDir, 'SKILL.md'),
|
|
86
|
-
`---
|
|
87
|
-
name: no-version
|
|
88
|
-
description: A skill without version
|
|
89
|
-
---
|
|
90
|
-
# No Version`
|
|
91
|
-
);
|
|
92
|
-
|
|
93
|
-
const outputPath = join(testDir, 'no-version-0.0.0.skill');
|
|
94
|
-
const result = await packSkill(skillDir, outputPath);
|
|
95
|
-
|
|
96
|
-
expect(result.success).toBe(true);
|
|
97
|
-
expect(result.version).toBe('0.0.0');
|
|
98
|
-
expect(basename(result.path!)).toBe('no-version-0.0.0.skill');
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
it('creates bundle in current directory by default', async () => {
|
|
102
|
-
const skillDir = join(testDir, 'output-test');
|
|
103
|
-
mkdirSync(skillDir);
|
|
104
|
-
writeFileSync(
|
|
105
|
-
join(skillDir, 'SKILL.md'),
|
|
106
|
-
`---
|
|
107
|
-
name: output-test
|
|
108
|
-
description: Testing output path
|
|
109
|
-
metadata:
|
|
110
|
-
version: "1.0.0"
|
|
111
|
-
---
|
|
112
|
-
# Output Test`
|
|
113
|
-
);
|
|
114
|
-
|
|
115
|
-
// Change to temp directory to test default output location
|
|
116
|
-
const originalCwd = process.cwd();
|
|
117
|
-
process.chdir(testDir);
|
|
118
|
-
|
|
119
|
-
try {
|
|
120
|
-
const result = await packSkill(skillDir);
|
|
121
|
-
|
|
122
|
-
expect(result.success).toBe(true);
|
|
123
|
-
expect(result.path).toContain(testDir);
|
|
124
|
-
} finally {
|
|
125
|
-
process.chdir(originalCwd);
|
|
126
|
-
}
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
it('uses custom output path when provided', async () => {
|
|
130
|
-
const skillDir = join(testDir, 'custom-output');
|
|
131
|
-
mkdirSync(skillDir);
|
|
132
|
-
writeFileSync(
|
|
133
|
-
join(skillDir, 'SKILL.md'),
|
|
134
|
-
`---
|
|
135
|
-
name: custom-output
|
|
136
|
-
description: Custom output path test
|
|
137
|
-
metadata:
|
|
138
|
-
version: "2.0.0"
|
|
139
|
-
---
|
|
140
|
-
# Custom Output`
|
|
141
|
-
);
|
|
142
|
-
|
|
143
|
-
const outputPath = join(testDir, 'custom-name.skill');
|
|
144
|
-
const result = await packSkill(skillDir, outputPath);
|
|
145
|
-
|
|
146
|
-
expect(result.success).toBe(true);
|
|
147
|
-
expect(result.path).toBe(outputPath);
|
|
148
|
-
expect(existsSync(outputPath)).toBe(true);
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
it('includes skill directory structure in bundle', async () => {
|
|
152
|
-
const skillDir = join(testDir, 'structured-skill');
|
|
153
|
-
mkdirSync(skillDir);
|
|
154
|
-
mkdirSync(join(skillDir, 'scripts'));
|
|
155
|
-
mkdirSync(join(skillDir, 'references'));
|
|
156
|
-
|
|
157
|
-
writeFileSync(
|
|
158
|
-
join(skillDir, 'SKILL.md'),
|
|
159
|
-
`---
|
|
160
|
-
name: structured-skill
|
|
161
|
-
description: A skill with structure
|
|
162
|
-
metadata:
|
|
163
|
-
version: "1.0.0"
|
|
164
|
-
---
|
|
165
|
-
# Structured Skill`
|
|
166
|
-
);
|
|
167
|
-
writeFileSync(join(skillDir, 'scripts', 'helper.py'), '# Python helper');
|
|
168
|
-
writeFileSync(join(skillDir, 'references', 'PATTERNS.md'), '# Patterns');
|
|
169
|
-
|
|
170
|
-
const outputPath = join(testDir, 'structured-skill-1.0.0.skill');
|
|
171
|
-
const result = await packSkill(skillDir, outputPath);
|
|
172
|
-
|
|
173
|
-
expect(result.success).toBe(true);
|
|
174
|
-
|
|
175
|
-
// Verify bundle contents using unzip -l
|
|
176
|
-
try {
|
|
177
|
-
const listing = execSync(`unzip -l "${result.path}"`, { encoding: 'utf-8' });
|
|
178
|
-
expect(listing).toContain('structured-skill/SKILL.md');
|
|
179
|
-
expect(listing).toContain('structured-skill/scripts/helper.py');
|
|
180
|
-
expect(listing).toContain('structured-skill/references/PATTERNS.md');
|
|
181
|
-
} catch {
|
|
182
|
-
// unzip may not be available, skip this check
|
|
183
|
-
}
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
it('calculates correct SHA256', async () => {
|
|
187
|
-
const skillDir = join(testDir, 'hash-test');
|
|
188
|
-
mkdirSync(skillDir);
|
|
189
|
-
writeFileSync(
|
|
190
|
-
join(skillDir, 'SKILL.md'),
|
|
191
|
-
`---
|
|
192
|
-
name: hash-test
|
|
193
|
-
description: Testing SHA256 calculation
|
|
194
|
-
metadata:
|
|
195
|
-
version: "1.0.0"
|
|
196
|
-
---
|
|
197
|
-
# Hash Test`
|
|
198
|
-
);
|
|
199
|
-
|
|
200
|
-
const outputPath = join(testDir, 'hash-test-1.0.0.skill');
|
|
201
|
-
const result = await packSkill(skillDir, outputPath);
|
|
202
|
-
|
|
203
|
-
expect(result.success).toBe(true);
|
|
204
|
-
expect(result.sha256).toHaveLength(64);
|
|
205
|
-
|
|
206
|
-
// Verify hash using shasum if available
|
|
207
|
-
try {
|
|
208
|
-
const shasum = execSync(`shasum -a 256 "${result.path}"`, { encoding: 'utf-8' });
|
|
209
|
-
const computedHash = shasum.split(' ')[0];
|
|
210
|
-
expect(result.sha256).toBe(computedHash);
|
|
211
|
-
} catch {
|
|
212
|
-
// shasum may not be available, skip this check
|
|
213
|
-
}
|
|
214
|
-
});
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
describe('bundle naming', () => {
|
|
218
|
-
it('creates bundle with name-version.skill format', async () => {
|
|
219
|
-
const skillDir = join(testDir, 'naming-test');
|
|
220
|
-
mkdirSync(skillDir);
|
|
221
|
-
writeFileSync(
|
|
222
|
-
join(skillDir, 'SKILL.md'),
|
|
223
|
-
`---
|
|
224
|
-
name: naming-test
|
|
225
|
-
description: Testing bundle naming
|
|
226
|
-
metadata:
|
|
227
|
-
version: "3.2.1"
|
|
228
|
-
---
|
|
229
|
-
# Naming Test`
|
|
230
|
-
);
|
|
231
|
-
|
|
232
|
-
const outputPath = join(testDir, 'naming-test-3.2.1.skill');
|
|
233
|
-
const result = await packSkill(skillDir, outputPath);
|
|
234
|
-
|
|
235
|
-
expect(result.success).toBe(true);
|
|
236
|
-
expect(basename(result.path!)).toBe('naming-test-3.2.1.skill');
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
it('handles prerelease versions', async () => {
|
|
240
|
-
const skillDir = join(testDir, 'prerelease-test');
|
|
241
|
-
mkdirSync(skillDir);
|
|
242
|
-
writeFileSync(
|
|
243
|
-
join(skillDir, 'SKILL.md'),
|
|
244
|
-
`---
|
|
245
|
-
name: prerelease-test
|
|
246
|
-
description: Testing prerelease version
|
|
247
|
-
metadata:
|
|
248
|
-
version: "1.0.0-beta.1"
|
|
249
|
-
---
|
|
250
|
-
# Prerelease Test`
|
|
251
|
-
);
|
|
252
|
-
|
|
253
|
-
const outputPath = join(testDir, 'prerelease-test-1.0.0-beta.1.skill');
|
|
254
|
-
const result = await packSkill(skillDir, outputPath);
|
|
255
|
-
|
|
256
|
-
expect(result.success).toBe(true);
|
|
257
|
-
expect(basename(result.path!)).toBe('prerelease-test-1.0.0-beta.1.skill');
|
|
258
|
-
});
|
|
259
|
-
});
|
|
260
|
-
});
|
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
import { createWriteStream, createReadStream } from 'fs';
|
|
2
|
-
import { createHash } from 'crypto';
|
|
3
|
-
import { basename, join, resolve } from 'path';
|
|
4
|
-
import archiver from 'archiver';
|
|
5
|
-
import { validateSkillDirectory, formatValidationResult } from './validate.js';
|
|
6
|
-
|
|
7
|
-
export interface PackResult {
|
|
8
|
-
success: boolean;
|
|
9
|
-
path: string | null;
|
|
10
|
-
name: string | null;
|
|
11
|
-
version: string | null;
|
|
12
|
-
size: number | null;
|
|
13
|
-
sha256: string | null;
|
|
14
|
-
error: string | null;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Create a .skill bundle from a skill directory
|
|
19
|
-
*/
|
|
20
|
-
export async function packSkill(skillPath: string, outputPath?: string): Promise<PackResult> {
|
|
21
|
-
// Validate first
|
|
22
|
-
const validation = validateSkillDirectory(skillPath);
|
|
23
|
-
|
|
24
|
-
if (!validation.valid) {
|
|
25
|
-
return {
|
|
26
|
-
success: false,
|
|
27
|
-
path: null,
|
|
28
|
-
name: null,
|
|
29
|
-
version: null,
|
|
30
|
-
size: null,
|
|
31
|
-
sha256: null,
|
|
32
|
-
error: `Validation failed:\n${formatValidationResult(validation)}`,
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const skillName = validation.name!;
|
|
37
|
-
const version = validation.frontmatter?.metadata?.version || '0.0.0';
|
|
38
|
-
|
|
39
|
-
// Determine output path
|
|
40
|
-
const bundleName = `${skillName}-${version}.skill`;
|
|
41
|
-
const finalOutputPath = outputPath || join(process.cwd(), bundleName);
|
|
42
|
-
|
|
43
|
-
// Create the zip archive
|
|
44
|
-
return new Promise((resolvePromise) => {
|
|
45
|
-
const output = createWriteStream(finalOutputPath);
|
|
46
|
-
const archive = archiver('zip', { zlib: { level: 9 } });
|
|
47
|
-
|
|
48
|
-
let size = 0;
|
|
49
|
-
|
|
50
|
-
output.on('close', async () => {
|
|
51
|
-
size = archive.pointer();
|
|
52
|
-
|
|
53
|
-
// Calculate SHA256
|
|
54
|
-
const hash = createHash('sha256');
|
|
55
|
-
const stream = createReadStream(finalOutputPath);
|
|
56
|
-
|
|
57
|
-
stream.on('data', (chunk) => hash.update(chunk));
|
|
58
|
-
stream.on('end', () => {
|
|
59
|
-
const sha256 = hash.digest('hex');
|
|
60
|
-
|
|
61
|
-
resolvePromise({
|
|
62
|
-
success: true,
|
|
63
|
-
path: finalOutputPath,
|
|
64
|
-
name: skillName,
|
|
65
|
-
version,
|
|
66
|
-
size,
|
|
67
|
-
sha256,
|
|
68
|
-
error: null,
|
|
69
|
-
});
|
|
70
|
-
});
|
|
71
|
-
stream.on('error', (err) => {
|
|
72
|
-
resolvePromise({
|
|
73
|
-
success: false,
|
|
74
|
-
path: null,
|
|
75
|
-
name: skillName,
|
|
76
|
-
version,
|
|
77
|
-
size: null,
|
|
78
|
-
sha256: null,
|
|
79
|
-
error: `Failed to calculate SHA256: ${err.message}`,
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
archive.on('error', (err) => {
|
|
85
|
-
resolvePromise({
|
|
86
|
-
success: false,
|
|
87
|
-
path: null,
|
|
88
|
-
name: skillName,
|
|
89
|
-
version,
|
|
90
|
-
size: null,
|
|
91
|
-
sha256: null,
|
|
92
|
-
error: `Archive error: ${err.message}`,
|
|
93
|
-
});
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
archive.pipe(output);
|
|
97
|
-
|
|
98
|
-
// Add the skill directory to the archive
|
|
99
|
-
// The archive should contain: skillName/SKILL.md, skillName/scripts/, etc.
|
|
100
|
-
const dirName = basename(resolve(skillPath));
|
|
101
|
-
archive.directory(skillPath, dirName);
|
|
102
|
-
|
|
103
|
-
archive.finalize();
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Format file size for display
|
|
109
|
-
*/
|
|
110
|
-
function formatSize(bytes: number): string {
|
|
111
|
-
if (bytes < 1024) return `${bytes} B`;
|
|
112
|
-
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
113
|
-
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
export interface PackOptions {
|
|
117
|
-
output?: string;
|
|
118
|
-
json?: boolean;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Handle the pack command
|
|
123
|
-
*/
|
|
124
|
-
export async function handleSkillPack(skillPath: string, options: PackOptions): Promise<void> {
|
|
125
|
-
console.log('');
|
|
126
|
-
console.log(`Validating ${skillPath}...`);
|
|
127
|
-
|
|
128
|
-
const result = await packSkill(skillPath, options.output);
|
|
129
|
-
|
|
130
|
-
if (options.json) {
|
|
131
|
-
console.log(JSON.stringify(result, null, 2));
|
|
132
|
-
} else if (result.success) {
|
|
133
|
-
console.log(`\u2713 Valid: ${result.name}`);
|
|
134
|
-
console.log('');
|
|
135
|
-
console.log('Creating bundle...');
|
|
136
|
-
console.log(`\u2713 Created: ${basename(result.path!)} (${formatSize(result.size!)})`);
|
|
137
|
-
console.log(` SHA256: ${result.sha256}`);
|
|
138
|
-
} else {
|
|
139
|
-
console.log(result.error);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
if (!result.success) {
|
|
143
|
-
process.exit(1);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import { writeFileSync } from 'fs';
|
|
2
|
-
import { basename, join } from 'path';
|
|
3
|
-
import { getSkillDownloadInfo, downloadSkillBundle } from '../../lib/api/skills-client.js';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Parse skill spec into name and version
|
|
7
|
-
* Examples: @scope/name, @scope/name@1.0.0
|
|
8
|
-
*/
|
|
9
|
-
function parseSkillSpec(spec: string): { name: string; version?: string } {
|
|
10
|
-
// Handle @scope/name@version format
|
|
11
|
-
const atIndex = spec.lastIndexOf('@');
|
|
12
|
-
|
|
13
|
-
// If @ is at position 0, it's just the scope prefix
|
|
14
|
-
if (atIndex <= 0) {
|
|
15
|
-
return { name: spec };
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// Check if the @ is part of version (after the /)
|
|
19
|
-
const slashIndex = spec.indexOf('/');
|
|
20
|
-
if (atIndex > slashIndex) {
|
|
21
|
-
return {
|
|
22
|
-
name: spec.slice(0, atIndex),
|
|
23
|
-
version: spec.slice(atIndex + 1),
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return { name: spec };
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export interface PullOptions {
|
|
31
|
-
output?: string;
|
|
32
|
-
json?: boolean;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Handle the skill pull command
|
|
37
|
-
*/
|
|
38
|
-
export async function handleSkillPull(skillSpec: string, options: PullOptions): Promise<void> {
|
|
39
|
-
try {
|
|
40
|
-
const { name, version } = parseSkillSpec(skillSpec);
|
|
41
|
-
|
|
42
|
-
// Get download info
|
|
43
|
-
const downloadInfo = await getSkillDownloadInfo(name, version);
|
|
44
|
-
|
|
45
|
-
console.log(
|
|
46
|
-
`Pulling ${downloadInfo.skill.name}@${downloadInfo.skill.version}...`
|
|
47
|
-
);
|
|
48
|
-
|
|
49
|
-
// Download the bundle
|
|
50
|
-
const buffer = await downloadSkillBundle(downloadInfo.url, downloadInfo.skill.sha256);
|
|
51
|
-
|
|
52
|
-
// Determine output path
|
|
53
|
-
const filename = `${basename(downloadInfo.skill.name.replace('@', '').replace('/', '-'))}-${downloadInfo.skill.version}.skill`;
|
|
54
|
-
const outputPath = options.output || join(process.cwd(), filename);
|
|
55
|
-
|
|
56
|
-
// Write to disk
|
|
57
|
-
writeFileSync(outputPath, buffer);
|
|
58
|
-
|
|
59
|
-
if (options.json) {
|
|
60
|
-
console.log(
|
|
61
|
-
JSON.stringify(
|
|
62
|
-
{
|
|
63
|
-
path: outputPath,
|
|
64
|
-
name: downloadInfo.skill.name,
|
|
65
|
-
version: downloadInfo.skill.version,
|
|
66
|
-
size: downloadInfo.skill.size,
|
|
67
|
-
sha256: downloadInfo.skill.sha256,
|
|
68
|
-
},
|
|
69
|
-
null,
|
|
70
|
-
2
|
|
71
|
-
)
|
|
72
|
-
);
|
|
73
|
-
} else {
|
|
74
|
-
console.log(`Downloaded ${filename} (${formatSize(downloadInfo.skill.size)})`);
|
|
75
|
-
console.log(` SHA256: ${downloadInfo.skill.sha256}`);
|
|
76
|
-
console.log(` Path: ${outputPath}`);
|
|
77
|
-
}
|
|
78
|
-
} catch (err) {
|
|
79
|
-
console.error(`Error: ${err instanceof Error ? err.message : err}`);
|
|
80
|
-
process.exit(1);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
function formatSize(bytes: number): string {
|
|
85
|
-
if (bytes < 1024) return `${bytes} B`;
|
|
86
|
-
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
87
|
-
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
88
|
-
}
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { searchSkills } from '../../lib/api/skills-client.js';
|
|
2
|
-
|
|
3
|
-
export interface SearchOptions {
|
|
4
|
-
tags?: string;
|
|
5
|
-
category?: string;
|
|
6
|
-
surface?: string;
|
|
7
|
-
sort?: string;
|
|
8
|
-
limit?: number;
|
|
9
|
-
offset?: number;
|
|
10
|
-
json?: boolean;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Handle the skill search command
|
|
15
|
-
*/
|
|
16
|
-
export async function handleSkillSearch(query: string, options: SearchOptions): Promise<void> {
|
|
17
|
-
try {
|
|
18
|
-
const result = await searchSkills({
|
|
19
|
-
q: query,
|
|
20
|
-
tags: options.tags,
|
|
21
|
-
category: options.category as any,
|
|
22
|
-
surface: options.surface as any,
|
|
23
|
-
sort: options.sort as any,
|
|
24
|
-
limit: options.limit,
|
|
25
|
-
offset: options.offset,
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
if (options.json) {
|
|
29
|
-
console.log(JSON.stringify(result, null, 2));
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
if (result.skills.length === 0) {
|
|
34
|
-
console.log(`No skills found for "${query}"`);
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Table header
|
|
39
|
-
const nameWidth = 45;
|
|
40
|
-
const categoryWidth = 12;
|
|
41
|
-
const downloadsWidth = 10;
|
|
42
|
-
|
|
43
|
-
console.log('');
|
|
44
|
-
console.log(
|
|
45
|
-
'NAME'.padEnd(nameWidth) +
|
|
46
|
-
'CATEGORY'.padEnd(categoryWidth) +
|
|
47
|
-
'DOWNLOADS'.padStart(downloadsWidth)
|
|
48
|
-
);
|
|
49
|
-
|
|
50
|
-
// Table rows
|
|
51
|
-
for (const skill of result.skills) {
|
|
52
|
-
const name = skill.name.length > nameWidth - 2
|
|
53
|
-
? skill.name.slice(0, nameWidth - 5) + '...'
|
|
54
|
-
: skill.name;
|
|
55
|
-
const category = skill.category || '-';
|
|
56
|
-
const downloads = skill.downloads.toLocaleString();
|
|
57
|
-
|
|
58
|
-
console.log(
|
|
59
|
-
name.padEnd(nameWidth) +
|
|
60
|
-
category.padEnd(categoryWidth) +
|
|
61
|
-
downloads.padStart(downloadsWidth)
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (result.pagination.has_more) {
|
|
66
|
-
console.log('');
|
|
67
|
-
console.log(`Showing ${result.skills.length} of ${result.total} results. Use --offset to see more.`);
|
|
68
|
-
}
|
|
69
|
-
} catch (err) {
|
|
70
|
-
console.error(`Error: ${err instanceof Error ? err.message : err}`);
|
|
71
|
-
process.exit(1);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import { getSkillDetails } from '../../lib/api/skills-client.js';
|
|
2
|
-
|
|
3
|
-
export interface ShowOptions {
|
|
4
|
-
json?: boolean;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Handle the skill show command
|
|
9
|
-
*/
|
|
10
|
-
export async function handleSkillShow(name: string, options: ShowOptions): Promise<void> {
|
|
11
|
-
try {
|
|
12
|
-
const skill = await getSkillDetails(name);
|
|
13
|
-
|
|
14
|
-
if (options.json) {
|
|
15
|
-
console.log(JSON.stringify(skill, null, 2));
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
console.log('');
|
|
20
|
-
console.log(`${skill.name}@${skill.latest_version}`);
|
|
21
|
-
console.log('');
|
|
22
|
-
console.log(skill.description);
|
|
23
|
-
console.log('');
|
|
24
|
-
|
|
25
|
-
// Metadata section
|
|
26
|
-
console.log('Metadata:');
|
|
27
|
-
if (skill.license) console.log(` License: ${skill.license}`);
|
|
28
|
-
if (skill.category) console.log(` Category: ${skill.category}`);
|
|
29
|
-
if (skill.tags && skill.tags.length > 0) console.log(` Tags: ${skill.tags.join(', ')}`);
|
|
30
|
-
if (skill.surfaces && skill.surfaces.length > 0)
|
|
31
|
-
console.log(` Surfaces: ${skill.surfaces.join(', ')}`);
|
|
32
|
-
if (skill.author) console.log(` Author: ${skill.author.name}${skill.author.url ? ` (${skill.author.url})` : ''}`);
|
|
33
|
-
console.log(` Downloads: ${skill.downloads.toLocaleString()}`);
|
|
34
|
-
console.log(` Published: ${new Date(skill.published_at).toLocaleDateString()}`);
|
|
35
|
-
|
|
36
|
-
// Triggers
|
|
37
|
-
if (skill.triggers && skill.triggers.length > 0) {
|
|
38
|
-
console.log('');
|
|
39
|
-
console.log('Triggers:');
|
|
40
|
-
skill.triggers.forEach((t: string) => console.log(` - ${t}`));
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Examples
|
|
44
|
-
if (skill.examples && skill.examples.length > 0) {
|
|
45
|
-
console.log('');
|
|
46
|
-
console.log('Examples:');
|
|
47
|
-
skill.examples.forEach((ex: { prompt: string; context?: string }) => {
|
|
48
|
-
console.log(` - "${ex.prompt}"${ex.context ? ` (${ex.context})` : ''}`);
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Versions
|
|
53
|
-
if (skill.versions && skill.versions.length > 0) {
|
|
54
|
-
console.log('');
|
|
55
|
-
console.log('Versions:');
|
|
56
|
-
skill.versions.slice(0, 5).forEach((v: { version: string; published_at: string; downloads: number }) => {
|
|
57
|
-
console.log(
|
|
58
|
-
` ${v.version.padEnd(12)} ${new Date(v.published_at).toLocaleDateString().padEnd(12)} ${v.downloads.toLocaleString()} downloads`
|
|
59
|
-
);
|
|
60
|
-
});
|
|
61
|
-
if (skill.versions.length > 5) {
|
|
62
|
-
console.log(` ... and ${skill.versions.length - 5} more`);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
console.log('');
|
|
67
|
-
console.log(`Install: mpak skill install ${skill.name}`);
|
|
68
|
-
} catch (err) {
|
|
69
|
-
console.error(`Error: ${err instanceof Error ? err.message : err}`);
|
|
70
|
-
process.exit(1);
|
|
71
|
-
}
|
|
72
|
-
}
|