@@ -425,7 +425,7 @@ describe('ConfigManager', () => {
425425 } ) ;
426426
427427 describe ( 'addSkill' , ( ) => {
428- it ( 'adds a new skill entry to config' , async ( ) => {
428+ it ( 'adds a new skill entry to config when skills is an array ' , async ( ) => {
429429 const config : DevKitConfig = {
430430 version : '1.0.0' ,
431431 environments : [ 'cursor' ] ,
@@ -444,10 +444,46 @@ describe('ConfigManager', () => {
444444 name : 'memory'
445445 } ) ;
446446
447- expect ( result . skills ) . toEqual ( [
448- { registry : 'codeaholicguy/ai-devkit' , name : 'debug' } ,
449- { registry : 'codeaholicguy/ai-devkit' , name : 'memory' }
450- ] ) ;
447+ expect ( result . skills ) . toEqual ( {
448+ installed : [
449+ { registry : 'codeaholicguy/ai-devkit' , name : 'debug' } ,
450+ { registry : 'codeaholicguy/ai-devkit' , name : 'memory' }
451+ ]
452+ } ) ;
453+ expect ( mockFs . writeJson ) . toHaveBeenCalled ( ) ;
454+ } ) ;
455+
456+ it ( 'adds a new skill entry when skills is an object with registries' , async ( ) => {
457+ const config = {
458+ version : '1.0.0' ,
459+ environments : [ 'cursor' ] ,
460+ phases : [ ] ,
461+ skills : {
462+ registries : {
463+ 'custom/repo' : 'https://github.com/custom/repo.git'
464+ }
465+ } ,
466+ createdAt : '2024-01-01T00:00:00.000Z' ,
467+ updatedAt : '2024-01-01T00:00:00.000Z'
468+ } ;
469+
470+ ( mockFs . pathExists as any ) . mockResolvedValue ( true ) ;
471+ ( mockFs . readJson as any ) . mockResolvedValue ( config ) ;
472+ ( mockFs . writeJson as any ) . mockResolvedValue ( undefined ) ;
473+
474+ const result = await configManager . addSkill ( {
475+ registry : 'custom/repo' ,
476+ name : 'my-skill'
477+ } ) ;
478+
479+ expect ( result . skills ) . toEqual ( {
480+ registries : {
481+ 'custom/repo' : 'https://github.com/custom/repo.git'
482+ } ,
483+ installed : [
484+ { registry : 'custom/repo' , name : 'my-skill' }
485+ ]
486+ } ) ;
451487 expect ( mockFs . writeJson ) . toHaveBeenCalled ( ) ;
452488 } ) ;
453489
@@ -472,6 +508,114 @@ describe('ConfigManager', () => {
472508 expect ( result . skills ) . toEqual ( [ { registry : 'codeaholicguy/ai-devkit' , name : 'debug' } ] ) ;
473509 expect ( mockFs . writeJson ) . not . toHaveBeenCalled ( ) ;
474510 } ) ;
511+
512+ it ( 'adds skill when skills is undefined' , async ( ) => {
513+ const config : DevKitConfig = {
514+ version : '1.0.0' ,
515+ environments : [ 'cursor' ] ,
516+ phases : [ ] ,
517+ createdAt : '2024-01-01T00:00:00.000Z' ,
518+ updatedAt : '2024-01-01T00:00:00.000Z'
519+ } ;
520+
521+ ( mockFs . pathExists as any ) . mockResolvedValue ( true ) ;
522+ ( mockFs . readJson as any ) . mockResolvedValue ( config ) ;
523+ ( mockFs . writeJson as any ) . mockResolvedValue ( undefined ) ;
524+
525+ const result = await configManager . addSkill ( {
526+ registry : 'codeaholicguy/ai-devkit' ,
527+ name : 'memory'
528+ } ) ;
529+
530+ expect ( result . skills ) . toEqual ( {
531+ installed : [
532+ { registry : 'codeaholicguy/ai-devkit' , name : 'memory' }
533+ ]
534+ } ) ;
535+ expect ( mockFs . writeJson ) . toHaveBeenCalled ( ) ;
536+ } ) ;
537+ } ) ;
538+
539+ describe ( 'normalizeSkillsConfig' , ( ) => {
540+ it ( 'normalizes an array to SkillsConfig' , ( ) => {
541+ const result = configManager . normalizeSkillsConfig ( [
542+ { registry : 'r' , name : 's' }
543+ ] ) ;
544+ expect ( result ) . toEqual ( {
545+ installed : [ { registry : 'r' , name : 's' } ]
546+ } ) ;
547+ } ) ;
548+
549+ it ( 'normalizes an object with registries and installed' , ( ) => {
550+ const result = configManager . normalizeSkillsConfig ( {
551+ registries : { 'r' : 'https://example.com' } ,
552+ installed : [ { registry : 'r' , name : 's' } ]
553+ } ) ;
554+ expect ( result ) . toEqual ( {
555+ registries : { 'r' : 'https://example.com' } ,
556+ installed : [ { registry : 'r' , name : 's' } ]
557+ } ) ;
558+ } ) ;
559+
560+ it ( 'normalizes an object with only registries' , ( ) => {
561+ const result = configManager . normalizeSkillsConfig ( {
562+ registries : { 'r' : 'https://example.com' }
563+ } ) ;
564+ expect ( result ) . toEqual ( {
565+ registries : { 'r' : 'https://example.com' } ,
566+ installed : [ ]
567+ } ) ;
568+ } ) ;
569+
570+ it ( 'normalizes undefined to empty SkillsConfig' , ( ) => {
571+ const result = configManager . normalizeSkillsConfig ( undefined ) ;
572+ expect ( result ) . toEqual ( { installed : [ ] } ) ;
573+ } ) ;
574+
575+ it ( 'normalizes null to empty SkillsConfig' , ( ) => {
576+ const result = configManager . normalizeSkillsConfig ( null ) ;
577+ expect ( result ) . toEqual ( { installed : [ ] } ) ;
578+ } ) ;
579+ } ) ;
580+
581+ describe ( 'getInstalledSkills' , ( ) => {
582+ it ( 'returns skills from array format' , ( ) => {
583+ const config : DevKitConfig = {
584+ version : '1.0.0' ,
585+ environments : [ ] ,
586+ phases : [ ] ,
587+ skills : [ { registry : 'r' , name : 's' } ] ,
588+ createdAt : '' ,
589+ updatedAt : ''
590+ } ;
591+ expect ( configManager . getInstalledSkills ( config ) ) . toEqual ( [ { registry : 'r' , name : 's' } ] ) ;
592+ } ) ;
593+
594+ it ( 'returns skills from object format' , ( ) => {
595+ const config = {
596+ version : '1.0.0' ,
597+ environments : [ ] ,
598+ phases : [ ] ,
599+ skills : {
600+ registries : { 'r' : 'https://example.com' } ,
601+ installed : [ { registry : 'r' , name : 's' } ]
602+ } ,
603+ createdAt : '' ,
604+ updatedAt : ''
605+ } as DevKitConfig ;
606+ expect ( configManager . getInstalledSkills ( config ) ) . toEqual ( [ { registry : 'r' , name : 's' } ] ) ;
607+ } ) ;
608+
609+ it ( 'returns empty array when skills is undefined' , ( ) => {
610+ const config : DevKitConfig = {
611+ version : '1.0.0' ,
612+ environments : [ ] ,
613+ phases : [ ] ,
614+ createdAt : '' ,
615+ updatedAt : ''
616+ } ;
617+ expect ( configManager . getInstalledSkills ( config ) ) . toEqual ( [ ] ) ;
618+ } ) ;
475619 } ) ;
476620
477621 describe ( 'getSkillRegistries' , ( ) => {
0 commit comments