@skillsmith/cli 0.3.1 → 0.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/README.md +57 -0
- package/assets/skillsmith-skill/SKILL.md +235 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/src/commands/index.d.ts +2 -0
- package/dist/src/commands/index.d.ts.map +1 -1
- package/dist/src/commands/index.js +4 -0
- package/dist/src/commands/index.js.map +1 -1
- package/dist/src/commands/install-skill.d.ts +13 -0
- package/dist/src/commands/install-skill.d.ts.map +1 -0
- package/dist/src/commands/install-skill.js +137 -0
- package/dist/src/commands/install-skill.js.map +1 -0
- package/dist/src/commands/manage.d.ts +4 -1
- package/dist/src/commands/manage.d.ts.map +1 -1
- package/dist/src/commands/manage.js +56 -10
- package/dist/src/commands/manage.js.map +1 -1
- package/dist/src/commands/merge.d.ts +17 -0
- package/dist/src/commands/merge.d.ts.map +1 -0
- package/dist/src/commands/merge.js +160 -0
- package/dist/src/commands/merge.js.map +1 -0
- package/dist/src/commands/recommend.d.ts +1 -4
- package/dist/src/commands/recommend.d.ts.map +1 -1
- package/dist/src/commands/recommend.helpers.d.ts +58 -0
- package/dist/src/commands/recommend.helpers.d.ts.map +1 -0
- package/dist/src/commands/recommend.helpers.js +428 -0
- package/dist/src/commands/recommend.helpers.js.map +1 -0
- package/dist/src/commands/recommend.js +50 -372
- package/dist/src/commands/recommend.js.map +1 -1
- package/dist/src/commands/recommend.types.d.ts +66 -0
- package/dist/src/commands/recommend.types.d.ts.map +1 -0
- package/dist/src/commands/recommend.types.js +14 -0
- package/dist/src/commands/recommend.types.js.map +1 -0
- package/dist/src/commands/search.d.ts.map +1 -1
- package/dist/src/commands/search.js +133 -18
- package/dist/src/commands/search.js.map +1 -1
- package/dist/src/config.d.ts +5 -0
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/config.js +7 -0
- package/dist/src/config.js.map +1 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +11 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/utils/license.test.js +6 -1
- package/dist/src/utils/license.test.js.map +1 -1
- package/dist/src/utils/node-version.d.ts +41 -0
- package/dist/src/utils/node-version.d.ts.map +1 -0
- package/dist/src/utils/node-version.js +123 -0
- package/dist/src/utils/node-version.js.map +1 -0
- package/dist/tests/e2e/search.e2e.test.js +62 -6
- package/dist/tests/e2e/search.e2e.test.js.map +1 -1
- package/dist/tests/e2e/utils/hardcoded-detector.d.ts.map +1 -1
- package/dist/tests/e2e/utils/hardcoded-detector.js +44 -3
- package/dist/tests/e2e/utils/hardcoded-detector.js.map +1 -1
- package/dist/tests/install-skill.test.d.ts +8 -0
- package/dist/tests/install-skill.test.d.ts.map +1 -0
- package/dist/tests/install-skill.test.js +409 -0
- package/dist/tests/install-skill.test.js.map +1 -0
- package/dist/tests/manage.test.js +284 -8
- package/dist/tests/manage.test.js.map +1 -1
- package/dist/tests/node-version.test.d.ts +8 -0
- package/dist/tests/node-version.test.d.ts.map +1 -0
- package/dist/tests/node-version.test.js +200 -0
- package/dist/tests/node-version.test.js.map +1 -0
- package/dist/tests/recommend.test.js +94 -0
- package/dist/tests/recommend.test.js.map +1 -1
- package/package.json +3 -2
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMI-824: Install Skillsmith Skill Command Tests
|
|
3
|
+
*
|
|
4
|
+
* Tests for the install-skill command that copies bundled skillsmith skill
|
|
5
|
+
* assets to ~/.claude/skills/skillsmith/ for /skillsmith slash command support.
|
|
6
|
+
*/
|
|
7
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
8
|
+
import { Command } from 'commander';
|
|
9
|
+
import { join } from 'path';
|
|
10
|
+
import { homedir } from 'os';
|
|
11
|
+
// ============================================================================
|
|
12
|
+
// Mock Setup - Must be before imports
|
|
13
|
+
// ============================================================================
|
|
14
|
+
// Create a mocks container that survives hoisting
|
|
15
|
+
const mocks = vi.hoisted(() => ({
|
|
16
|
+
mkdir: vi.fn(),
|
|
17
|
+
copyFile: vi.fn(),
|
|
18
|
+
stat: vi.fn(),
|
|
19
|
+
readdir: vi.fn(),
|
|
20
|
+
spinner: {
|
|
21
|
+
start: vi.fn().mockReturnThis(),
|
|
22
|
+
stop: vi.fn().mockReturnThis(),
|
|
23
|
+
succeed: vi.fn().mockReturnThis(),
|
|
24
|
+
fail: vi.fn().mockReturnThis(),
|
|
25
|
+
warn: vi.fn().mockReturnThis(),
|
|
26
|
+
text: '',
|
|
27
|
+
},
|
|
28
|
+
}));
|
|
29
|
+
vi.mock('fs/promises', () => ({
|
|
30
|
+
mkdir: (...args) => mocks.mkdir(...args),
|
|
31
|
+
copyFile: (...args) => mocks.copyFile(...args),
|
|
32
|
+
stat: (...args) => mocks.stat(...args),
|
|
33
|
+
readdir: (...args) => mocks.readdir(...args),
|
|
34
|
+
}));
|
|
35
|
+
vi.mock('ora', () => ({
|
|
36
|
+
default: () => mocks.spinner,
|
|
37
|
+
}));
|
|
38
|
+
// Convenience aliases
|
|
39
|
+
const mockMkdir = mocks.mkdir;
|
|
40
|
+
const mockCopyFile = mocks.copyFile;
|
|
41
|
+
const mockStat = mocks.stat;
|
|
42
|
+
const mockReaddir = mocks.readdir;
|
|
43
|
+
const mockSpinner = mocks.spinner;
|
|
44
|
+
// Mock console.log/error for output verification
|
|
45
|
+
const originalConsoleLog = console.log;
|
|
46
|
+
const originalConsoleError = console.error;
|
|
47
|
+
const mockConsoleLog = vi.fn();
|
|
48
|
+
const mockConsoleError = vi.fn();
|
|
49
|
+
// Mock process.exit
|
|
50
|
+
const mockExit = vi.spyOn(process, 'exit').mockImplementation(() => undefined);
|
|
51
|
+
// ============================================================================
|
|
52
|
+
// Test Fixtures
|
|
53
|
+
// ============================================================================
|
|
54
|
+
// Target path used in assertions
|
|
55
|
+
const EXPECTED_TARGET_PATH = join(homedir(), '.claude', 'skills', 'skillsmith');
|
|
56
|
+
void EXPECTED_TARGET_PATH; // Used in tests below via mockMkdir assertions
|
|
57
|
+
/**
|
|
58
|
+
* Create a mock directory entry for readdir
|
|
59
|
+
*/
|
|
60
|
+
function createDirEntry(name, isDir) {
|
|
61
|
+
return {
|
|
62
|
+
name,
|
|
63
|
+
isDirectory: () => isDir,
|
|
64
|
+
isFile: () => !isDir,
|
|
65
|
+
isSymbolicLink: () => false,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Set up mocks for a successful installation scenario
|
|
70
|
+
*/
|
|
71
|
+
function setupSuccessfulInstall() {
|
|
72
|
+
// Assets directory exists
|
|
73
|
+
mockStat.mockImplementation(async (path) => {
|
|
74
|
+
if (path.includes('assets/skillsmith-skill') || path.includes('assets\\skillsmith-skill')) {
|
|
75
|
+
return { isDirectory: () => true };
|
|
76
|
+
}
|
|
77
|
+
// Target directory does not exist
|
|
78
|
+
throw Object.assign(new Error('ENOENT'), { code: 'ENOENT' });
|
|
79
|
+
});
|
|
80
|
+
// Assets directory has files
|
|
81
|
+
mockReaddir.mockResolvedValue([createDirEntry('SKILL.md', false)]);
|
|
82
|
+
// mkdir and copyFile succeed
|
|
83
|
+
mockMkdir.mockResolvedValue(undefined);
|
|
84
|
+
mockCopyFile.mockResolvedValue(undefined);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Set up mocks for existing installation scenario
|
|
88
|
+
*/
|
|
89
|
+
function setupExistingInstall() {
|
|
90
|
+
mockStat.mockImplementation(async (_path) => {
|
|
91
|
+
// Both assets and target exist
|
|
92
|
+
return { isDirectory: () => true };
|
|
93
|
+
});
|
|
94
|
+
mockReaddir.mockResolvedValue([createDirEntry('SKILL.md', false)]);
|
|
95
|
+
mockMkdir.mockResolvedValue(undefined);
|
|
96
|
+
mockCopyFile.mockResolvedValue(undefined);
|
|
97
|
+
}
|
|
98
|
+
// ============================================================================
|
|
99
|
+
// Tests
|
|
100
|
+
// ============================================================================
|
|
101
|
+
describe('SMI-824: Install Skillsmith Skill Command', () => {
|
|
102
|
+
beforeEach(() => {
|
|
103
|
+
vi.clearAllMocks();
|
|
104
|
+
console.log = mockConsoleLog;
|
|
105
|
+
console.error = mockConsoleError;
|
|
106
|
+
});
|
|
107
|
+
afterEach(() => {
|
|
108
|
+
console.log = originalConsoleLog;
|
|
109
|
+
console.error = originalConsoleError;
|
|
110
|
+
});
|
|
111
|
+
// ==========================================================================
|
|
112
|
+
// Command Registration Tests
|
|
113
|
+
// ==========================================================================
|
|
114
|
+
describe('command registration', () => {
|
|
115
|
+
it('should create a Command instance named "install-skill"', async () => {
|
|
116
|
+
const { createInstallSkillCommand } = await import('../src/commands/install-skill.js');
|
|
117
|
+
const cmd = createInstallSkillCommand();
|
|
118
|
+
expect(cmd).toBeInstanceOf(Command);
|
|
119
|
+
expect(cmd.name()).toBe('install-skill');
|
|
120
|
+
});
|
|
121
|
+
it('should have a description mentioning skillsmith skill', async () => {
|
|
122
|
+
const { createInstallSkillCommand } = await import('../src/commands/install-skill.js');
|
|
123
|
+
const cmd = createInstallSkillCommand();
|
|
124
|
+
const description = cmd.description();
|
|
125
|
+
expect(description.toLowerCase()).toContain('skillsmith');
|
|
126
|
+
expect(description.toLowerCase()).toContain('skill');
|
|
127
|
+
});
|
|
128
|
+
it('should have --force option with short flag -f', async () => {
|
|
129
|
+
const { createInstallSkillCommand } = await import('../src/commands/install-skill.js');
|
|
130
|
+
const cmd = createInstallSkillCommand();
|
|
131
|
+
const forceOpt = cmd.options.find((o) => o.short === '-f');
|
|
132
|
+
expect(forceOpt).toBeDefined();
|
|
133
|
+
expect(forceOpt?.long).toBe('--force');
|
|
134
|
+
});
|
|
135
|
+
it('should export as default', async () => {
|
|
136
|
+
const mod = await import('../src/commands/install-skill.js');
|
|
137
|
+
expect(mod.default).toBeDefined();
|
|
138
|
+
expect(typeof mod.default).toBe('function');
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
// ==========================================================================
|
|
142
|
+
// Successful Installation Tests
|
|
143
|
+
// ==========================================================================
|
|
144
|
+
describe('successful installation', () => {
|
|
145
|
+
beforeEach(() => {
|
|
146
|
+
setupSuccessfulInstall();
|
|
147
|
+
});
|
|
148
|
+
it('should create target directory with recursive option', async () => {
|
|
149
|
+
const { createInstallSkillCommand } = await import('../src/commands/install-skill.js');
|
|
150
|
+
const cmd = createInstallSkillCommand();
|
|
151
|
+
await cmd.parseAsync(['node', 'test']);
|
|
152
|
+
// Should create parent directories
|
|
153
|
+
expect(mockMkdir).toHaveBeenCalledWith(expect.stringContaining('.claude'), expect.objectContaining({ recursive: true }));
|
|
154
|
+
});
|
|
155
|
+
it('should copy files from assets to target directory', async () => {
|
|
156
|
+
const { createInstallSkillCommand } = await import('../src/commands/install-skill.js');
|
|
157
|
+
const cmd = createInstallSkillCommand();
|
|
158
|
+
await cmd.parseAsync(['node', 'test']);
|
|
159
|
+
expect(mockCopyFile).toHaveBeenCalled();
|
|
160
|
+
});
|
|
161
|
+
it('should show spinner during installation', async () => {
|
|
162
|
+
const { createInstallSkillCommand } = await import('../src/commands/install-skill.js');
|
|
163
|
+
const cmd = createInstallSkillCommand();
|
|
164
|
+
await cmd.parseAsync(['node', 'test']);
|
|
165
|
+
// ora() is called with text, then .start() is called without args
|
|
166
|
+
expect(mockSpinner.start).toHaveBeenCalled();
|
|
167
|
+
});
|
|
168
|
+
it('should show success message after installation', async () => {
|
|
169
|
+
const { createInstallSkillCommand } = await import('../src/commands/install-skill.js');
|
|
170
|
+
const cmd = createInstallSkillCommand();
|
|
171
|
+
await cmd.parseAsync(['node', 'test']);
|
|
172
|
+
expect(mockSpinner.succeed).toHaveBeenCalledWith(expect.stringContaining('installed successfully'));
|
|
173
|
+
});
|
|
174
|
+
it('should display available commands after installation', async () => {
|
|
175
|
+
const { createInstallSkillCommand } = await import('../src/commands/install-skill.js');
|
|
176
|
+
const cmd = createInstallSkillCommand();
|
|
177
|
+
await cmd.parseAsync(['node', 'test']);
|
|
178
|
+
const output = mockConsoleLog.mock.calls.map((c) => c[0]).join('\n');
|
|
179
|
+
expect(output).toContain('Available Commands');
|
|
180
|
+
expect(output).toContain('/skillsmith search');
|
|
181
|
+
expect(output).toContain('/skillsmith install');
|
|
182
|
+
expect(output).toContain('/skillsmith recommend');
|
|
183
|
+
});
|
|
184
|
+
it('should display installation location', async () => {
|
|
185
|
+
const { createInstallSkillCommand } = await import('../src/commands/install-skill.js');
|
|
186
|
+
const cmd = createInstallSkillCommand();
|
|
187
|
+
await cmd.parseAsync(['node', 'test']);
|
|
188
|
+
const output = mockConsoleLog.mock.calls.map((c) => c[0]).join('\n');
|
|
189
|
+
expect(output).toContain('Location');
|
|
190
|
+
});
|
|
191
|
+
it('should display files copied count', async () => {
|
|
192
|
+
const { createInstallSkillCommand } = await import('../src/commands/install-skill.js');
|
|
193
|
+
const cmd = createInstallSkillCommand();
|
|
194
|
+
await cmd.parseAsync(['node', 'test']);
|
|
195
|
+
const output = mockConsoleLog.mock.calls.map((c) => c[0]).join('\n');
|
|
196
|
+
expect(output).toContain('Files copied');
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
// ==========================================================================
|
|
200
|
+
// Existing Installation Tests
|
|
201
|
+
// ==========================================================================
|
|
202
|
+
describe('existing installation', () => {
|
|
203
|
+
beforeEach(() => {
|
|
204
|
+
setupExistingInstall();
|
|
205
|
+
});
|
|
206
|
+
it('should show already installed message without --force', async () => {
|
|
207
|
+
const { createInstallSkillCommand } = await import('../src/commands/install-skill.js');
|
|
208
|
+
const cmd = createInstallSkillCommand();
|
|
209
|
+
await cmd.parseAsync(['node', 'test']);
|
|
210
|
+
const output = mockConsoleLog.mock.calls.map((c) => c[0]).join('\n');
|
|
211
|
+
expect(output).toContain('already installed');
|
|
212
|
+
});
|
|
213
|
+
it('should suggest using --force when already installed', async () => {
|
|
214
|
+
const { createInstallSkillCommand } = await import('../src/commands/install-skill.js');
|
|
215
|
+
const cmd = createInstallSkillCommand();
|
|
216
|
+
await cmd.parseAsync(['node', 'test']);
|
|
217
|
+
const output = mockConsoleLog.mock.calls.map((c) => c[0]).join('\n');
|
|
218
|
+
expect(output).toContain('--force');
|
|
219
|
+
});
|
|
220
|
+
it('should not copy files when already installed without --force', async () => {
|
|
221
|
+
const { createInstallSkillCommand } = await import('../src/commands/install-skill.js');
|
|
222
|
+
const cmd = createInstallSkillCommand();
|
|
223
|
+
await cmd.parseAsync(['node', 'test']);
|
|
224
|
+
// Spinner should not have been started for already installed case
|
|
225
|
+
expect(mockSpinner.start).not.toHaveBeenCalled();
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
// ==========================================================================
|
|
229
|
+
// Force Flag Tests
|
|
230
|
+
// ==========================================================================
|
|
231
|
+
describe('--force flag', () => {
|
|
232
|
+
beforeEach(() => {
|
|
233
|
+
setupExistingInstall();
|
|
234
|
+
});
|
|
235
|
+
it('should reinstall when --force is provided', async () => {
|
|
236
|
+
const { createInstallSkillCommand } = await import('../src/commands/install-skill.js');
|
|
237
|
+
const cmd = createInstallSkillCommand();
|
|
238
|
+
await cmd.parseAsync(['node', 'test', '--force']);
|
|
239
|
+
// ora() is called with text, then .start() is called without args
|
|
240
|
+
expect(mockSpinner.start).toHaveBeenCalled();
|
|
241
|
+
expect(mockCopyFile).toHaveBeenCalled();
|
|
242
|
+
});
|
|
243
|
+
it('should show success message when reinstalling with --force', async () => {
|
|
244
|
+
const { createInstallSkillCommand } = await import('../src/commands/install-skill.js');
|
|
245
|
+
const cmd = createInstallSkillCommand();
|
|
246
|
+
await cmd.parseAsync(['node', 'test', '-f']);
|
|
247
|
+
expect(mockSpinner.succeed).toHaveBeenCalledWith(expect.stringContaining('installed successfully'));
|
|
248
|
+
});
|
|
249
|
+
it('should accept -f short flag', async () => {
|
|
250
|
+
const { createInstallSkillCommand } = await import('../src/commands/install-skill.js');
|
|
251
|
+
const cmd = createInstallSkillCommand();
|
|
252
|
+
await cmd.parseAsync(['node', 'test', '-f']);
|
|
253
|
+
expect(mockSpinner.start).toHaveBeenCalled();
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
// ==========================================================================
|
|
257
|
+
// Error Handling Tests
|
|
258
|
+
// ==========================================================================
|
|
259
|
+
describe('error handling', () => {
|
|
260
|
+
it('should fail when assets directory not found', async () => {
|
|
261
|
+
mockStat.mockRejectedValue(Object.assign(new Error('ENOENT'), { code: 'ENOENT' }));
|
|
262
|
+
const { createInstallSkillCommand } = await import('../src/commands/install-skill.js');
|
|
263
|
+
const cmd = createInstallSkillCommand();
|
|
264
|
+
await cmd.parseAsync(['node', 'test']);
|
|
265
|
+
expect(mockConsoleError).toHaveBeenCalled();
|
|
266
|
+
const errorOutput = mockConsoleError.mock.calls
|
|
267
|
+
.map((c) => String(c[0] || '') + String(c[1] || ''))
|
|
268
|
+
.join(' ');
|
|
269
|
+
expect(errorOutput.toLowerCase()).toContain('error');
|
|
270
|
+
expect(mockExit).toHaveBeenCalledWith(1);
|
|
271
|
+
});
|
|
272
|
+
it('should fail spinner when copy fails', async () => {
|
|
273
|
+
setupSuccessfulInstall();
|
|
274
|
+
mockCopyFile.mockRejectedValue(new Error('Permission denied'));
|
|
275
|
+
const { createInstallSkillCommand } = await import('../src/commands/install-skill.js');
|
|
276
|
+
const cmd = createInstallSkillCommand();
|
|
277
|
+
await cmd.parseAsync(['node', 'test']);
|
|
278
|
+
expect(mockSpinner.fail).toHaveBeenCalledWith('Failed to install skillsmith skill');
|
|
279
|
+
expect(mockExit).toHaveBeenCalledWith(1);
|
|
280
|
+
});
|
|
281
|
+
it('should fail spinner when mkdir fails', async () => {
|
|
282
|
+
setupSuccessfulInstall();
|
|
283
|
+
mockMkdir.mockRejectedValue(new Error('Cannot create directory'));
|
|
284
|
+
const { createInstallSkillCommand } = await import('../src/commands/install-skill.js');
|
|
285
|
+
const cmd = createInstallSkillCommand();
|
|
286
|
+
await cmd.parseAsync(['node', 'test']);
|
|
287
|
+
expect(mockSpinner.fail).toHaveBeenCalled();
|
|
288
|
+
expect(mockExit).toHaveBeenCalledWith(1);
|
|
289
|
+
});
|
|
290
|
+
it('should sanitize error messages containing user paths', async () => {
|
|
291
|
+
setupSuccessfulInstall();
|
|
292
|
+
mockCopyFile.mockRejectedValue(new Error(`Error at ${homedir()}/secret/path`));
|
|
293
|
+
const { createInstallSkillCommand } = await import('../src/commands/install-skill.js');
|
|
294
|
+
const cmd = createInstallSkillCommand();
|
|
295
|
+
await cmd.parseAsync(['node', 'test']);
|
|
296
|
+
// Error should be logged but with sanitized paths
|
|
297
|
+
expect(mockConsoleError).toHaveBeenCalled();
|
|
298
|
+
const errorOutput = mockConsoleError.mock.calls.map((c) => c.join(' ')).join(' ');
|
|
299
|
+
// The sanitizeError function replaces home paths with ~
|
|
300
|
+
expect(errorOutput).not.toContain(homedir());
|
|
301
|
+
});
|
|
302
|
+
});
|
|
303
|
+
// ==========================================================================
|
|
304
|
+
// Recursive Directory Copy Tests
|
|
305
|
+
// ==========================================================================
|
|
306
|
+
describe('recursive directory copy', () => {
|
|
307
|
+
it('should copy nested directories recursively', async () => {
|
|
308
|
+
// Assets directory exists
|
|
309
|
+
mockStat.mockImplementation(async (path) => {
|
|
310
|
+
if (path.includes('assets/skillsmith-skill') || path.includes('assets\\skillsmith-skill')) {
|
|
311
|
+
return { isDirectory: () => true };
|
|
312
|
+
}
|
|
313
|
+
// Target directory does not exist
|
|
314
|
+
throw Object.assign(new Error('ENOENT'), { code: 'ENOENT' });
|
|
315
|
+
});
|
|
316
|
+
// Assets have nested structure
|
|
317
|
+
mockReaddir.mockImplementation(async (path) => {
|
|
318
|
+
if (path.includes('subdir')) {
|
|
319
|
+
return [createDirEntry('nested-file.md', false)];
|
|
320
|
+
}
|
|
321
|
+
return [createDirEntry('SKILL.md', false), createDirEntry('subdir', true)];
|
|
322
|
+
});
|
|
323
|
+
mockMkdir.mockResolvedValue(undefined);
|
|
324
|
+
mockCopyFile.mockResolvedValue(undefined);
|
|
325
|
+
const { createInstallSkillCommand } = await import('../src/commands/install-skill.js');
|
|
326
|
+
const cmd = createInstallSkillCommand();
|
|
327
|
+
await cmd.parseAsync(['node', 'test']);
|
|
328
|
+
// Should have copied multiple files
|
|
329
|
+
expect(mockCopyFile).toHaveBeenCalledTimes(2); // SKILL.md and nested-file.md
|
|
330
|
+
// Should have created subdirectory
|
|
331
|
+
expect(mockMkdir).toHaveBeenCalledWith(expect.stringContaining('subdir'), expect.objectContaining({ recursive: true }));
|
|
332
|
+
});
|
|
333
|
+
it('should count all copied files correctly', async () => {
|
|
334
|
+
// Assets directory exists
|
|
335
|
+
mockStat.mockImplementation(async (path) => {
|
|
336
|
+
if (path.includes('assets/skillsmith-skill') || path.includes('assets\\skillsmith-skill')) {
|
|
337
|
+
return { isDirectory: () => true };
|
|
338
|
+
}
|
|
339
|
+
throw Object.assign(new Error('ENOENT'), { code: 'ENOENT' });
|
|
340
|
+
});
|
|
341
|
+
// Multiple files in assets
|
|
342
|
+
mockReaddir.mockResolvedValue([
|
|
343
|
+
createDirEntry('SKILL.md', false),
|
|
344
|
+
createDirEntry('README.md', false),
|
|
345
|
+
createDirEntry('config.json', false),
|
|
346
|
+
]);
|
|
347
|
+
mockMkdir.mockResolvedValue(undefined);
|
|
348
|
+
mockCopyFile.mockResolvedValue(undefined);
|
|
349
|
+
const { createInstallSkillCommand } = await import('../src/commands/install-skill.js');
|
|
350
|
+
const cmd = createInstallSkillCommand();
|
|
351
|
+
await cmd.parseAsync(['node', 'test']);
|
|
352
|
+
const output = mockConsoleLog.mock.calls.map((c) => c[0]).join('\n');
|
|
353
|
+
expect(output).toContain('Files copied: 3');
|
|
354
|
+
});
|
|
355
|
+
it('should skip symlinks for security', async () => {
|
|
356
|
+
// Assets directory exists
|
|
357
|
+
mockStat.mockImplementation(async (path) => {
|
|
358
|
+
if (path.includes('assets/skillsmith-skill') || path.includes('assets\\skillsmith-skill')) {
|
|
359
|
+
return { isDirectory: () => true };
|
|
360
|
+
}
|
|
361
|
+
throw Object.assign(new Error('ENOENT'), { code: 'ENOENT' });
|
|
362
|
+
});
|
|
363
|
+
// Assets include a symlink (which should be skipped)
|
|
364
|
+
mockReaddir.mockResolvedValue([
|
|
365
|
+
createDirEntry('SKILL.md', false),
|
|
366
|
+
{
|
|
367
|
+
name: 'dangerous-symlink',
|
|
368
|
+
isDirectory: () => false,
|
|
369
|
+
isFile: () => false,
|
|
370
|
+
isSymbolicLink: () => true,
|
|
371
|
+
},
|
|
372
|
+
]);
|
|
373
|
+
mockMkdir.mockResolvedValue(undefined);
|
|
374
|
+
mockCopyFile.mockResolvedValue(undefined);
|
|
375
|
+
const { createInstallSkillCommand } = await import('../src/commands/install-skill.js');
|
|
376
|
+
const cmd = createInstallSkillCommand();
|
|
377
|
+
await cmd.parseAsync(['node', 'test']);
|
|
378
|
+
// Should only copy the regular file, not the symlink
|
|
379
|
+
expect(mockCopyFile).toHaveBeenCalledTimes(1);
|
|
380
|
+
expect(mockCopyFile).toHaveBeenCalledWith(expect.stringContaining('SKILL.md'), expect.stringContaining('SKILL.md'));
|
|
381
|
+
// Should not have tried to copy the symlink
|
|
382
|
+
expect(mockCopyFile).not.toHaveBeenCalledWith(expect.stringContaining('dangerous-symlink'), expect.any(String));
|
|
383
|
+
});
|
|
384
|
+
});
|
|
385
|
+
// ==========================================================================
|
|
386
|
+
// Target Path Tests
|
|
387
|
+
// ==========================================================================
|
|
388
|
+
describe('target path', () => {
|
|
389
|
+
it('should install to ~/.claude/skills/skillsmith/', async () => {
|
|
390
|
+
setupSuccessfulInstall();
|
|
391
|
+
const { createInstallSkillCommand } = await import('../src/commands/install-skill.js');
|
|
392
|
+
const cmd = createInstallSkillCommand();
|
|
393
|
+
await cmd.parseAsync(['node', 'test']);
|
|
394
|
+
// mkdir should be called with the correct target path
|
|
395
|
+
expect(mockMkdir).toHaveBeenCalledWith(expect.stringContaining(join('.claude', 'skills', 'skillsmith')), expect.any(Object));
|
|
396
|
+
});
|
|
397
|
+
it('should display correct target path in output', async () => {
|
|
398
|
+
setupSuccessfulInstall();
|
|
399
|
+
const { createInstallSkillCommand } = await import('../src/commands/install-skill.js');
|
|
400
|
+
const cmd = createInstallSkillCommand();
|
|
401
|
+
await cmd.parseAsync(['node', 'test']);
|
|
402
|
+
const output = mockConsoleLog.mock.calls.map((c) => c[0]).join('\n');
|
|
403
|
+
expect(output).toContain('.claude');
|
|
404
|
+
expect(output).toContain('skills');
|
|
405
|
+
expect(output).toContain('skillsmith');
|
|
406
|
+
});
|
|
407
|
+
});
|
|
408
|
+
});
|
|
409
|
+
//# sourceMappingURL=install-skill.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-skill.test.js","sourceRoot":"","sources":["../../tests/install-skill.test.ts"],"names":[],"mappings":"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"}
|