@@ -18,6 +18,30 @@ const WORKSPACE_INDEX_VERSION = 2;
1818const UPSTREAM_GLOBAL_PACKAGE = "@vudovn/ag-kit" ;
1919const TOOLKIT_PACKAGE_NAMES = new Set ( [ "@mison/ag-kit-cn" , "antigravity-kit-cn" , "antigravity-kit" ] ) ;
2020const SUPPORTED_TARGETS = [ "gemini" , "codex" ] ;
21+ const LEGACY_INDEX_TARGET_ALIASES = {
22+ full : "gemini" ,
23+ } ;
24+ const GLOBAL_TARGET_DESTINATIONS = {
25+ codex : [
26+ {
27+ id : "codex" ,
28+ rootParts : [ ".codex" ] ,
29+ skillsParts : [ ".codex" , "skills" ] ,
30+ } ,
31+ ] ,
32+ gemini : [
33+ {
34+ id : "gemini-cli" ,
35+ rootParts : [ ".gemini" , "skills" ] ,
36+ skillsParts : [ ".gemini" , "skills" ] ,
37+ } ,
38+ {
39+ id : "antigravity" ,
40+ rootParts : [ ".gemini" , "antigravity" ] ,
41+ skillsParts : [ ".gemini" , "antigravity" , "skills" ] ,
42+ } ,
43+ ] ,
44+ } ;
2145const INDEX_LOCK_RETRY_MS = 50 ;
2246const INDEX_LOCK_TIMEOUT_MS = 3000 ;
2347const INDEX_LOCK_STALE_MS = 30000 ;
@@ -56,15 +80,21 @@ function resolveGlobalRootDir() {
5680 return os . homedir ( ) ;
5781}
5882
59- function resolveGlobalSkillRoot ( targetName ) {
60- const globalRoot = resolveGlobalRootDir ( ) ;
61- if ( targetName === "codex" ) {
62- return path . join ( globalRoot , ".agents" , "skills" ) ;
83+ function getGlobalDestinations ( targetName , globalRoot = resolveGlobalRootDir ( ) ) {
84+ const config = GLOBAL_TARGET_DESTINATIONS [ targetName ] ;
85+ if ( ! config ) {
86+ throw new Error ( `未知目标: ${ targetName } ` ) ;
6387 }
64- if ( targetName === "gemini" ) {
65- return path . join ( globalRoot , ".gemini" , "antigravity" , "skills" ) ;
66- }
67- throw new Error ( `未知目标: ${ targetName } ` ) ;
88+ return config . map ( ( item ) => ( {
89+ ...item ,
90+ targetName,
91+ rootDir : path . join ( globalRoot , ...item . rootParts ) ,
92+ skillsRoot : path . join ( globalRoot , ...item . skillsParts ) ,
93+ } ) ) ;
94+ }
95+
96+ function listGlobalDestinations ( globalRoot = resolveGlobalRootDir ( ) ) {
97+ return Object . keys ( GLOBAL_TARGET_DESTINATIONS ) . flatMap ( ( targetName ) => getGlobalDestinations ( targetName , globalRoot ) ) ;
6898}
6999
70100function resolveGlobalBackupRoot ( timestamp ) {
@@ -108,7 +138,7 @@ function printUsage() {
108138 console . log ( " ag-kit update [--path <dir>] [--branch <name>] [--target <name>|--targets <a,b>] [--no-index] [--quiet] [--dry-run]" ) ;
109139 console . log ( " ag-kit update-all [--branch <name>] [--targets <a,b>] [--prune-missing] [--quiet] [--dry-run]" ) ;
110140 console . log ( " ag-kit doctor [--path <dir>] [--target <name>|--targets <a,b>] [--fix] [--quiet]" ) ;
111- console . log ( " ag-kit global sync [--target <name>|--targets <a,b>] [--branch <name>] [--quiet] [--dry-run] # 默认同步 codex+ gemini" ) ;
141+ console . log ( " ag-kit global sync [--target <name>|--targets <a,b>] [--branch <name>] [--quiet] [--dry-run] # 默认同步 codex + gemini(cli+antigravity) " ) ;
112142 console . log ( " ag-kit global status [--quiet]" ) ;
113143 console . log ( " ag-kit exclude list [--quiet]" ) ;
114144 console . log ( " ag-kit exclude add --path <dir> [--dry-run] [--quiet]" ) ;
@@ -416,13 +446,34 @@ function normalizeTargetState(value) {
416446 } ;
417447}
418448
449+ function normalizeIndexTargetName ( targetName ) {
450+ if ( typeof targetName !== "string" ) {
451+ return null ;
452+ }
453+ const normalized = targetName . trim ( ) . toLowerCase ( ) ;
454+ if ( ! normalized ) {
455+ return null ;
456+ }
457+ if ( Object . prototype . hasOwnProperty . call ( LEGACY_INDEX_TARGET_ALIASES , normalized ) ) {
458+ return LEGACY_INDEX_TARGET_ALIASES [ normalized ] ;
459+ }
460+ if ( SUPPORTED_TARGETS . includes ( normalized ) ) {
461+ return normalized ;
462+ }
463+ return null ;
464+ }
465+
419466function normalizeWorkspaceRecordV2 ( item , normalizedPath ) {
420467 const targets = { } ;
421468 if ( item && item . targets && typeof item . targets === "object" ) {
422469 for ( const [ targetName , state ] of Object . entries ( item . targets ) ) {
470+ const normalizedTargetName = normalizeIndexTargetName ( targetName ) ;
471+ if ( ! normalizedTargetName ) {
472+ continue ;
473+ }
423474 const normalizedState = normalizeTargetState ( state ) ;
424475 if ( normalizedState ) {
425- targets [ targetName ] = normalizedState ;
476+ targets [ normalizedTargetName ] = normalizedState ;
426477 }
427478 }
428479 }
@@ -862,33 +913,16 @@ function evaluateWorkspaceState(workspaceRoot, options) {
862913 } ;
863914}
864915
865- function getGlobalTargetPaths ( globalRoot , targetName ) {
866- if ( targetName === "codex" ) {
867- return {
868- markerDir : path . join ( globalRoot , ".agents" ) ,
869- skillsRoot : path . join ( globalRoot , ".agents" , "skills" ) ,
870- } ;
871- }
872- if ( targetName === "gemini" ) {
873- return {
874- markerDir : path . join ( globalRoot , ".gemini" , "antigravity" ) ,
875- skillsRoot : path . join ( globalRoot , ".gemini" , "antigravity" , "skills" ) ,
876- } ;
877- }
878- throw new Error ( `未知全局目标: ${ targetName } ` ) ;
879- }
880-
881916function evaluateGlobalState ( ) {
882917 const globalRoot = resolveGlobalRootDir ( ) ;
883- const targetStates = SUPPORTED_TARGETS . map ( ( targetName ) => {
884- const paths = getGlobalTargetPaths ( globalRoot , targetName ) ;
885- const markerExists = fs . existsSync ( paths . markerDir ) ;
886- const skillsExists = fs . existsSync ( paths . skillsRoot ) ;
887- const skillsCount = skillsExists ? countSkillsRecursive ( paths . skillsRoot ) : 0 ;
918+ const targetStates = listGlobalDestinations ( globalRoot ) . map ( ( destination ) => {
919+ const rootExists = fs . existsSync ( destination . rootDir ) ;
920+ const skillsExists = fs . existsSync ( destination . skillsRoot ) ;
921+ const skillsCount = skillsExists ? countSkillsRecursive ( destination . skillsRoot ) : 0 ;
888922 let state = "missing" ;
889923 const issues = [ ] ;
890924
891- if ( markerExists || skillsExists ) {
925+ if ( rootExists || skillsExists ) {
892926 if ( ! skillsExists ) {
893927 state = "broken" ;
894928 issues . push ( "Skills 根目录缺失" ) ;
@@ -901,10 +935,11 @@ function evaluateGlobalState() {
901935 }
902936
903937 return {
904- targetName,
938+ targetName : destination . id ,
939+ family : destination . targetName ,
905940 state,
906- markerDir : paths . markerDir ,
907- skillsRoot : paths . skillsRoot ,
941+ rootDir : destination . rootDir ,
942+ skillsRoot : destination . skillsRoot ,
908943 skillsCount,
909944 issues,
910945 } ;
@@ -972,7 +1007,7 @@ function resolveTargetsForGlobalSync(options) {
9721007 if ( requested . length > 0 ) {
9731008 return requested ;
9741009 }
975- // 保持 global sync 简洁:默认同步两个目标 。
1010+ // 保持 global sync 简洁:默认同步 codex + gemini;其中 gemini 会展开为 gemini-cli 与 antigravity 。
9761011 return [ "codex" , "gemini" ] ;
9771012}
9781013
@@ -1025,58 +1060,87 @@ function backupSkillDirectory(targetName, skillName, sourceDir, timestamp, optio
10251060 log ( options , `📦 已备份 ${ targetName } 全局 Skill: ${ skillName } -> ${ backupDir } ` ) ;
10261061}
10271062
1028- function syncSkillDirectory ( targetName , srcDir , destDir , timestamp , options ) {
1063+ function syncSkillDirectory ( destination , srcDir , destDir , timestamp , options ) {
10291064 const exists = fs . existsSync ( destDir ) ;
10301065 if ( exists ) {
10311066 if ( areDirectoriesEqual ( srcDir , destDir ) ) {
1032- log ( options , `⏭️ 全局 Skill 已最新,无需同步: ${ targetName } /${ path . basename ( destDir ) } ` ) ;
1067+ log ( options , `⏭️ 全局 Skill 已最新,无需同步: ${ destination . id } /${ path . basename ( destDir ) } ` ) ;
10331068 return { skipped : 1 , synced : 0 , backedUp : 0 } ;
10341069 }
10351070 }
10361071
10371072 if ( options . dryRun ) {
1038- log ( options , `[dry-run] 将同步全局 Skill: ${ targetName } /${ path . basename ( destDir ) } ` ) ;
1073+ log ( options , `[dry-run] 将同步全局 Skill: ${ destination . id } /${ path . basename ( destDir ) } ` ) ;
10391074 return { skipped : 0 , synced : 0 , backedUp : exists ? 1 : 0 } ;
10401075 }
10411076
10421077 let backedUp = 0 ;
10431078 if ( exists ) {
1044- backupSkillDirectory ( targetName , path . basename ( destDir ) , destDir , timestamp , options ) ;
1079+ backupSkillDirectory ( destination . id , path . basename ( destDir ) , destDir , timestamp , options ) ;
10451080 backedUp = 1 ;
10461081 }
10471082
10481083 const logger = options . quiet ? ( ( ) => { } ) : log . bind ( null , options ) ;
10491084 AtomicWriter . atomicCopyDir ( srcDir , destDir , { logger } ) ;
1050- log ( options , `✅ 已同步全局 Skill: ${ targetName } /${ path . basename ( destDir ) } ` ) ;
1085+ log ( options , `✅ 已同步全局 Skill: ${ destination . id } /${ path . basename ( destDir ) } ` ) ;
10511086
10521087 return { skipped : 0 , synced : 1 , backedUp } ;
10531088}
10541089
10551090function syncGlobalSkillsFromRoot ( targetName , skillsRoot , timestamp , options ) {
1056- const destRoot = resolveGlobalSkillRoot ( targetName ) ;
1091+ const destinations = getGlobalDestinations ( targetName ) ;
10571092 const skillNames = listSkillDirectories ( skillsRoot ) ;
10581093 if ( skillNames . length === 0 ) {
10591094 throw new Error ( `未检测到可同步的 Skills: ${ skillsRoot } ` ) ;
10601095 }
10611096
10621097 if ( options . dryRun ) {
1063- log ( options , `[dry-run] 将同步 ${ skillNames . length } 个全局 Skills -> ${ destRoot } ` ) ;
1098+ for ( const destination of destinations ) {
1099+ log ( options , `[dry-run] 将同步 ${ skillNames . length } 个全局 Skills -> ${ destination . skillsRoot } ` ) ;
1100+ }
10641101 }
10651102
10661103 let synced = 0 ;
10671104 let skipped = 0 ;
10681105 let backedUp = 0 ;
1106+ const destinationResults = [ ] ;
1107+
1108+ for ( const destination of destinations ) {
1109+ let destinationSynced = 0 ;
1110+ let destinationSkipped = 0 ;
1111+ let destinationBackedUp = 0 ;
1112+
1113+ for ( const skillName of skillNames ) {
1114+ const srcDir = path . join ( skillsRoot , skillName ) ;
1115+ const destDir = path . join ( destination . skillsRoot , skillName ) ;
1116+ const result = syncSkillDirectory ( destination , srcDir , destDir , timestamp , options ) ;
1117+ synced += result . synced ;
1118+ skipped += result . skipped ;
1119+ backedUp += result . backedUp ;
1120+ destinationSynced += result . synced ;
1121+ destinationSkipped += result . skipped ;
1122+ destinationBackedUp += result . backedUp ;
1123+ }
10691124
1070- for ( const skillName of skillNames ) {
1071- const srcDir = path . join ( skillsRoot , skillName ) ;
1072- const destDir = path . join ( destRoot , skillName ) ;
1073- const result = syncSkillDirectory ( targetName , srcDir , destDir , timestamp , options ) ;
1074- synced += result . synced ;
1075- skipped += result . skipped ;
1076- backedUp += result . backedUp ;
1125+ destinationResults . push ( {
1126+ targetName : destination . id ,
1127+ family : destination . targetName ,
1128+ destRoot : destination . skillsRoot ,
1129+ total : skillNames . length ,
1130+ synced : destinationSynced ,
1131+ skipped : destinationSkipped ,
1132+ backedUp : destinationBackedUp ,
1133+ } ) ;
10771134 }
10781135
1079- return { total : skillNames . length , synced, skipped, backedUp, destRoot } ;
1136+ return {
1137+ total : skillNames . length * destinations . length ,
1138+ skillsPerDestination : skillNames . length ,
1139+ synced,
1140+ skipped,
1141+ backedUp,
1142+ destinations : destinationResults ,
1143+ } ;
10801144}
10811145
10821146function applyGlobalSync ( targetName , agentDir , timestamp , options ) {
@@ -1116,7 +1180,9 @@ async function commandGlobalSync(options) {
11161180 const result = applyGlobalSync ( target , agentDir , timestamp , options ) ;
11171181 if ( ! options . dryRun ) {
11181182 log ( options , `📊 全局同步完成 [${ target } ]:总计 ${ result . total } ,新增/覆盖 ${ result . synced } ,跳过 ${ result . skipped } ,备份 ${ result . backedUp } ` ) ;
1119- log ( options , ` 目标路径: ${ result . destRoot } ` ) ;
1183+ for ( const item of result . destinations ) {
1184+ log ( options , ` - ${ item . targetName } : ${ item . destRoot } (每目标 ${ item . total } 个 Skills)` ) ;
1185+ }
11201186 }
11211187 }
11221188 } finally {
@@ -1152,6 +1218,7 @@ function commandGlobalStatus(options) {
11521218
11531219 for ( const item of summary . targets ) {
11541220 console . log ( `\n[${ item . targetName } :global]` ) ;
1221+ console . log ( ` 家族: ${ item . family } ` ) ;
11551222 console . log ( ` 状态: ${ item . state } ` ) ;
11561223 console . log ( ` 路径: ${ item . skillsRoot } ` ) ;
11571224 if ( item . state === "installed" ) {
0 commit comments