Skip to content

Commit f6bf040

Browse files
committed
fix(cli): cannot run install when skills is an object with installed array
1 parent 87fa154 commit f6bf040

File tree

3 files changed

+60
-1
lines changed

3 files changed

+60
-1
lines changed

e2e/cli.e2e.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,24 @@ describe('install command', () => {
301301
const result = run('install -c nonexistent.json', { cwd: projectDir });
302302
expect(result.exitCode).not.toBe(0);
303303
});
304+
305+
it('should install when skills is an object with installed array (issue #62)', () => {
306+
writeConfigFile(projectDir, {
307+
version: '1.0.0',
308+
environments: ['claude'],
309+
phases: ['requirements'],
310+
skills: {
311+
installed: [
312+
{ registry: 'codeaholicguy/ai-devkit', name: 'dev-lifecycle' }
313+
]
314+
},
315+
createdAt: new Date().toISOString(),
316+
updatedAt: new Date().toISOString()
317+
});
318+
319+
const result = run('install', { cwd: projectDir });
320+
expect(result.exitCode).toBe(0);
321+
});
304322
});
305323

306324
describe('skill command', () => {

packages/cli/src/__tests__/util/config.test.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,34 @@ describe('config util', () => {
3131
it('fails when skills entry is invalid', () => {
3232
expect(() => validateInstallConfig({ skills: [{ registry: '', name: 'debug' }] }, '/tmp/.ai-devkit.json')).toThrow('skills[0].registry');
3333
});
34+
35+
it('accepts skills as an object with installed array (issue #62)', () => {
36+
const result = validateInstallConfig({
37+
environments: ['claude'],
38+
skills: {
39+
installed: [
40+
{ registry: 'codeaholicguy/ai-devkit', name: 'dev-lifecycle' }
41+
]
42+
}
43+
}, '/tmp/.ai-devkit.json');
44+
45+
expect(result.skills).toEqual([
46+
{ registry: 'codeaholicguy/ai-devkit', name: 'dev-lifecycle' }
47+
]);
48+
});
49+
50+
it('accepts skills as an object with registries and installed array', () => {
51+
const result = validateInstallConfig({
52+
skills: {
53+
registries: { myorg: 'myorg/skills' },
54+
installed: [
55+
{ registry: 'codeaholicguy/ai-devkit', name: 'memory' }
56+
]
57+
}
58+
}, '/tmp/.ai-devkit.json');
59+
60+
expect(result.skills).toEqual([
61+
{ registry: 'codeaholicguy/ai-devkit', name: 'memory' }
62+
]);
63+
});
3464
});

packages/cli/src/util/config.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,18 @@ const installConfigSchema = z.object({
4646
});
4747
}).transform(values => dedupe(values) as EnvironmentCode[]),
4848
phases: z.array(z.string()).optional(),
49-
skills: z.array(skillEntrySchema).optional().default([]),
49+
skills: z.preprocess(
50+
(val) => {
51+
if (val == null) return [];
52+
if (Array.isArray(val)) return val;
53+
if (typeof val === 'object' && !Array.isArray(val)) {
54+
const obj = val as Record<string, unknown>;
55+
return Array.isArray(obj.installed) ? obj.installed : [];
56+
}
57+
return val;
58+
},
59+
z.array(skillEntrySchema).default([])
60+
),
5061
mcpServers: z.record(z.string(), z.object({
5162
transport: z.enum(['stdio', 'http', 'sse']),
5263
command: z.string().optional(),

0 commit comments

Comments
 (0)