ai-agent-config 2.2.2 → 2.4.1

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.
@@ -0,0 +1,236 @@
1
+ ---
2
+ name: ai-agent-config
3
+ description: Manage AI coding skills across platforms (Claude Code, Antigravity, Cursor, Windsurf) using ai-agent-config CLI. Use when the user wants to sync skills to/from GitHub, install to multiple platforms, add custom skill sources, or configure skill management settings.
4
+ ---
5
+
6
+ # AI Agent Config Management
7
+
8
+ Complete guide for the `ai-agent-config` CLI tool - universal skill management across AI coding platforms.
9
+
10
+ ## Core Commands
11
+
12
+ ### GitHub Sync
13
+
14
+ ```bash
15
+ # Initialize with repository
16
+ ai-agent init --repo https://github.com/username/my-skills.git
17
+
18
+ # Push local skills to GitHub
19
+ ai-agent push --message "Added new skills"
20
+
21
+ # Pull skills from GitHub
22
+ ai-agent pull
23
+
24
+ # Bi-directional sync
25
+ ai-agent sync --message "Sync latest"
26
+ ```
27
+
28
+ ### Installation
29
+
30
+ ```bash
31
+ # Install to all detected platforms
32
+ ai-agent install
33
+
34
+ # Force reinstall
35
+ ai-agent install --force
36
+
37
+ # Install specific skill
38
+ ai-agent install --skill backend-patterns
39
+ ```
40
+
41
+ ### Source Management
42
+
43
+ ```bash
44
+ # Add custom source
45
+ ai-agent source add https://github.com/company/skills.git \
46
+ --name company-skills \
47
+ --branch main
48
+
49
+ # List sources
50
+ ai-agent source list
51
+
52
+ # Enable/disable
53
+ ai-agent source enable company-skills
54
+ ai-agent source disable company-skills
55
+ ```
56
+
57
+ ### Configuration
58
+
59
+ ```bash
60
+ # Get/set config values
61
+ ai-agent config get repository.url
62
+ ai-agent config set repository.autoSync true
63
+
64
+ # Edit in $EDITOR
65
+ ai-agent config edit
66
+
67
+ # Validate config
68
+ ai-agent config validate
69
+ ```
70
+
71
+ ### Platform Info
72
+
73
+ ```bash
74
+ # Show detected platforms
75
+ ai-agent platforms
76
+
77
+ # List installed skills
78
+ ai-agent list
79
+ ```
80
+
81
+ ## Common Workflows
82
+
83
+ ### First-Time Setup
84
+
85
+ **User**: "Set up ai-agent-config with my GitHub"
86
+
87
+ **Assistant**:
88
+ ```bash
89
+ # Initialize with your repository
90
+ ai-agent init --repo https://github.com/yourname/my-ai-skills.git
91
+
92
+ # This will:
93
+ # 1. Create ~/.ai-agent/config.json
94
+ # 2. Clone your repo to ~/.ai-agent/sync-repo
95
+ # 3. Enable auto-sync (pull before push)
96
+
97
+ # Push current skills
98
+ ai-agent push --message "Initial setup"
99
+ ```
100
+
101
+ ### Daily Workflow
102
+
103
+ **User**: "Update all my skills"
104
+
105
+ **Assistant**:
106
+ ```bash
107
+ # Pull latest from GitHub (auto-installs)
108
+ ai-agent pull
109
+ ```
110
+
111
+ ### Adding Custom Skills
112
+
113
+ **User**: "Add skills from my company repo"
114
+
115
+ **Assistant**:
116
+ ```bash
117
+ # Add custom source
118
+ ai-agent source add https://github.com/company/ai-skills.git \
119
+ --name company-skills \
120
+ --branch main
121
+
122
+ # Update from new source (auto-installs)
123
+ ai-agent update --source company-skills
124
+ ```
125
+
126
+ ### Team Sharing
127
+
128
+ **User**: "Share my skills with team"
129
+
130
+ **Assistant**:
131
+ ```bash
132
+ # Push to GitHub
133
+ ai-agent push --message "Added debugging skills"
134
+
135
+ # Team members pull (auto-installs)
136
+ ai-agent pull
137
+ ```
138
+
139
+ ## Architecture
140
+
141
+ ### File Locations
142
+ - **Config**: `~/.ai-agent/config.json`
143
+ - **Sync Repo**: `~/.ai-agent/sync-repo/` (local clone)
144
+ - **Cache**: `~/.ai-agent-config-cache/` (external sources)
145
+
146
+ ### Platform Paths
147
+ - Claude Code: `~/.claude/skills/`
148
+ - Antigravity: `~/.gemini/antigravity/skills/`
149
+ - Cursor: `~/.cursor/skills/`
150
+ - Windsurf: `~/.windsurf/skills/`
151
+ - Codex: `~/.codex/skills/`
152
+
153
+ ## Configuration
154
+
155
+ Key config settings:
156
+
157
+ ```json
158
+ {
159
+ "repository": {
160
+ "url": "https://github.com/username/skills.git",
161
+ "branch": "main",
162
+ "autoSync": true
163
+ },
164
+ "sources": {
165
+ "official": [...],
166
+ "custom": [...]
167
+ }
168
+ }
169
+ ```
170
+
171
+ ## Examples
172
+
173
+ ### Setup for Team
174
+
175
+ ```bash
176
+ # Create shared repository
177
+ ai-agent init --repo https://github.com/team/shared-skills.git
178
+
179
+ # Add company skills
180
+ ai-agent source add https://github.com/company/official-skills.git \
181
+ --name company
182
+
183
+ # Push setup
184
+ ai-agent push --message "Team setup complete"
185
+ ```
186
+
187
+ ### Migration
188
+
189
+ ```bash
190
+ # Initialize ai-agent-config
191
+ ai-agent init --repo https://github.com/username/skills.git
192
+
193
+ # Install to all platforms
194
+ ai-agent install --force
195
+
196
+ # Push existing skills
197
+ ai-agent push --message "Migrated to ai-agent-config"
198
+ ```
199
+
200
+ ## Troubleshooting
201
+
202
+ ### Skills Not Installing
203
+
204
+ ```bash
205
+ # Force reinstall
206
+ ai-agent install --force
207
+
208
+ # Check platforms detected
209
+ ai-agent platforms
210
+ ```
211
+
212
+ ### GitHub Sync Conflicts
213
+
214
+ Auto-sync handles most conflicts automatically. If issues persist:
215
+
216
+ ```bash
217
+ cd ~/.ai-agent/sync-repo
218
+ git status
219
+ ```
220
+
221
+ ### Config Issues
222
+
223
+ ```bash
224
+ # Validate
225
+ ai-agent config validate
226
+
227
+ # Reset if corrupted
228
+ ai-agent config reset
229
+ ```
230
+
231
+ ## Tips
232
+
233
+ - **Auto-Sync**: Keep enabled to prevent conflicts
234
+ - **Regular Pulls**: Pull frequently for latest skills
235
+ - **Descriptive Messages**: Use `--message` for clear commit messages
236
+ - **Force Reinstall**: Use `--force` when skills aren't updating
package/README.md CHANGED
@@ -21,19 +21,19 @@
21
21
  # Install globally
22
22
  npm install -g ai-agent-config
23
23
 
24
- # Initialize (creates config at ~/.ai-agent/config.json)
25
- ai-agent init
24
+ # Initialize (optional)
25
+ ai-agent init --repo https://github.com/youruser/my-ai-skills.git
26
26
 
27
- # Install bundled skills to platforms
28
- ai-agent install
27
+ # Pull and auto-install
28
+ ai-agent pull
29
29
  ```
30
30
 
31
31
  ## 🎯 Bundled Skills (2)
32
32
 
33
33
  The package includes 2 core skills for managing the system:
34
34
 
35
- 1. **config-manager** - Manage configuration and custom sources
36
- 2. **skill-updater** - Update skills from GitHub repositories
35
+ 1. **config-manager** - Manage configuration and custom sources
36
+ 2. **skill-updater** - Update skills from GitHub repositories
37
37
 
38
38
  ## 📚 Add More Skills
39
39
 
@@ -80,9 +80,8 @@ ai-agent config reset --yes # Reset to defaults
80
80
 
81
81
  ### Installation & Updates
82
82
  ```bash
83
- ai-agent init # Initialize/migrate to v2.0
84
- ai-agent update [--source name] # Update skills from sources
85
- ai-agent install [--platform name] # Install to platforms
83
+ ai-agent init # Initialize/migrate config
84
+ ai-agent pull # Pull + auto-install from GitHub
86
85
  ai-agent list # List installed skills
87
86
  ai-agent platforms # Show detected platforms
88
87
  ai-agent uninstall # Remove skills
package/bin/cli.js CHANGED
@@ -1,28 +1,25 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- /**
4
- * AI Agent Config CLI v2.0
5
- * Universal Global Skills for AI Coding Assistants
6
- */
7
-
8
3
  const fs = require("fs");
9
4
  const path = require("path");
10
5
  const { execSync } = require("child_process");
11
-
12
- const platforms = require("../scripts/platforms");
13
- const installer = require("../scripts/installer");
14
- const externalSync = require("../scripts/external-sync");
15
6
  const configManager = require("../scripts/config-manager");
7
+ const installer = require("../scripts/installer");
8
+ const platforms = require("../scripts/platforms");
16
9
  const migration = require("../scripts/migration");
17
10
 
18
- // Read version from package.json
19
- const packageJson = require("../package.json");
20
- const VERSION = packageJson.version;
11
+ const VERSION = "2.4.1";
12
+
13
+ // Get package root (one level up from bin/)
14
+ const PACKAGE_ROOT = path.join(__dirname, "..");
21
15
 
16
+ // Commands with descriptions
22
17
  const COMMANDS = {
23
- // v2.0 New Commands
24
- init: "Initialize or migrate to v2.0 config",
18
+ // v2.3 New Commands
19
+ init: "Initialize or migrate config",
25
20
  migrate: "Migrate from v1.x to v2.0",
21
+ push: "Push skills to GitHub repository",
22
+ pull: "Pull skills from GitHub repository",
26
23
 
27
24
  // Source Management
28
25
  "source add": "Add a custom skill source",
@@ -44,7 +41,7 @@ const COMMANDS = {
44
41
  // Original Commands (updated)
45
42
  install: "Install skills to detected platforms",
46
43
  update: "Update skills from all sources",
47
- sync: "Sync skills from GitHub repository",
44
+ sync: "Bi-directional sync (pull + push)",
48
45
  list: "List installed skills",
49
46
  platforms: "Show detected platforms",
50
47
  uninstall: "Remove installed skills",
@@ -91,24 +88,32 @@ Usage: ai-agent <command> [options]
91
88
  🔧 Installation & Sync:
92
89
  install [opts] Install skills to platforms
93
90
  update [opts] Update all skills from sources
94
- list List installed skills
95
- platforms Show detected platforms
96
- uninstall [opts] Remove installed skills
97
-
98
- Options:
99
- --platform <name> Target specific platform
100
- --skill <name> Target specific skill
101
- --source <name> Target specific source
102
- --force Force overwrite
103
- --branch <name> Git branch (for source add)
104
- --merge Merge on import (don't replace)
105
-
106
- Examples:
107
- # Initialize v2.0 config
108
- ai-agent init
109
-
110
- # Add your company's skills
111
- ai-agent source add https://github.com/mycompany/ai-skills \\
91
+ list List installed ai-agent update [--source <name>] # Update from specific source
92
+
93
+ # Installation
94
+ ai-agent install # Install to all detected platforms
95
+ ai-agent install --force # Force reinstall
96
+ ai-agent install --skill <name> # Install specific skill
97
+
98
+ # List skills
99
+ ai-agent list # List installed skills
100
+
101
+ 🌐 Examples:
102
+
103
+ # Initialize with GitHub repository (v2.3)
104
+ ai-agent init --repo https://github.com/yourname/my-ai-skills.git
105
+
106
+ # Push skills to GitHub
107
+ ai-agent push --message "Added new skills"
108
+
109
+ # Pull latest skills from GitHub
110
+ ai-agent pull
111
+
112
+ # Bi-directional sync
113
+ ai-agent sync
114
+
115
+ # Add a source
116
+ ai-agent source add https://github.com/user/repo.git --name my-sourcekills \\
112
117
  --branch main \\
113
118
  --name company-skills
114
119
 
@@ -194,10 +199,23 @@ function listSkills() {
194
199
  console.log("");
195
200
  }
196
201
 
202
+ /**
203
+ * Get argument value by flag name
204
+ */
205
+ function getArgValue(args, flag) {
206
+ for (let i = 0; i < args.length; i++) {
207
+ if (args[i] === flag && args[i + 1]) {
208
+ return args[i + 1];
209
+ }
210
+ }
211
+ return null;
212
+ }
213
+
197
214
  function init(args) {
198
- console.log("\n🚀 Initializing AI Agent Config v2.0...\n");
215
+ console.log("\n🚀 Initializing AI Agent Config...\n");
199
216
 
200
217
  const force = args.includes("--force");
218
+ const repoUrl = getArgValue(args, "--repo");
201
219
 
202
220
  // Check if migration needed
203
221
  if (migration.needsMigration()) {
@@ -213,9 +231,37 @@ function init(args) {
213
231
  console.log("🔄 Resetting config...");
214
232
  configManager.resetConfig();
215
233
  console.log("✅ Config reset to defaults\n");
216
- } else {
234
+ } else if (!repoUrl) {
217
235
  console.log("\n💡 Use --force to reset config to defaults");
236
+ console.log("💡 Use --repo <url> to initialize with a repository");
237
+ }
238
+ }
239
+
240
+ // Handle --repo flag
241
+ if (repoUrl) {
242
+ console.log(`\n📦 Setting up repository: ${repoUrl}`);
243
+
244
+ const config = configManager.loadConfig();
245
+ const localPath = path.join(process.env.HOME || process.env.USERPROFILE, ".ai-agent", "sync-repo");
246
+
247
+ // Clone if not exists
248
+ if (!fs.existsSync(localPath)) {
249
+ try {
250
+ console.log(`🔄 Cloning repository to ${localPath}...`);
251
+ execSync(`git clone "${repoUrl}" "${localPath}"`, { stdio: "inherit" });
252
+ console.log("✅ Repository cloned successfully!");
253
+ } catch (error) {
254
+ console.error(`❌ Failed to clone repository: ${error.message}\n`);
255
+ return;
256
+ }
257
+ } else {
258
+ console.log(`⚠️ Directory ${localPath} already exists, skipping clone`);
218
259
  }
260
+
261
+ // Update config
262
+ configManager.setConfigValue("repository.url", repoUrl);
263
+ configManager.setConfigValue("repository.local", localPath);
264
+ console.log("✅ Repository configured!\n");
219
265
  }
220
266
 
221
267
  const detected = platforms.detectAll();
@@ -225,9 +271,14 @@ function init(args) {
225
271
  }
226
272
 
227
273
  console.log("\n📚 Next steps:");
228
- console.log(" 1. ai-agent update # Update skills from sources");
229
- console.log(" 2. ai-agent install # Install to platforms");
230
- console.log(" 3. ai-agent source add ... # Add custom sources");
274
+ if (repoUrl) {
275
+ console.log(" 1. ai-agent push # Push skills to repository");
276
+ console.log(" 2. ai-agent pull # Pull skills from repository");
277
+ } else {
278
+ console.log(" 1. ai-agent update # Update skills from sources");
279
+ console.log(" 2. ai-agent install # Install to platforms");
280
+ console.log(" 3. ai-agent source add ... # Add custom sources");
281
+ }
231
282
  console.log("");
232
283
  }
233
284
 
@@ -590,16 +641,13 @@ function install(args) {
590
641
  console.log("\n📥 Installing skills...\n");
591
642
 
592
643
  const options = {
593
- platform: null,
594
644
  force: false,
595
645
  skill: null,
596
646
  sync: true,
597
647
  };
598
648
 
599
649
  for (let i = 0; i < args.length; i++) {
600
- if (args[i] === "--platform" && args[i + 1]) {
601
- options.platform = args[++i];
602
- } else if (args[i] === "--force") {
650
+ if (args[i] === "--force") {
603
651
  options.force = true;
604
652
  } else if (args[i] === "--skill" && args[i + 1]) {
605
653
  options.skill = args[++i];
@@ -681,25 +729,118 @@ function update(args) {
681
729
  }
682
730
  }
683
731
 
684
- function sync(args) {
685
- console.log("\n🔄 Syncing from GitHub repository...\n");
732
+ /**
733
+ * Push skills to GitHub repository
734
+ */
735
+ function push(args) {
736
+ console.log("\\n⬆️ Pushing to GitHub...\\n");
737
+
738
+ const config = configManager.loadConfig();
739
+
740
+ if (!config.repository.url) {
741
+ console.error("❌ No repository configured");
742
+ console.log("\\n Run: ai-agent init --repo <url>\\n");
743
+ process.exit(1);
744
+ }
745
+
746
+ const SyncManager = require("../scripts/sync-manager");
747
+ const syncManager = new SyncManager(config);
748
+
749
+ const options = {
750
+ message: getArgValue(args, "--message") || "Update skills and workflows",
751
+ };
752
+
753
+ try {
754
+ const result = syncManager.push(options);
755
+
756
+ if (result.pushed) {
757
+ console.log("✅ Pushed successfully!");
758
+ console.log(` Repository: ${config.repository.url}\\n`);
759
+ } else {
760
+ console.log(`⚠️ ${result.reason}`);
761
+
762
+ if (result.conflicts && result.conflicts.length > 0) {
763
+ console.log("\\n Conflicting files:");
764
+ result.conflicts.forEach((f) => console.log(` - ${f}`));
765
+ console.log("\\n Resolve conflicts manually and try again.\\n");
766
+ process.exit(1);
767
+ }
768
+ }
769
+ } catch (error) {
770
+ console.error(`❌ Push failed: ${error.message}\\n`);
771
+ process.exit(1);
772
+ }
773
+ }
774
+
775
+ /**
776
+ * Pull skills from GitHub repository
777
+ */
778
+ function pull(args) {
779
+ console.log("\n⬇️ Pulling from GitHub...\n");
780
+
781
+ const config = configManager.loadConfig();
782
+
783
+ if (!config.repository.url) {
784
+ console.error("❌ No repository configured");
785
+ console.log("\n Run: ai-agent init <url>\n");
786
+ process.exit(1);
787
+ }
788
+
789
+ const SyncManager = require("../scripts/sync-manager");
790
+ const syncManager = new SyncManager(config);
791
+
792
+ try {
793
+ const result = syncManager.pull();
794
+
795
+ if (result.pulled) {
796
+ console.log("✅ Pulled successfully!\n");
797
+
798
+ // Auto-install after pull (unless --no-install flag)
799
+ const noInstall = args.includes("--no-install");
800
+
801
+ if (!noInstall) {
802
+ console.log("📥 Auto-installing skills...\n");
803
+ install(["--force"]); // Force install to ensure latest
804
+ }
805
+ } else {
806
+ console.log(`⚠️ ${result.reason || "Pull failed"}`);
807
+
808
+ if (result.conflicts && result.conflicts.length > 0) {
809
+ console.log("\n Conflicts in:");
810
+ result.conflicts.forEach((f) => console.log(` - ${f}`));
811
+ console.log("\n Resolve manually and commit.\n");
812
+ process.exit(1);
813
+ }
814
+ }
815
+ } catch (error) {
816
+ console.error(`❌ Pull failed: ${error.message}\n`);
817
+ process.exit(1);
818
+ }
819
+ }
820
+
821
+
822
+ /**
823
+ * Old sync function (backward compatibility)
824
+ */
825
+ function oldSync(args) {
826
+ console.log("\\n🔄 Syncing from GitHub repository...\\n");
686
827
  console.log(` Repository: ${installer.REPO_URL}`);
687
- console.log(` Cache: ${installer.CACHE_DIR}\n`);
828
+ console.log(` Cache: ${installer.CACHE_DIR}\\n`);
688
829
 
689
830
  try {
690
831
  const success = installer.syncRepo();
691
832
 
692
833
  if (success) {
693
- console.log("\n✓ Sync complete!\n");
834
+ console.log("\\n✓ Sync complete!\\n");
694
835
 
695
836
  const skills = installer.getAvailableSkills();
696
837
  const workflows = installer.getAvailableWorkflows();
697
838
 
698
839
  console.log(` Found ${skills.length} skill(s), ${workflows.length} workflow(s)`);
699
- console.log("\n Run 'ai-agent install' to install to your platforms.\n");
840
+ console.log("\\n Run 'ai-agent install' to install to your platforms.\\n");
700
841
  }
701
842
  } catch (error) {
702
- console.error(`\n❌ Sync failed: ${error.message}`);
843
+ console.error(`\\n❌ Sync failed: ${error.message}`);
703
844
  process.exit(1);
704
845
  }
705
846
  }
@@ -818,15 +959,19 @@ if (command === "source") {
818
959
  case "migrate":
819
960
  migrateCmd(args.slice(1));
820
961
  break;
962
+ case "push":
963
+ push(args.slice(1));
964
+ break;
965
+ case "pull":
966
+ pull(args.slice(1));
967
+ break;
821
968
  case "install":
822
969
  install(args.slice(1));
823
970
  break;
824
971
  case "update":
825
972
  update(args.slice(1));
826
973
  break;
827
- case "sync":
828
- sync(args.slice(1));
829
- break;
974
+
830
975
  case "sync-external":
831
976
  // Backward compatibility - alias for update
832
977
  update(args.slice(1));
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ai-agent-config",
3
- "version": "2.2.2",
4
- "description": "Universal Global Skills & Workflows for AI Coding Assistants (Claude Code, Antigravity, Cursor) - v2.0: User-configurable skill sources",
3
+ "version": "2.4.1",
4
+ "description": "Universal skill & workflow manager for AI coding assistants with bi-directional GitHub sync",
5
5
  "main": "index.js",
6
6
  "bin": {
7
7
  "ai-agent": "./bin/cli.js"
@@ -46,4 +46,4 @@
46
46
  "index.js",
47
47
  "README.md"
48
48
  ]
49
- }
49
+ }
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Config Manager Module
3
- * Manages user configuration for ai-agent-config v2.0
3
+ * Manages user configuration for ai-agent-config v2.3
4
4
  */
5
5
 
6
6
  const fs = require("fs");
@@ -49,16 +49,21 @@ function loadOfficialSources() {
49
49
  */
50
50
  function createDefaultConfig() {
51
51
  const config = {
52
- version: "2.0",
52
+ version: "2.3",
53
+ repository: {
54
+ url: null,
55
+ branch: "main",
56
+ local: path.join(os.homedir(), ".ai-agent", "sync-repo"),
57
+ lastSync: null,
58
+ autoSync: true,
59
+ },
60
+ sync: {
61
+ conflictResolution: "pull-first",
62
+ },
53
63
  sources: {
54
64
  official: loadOfficialSources().map((s) => ({ ...s, enabled: true })),
55
65
  custom: [],
56
66
  },
57
- sync: {
58
- enabled: false,
59
- provider: null,
60
- config: {},
61
- },
62
67
  preferences: {
63
68
  autoUpdate: true,
64
69
  updateInterval: "weekly",
@@ -90,6 +95,35 @@ function initConfig(force = false) {
90
95
  return { created: true, path: CONFIG_FILE };
91
96
  }
92
97
 
98
+ /**
99
+ * Migrate config from older versions to v2.3
100
+ */
101
+ function migrateConfig(oldConfig) {
102
+ const newConfig = {
103
+ version: "2.3",
104
+ repository: {
105
+ url: null,
106
+ branch: "main",
107
+ local: path.join(os.homedir(), ".ai-agent", "sync-repo"),
108
+ lastSync: null,
109
+ autoSync: true,
110
+ },
111
+ sync: {
112
+ conflictResolution: "pull-first",
113
+ },
114
+ sources: oldConfig.sources || {
115
+ official: loadOfficialSources().map((s) => ({ ...s, enabled: true })),
116
+ custom: [],
117
+ },
118
+ preferences: oldConfig.preferences || {
119
+ autoUpdate: true,
120
+ updateInterval: "weekly",
121
+ },
122
+ };
123
+
124
+ return newConfig;
125
+ }
126
+
93
127
  /**
94
128
  * Load user config
95
129
  */
@@ -101,7 +135,17 @@ function loadConfig() {
101
135
  }
102
136
 
103
137
  const data = fs.readFileSync(CONFIG_FILE, "utf-8");
104
- return JSON.parse(data);
138
+ let config = JSON.parse(data);
139
+
140
+ // Auto-migrate from v2.0/v2.2 to v2.3
141
+ if (config.version !== "2.3") {
142
+ console.log(`🔄 Migrating config from v${config.version} to v2.3...`);
143
+ config = migrateConfig(config);
144
+ saveConfig(config);
145
+ console.log("✅ Config migrated successfully!");
146
+ }
147
+
148
+ return config;
105
149
  }
106
150
 
107
151
  /**
@@ -144,6 +188,23 @@ function validateConfig(config) {
144
188
  }
145
189
  }
146
190
 
191
+ // V2.3 validation
192
+ if (config.version === "2.3") {
193
+ if (!config.repository) {
194
+ errors.push("Missing repository field in v2.3 config");
195
+ } else {
196
+ if (config.repository.url && typeof config.repository.url !== "string") {
197
+ errors.push("repository.url must be a string");
198
+ }
199
+ if (config.repository.branch && typeof config.repository.branch !== "string") {
200
+ errors.push("repository.branch must be a string");
201
+ }
202
+ if (config.repository.autoSync !== undefined && typeof config.repository.autoSync !== "boolean") {
203
+ errors.push("repository.autoSync must be a boolean");
204
+ }
205
+ }
206
+ }
207
+
147
208
  return {
148
209
  valid: errors.length === 0,
149
210
  errors,
@@ -375,6 +436,7 @@ module.exports = {
375
436
  loadOfficialSources,
376
437
  createDefaultConfig,
377
438
  initConfig,
439
+ migrateConfig,
378
440
  loadConfig,
379
441
  saveConfig,
380
442
  validateConfig,
@@ -81,12 +81,12 @@ function isRepoCached() {
81
81
 
82
82
  /**
83
83
  * Get list of available skills
84
- * Priority: Package bundled skills > External repo cache
84
+ * Merges package bundled skills + external repo cache
85
85
  */
86
86
  function getAvailableSkills() {
87
87
  const skills = new Set();
88
88
 
89
- // Try package bundled skills first (.agent/skills/)
89
+ // Add package bundled skills first (.agent/skills/)
90
90
  if (fs.existsSync(PACKAGE_SKILLS_DIR)) {
91
91
  const packageSkills = fs.readdirSync(PACKAGE_SKILLS_DIR);
92
92
  packageSkills.forEach((name) => {
@@ -97,13 +97,10 @@ function getAvailableSkills() {
97
97
  }
98
98
  });
99
99
 
100
- // If package has bundled skills, return only those (don't merge with cache)
101
- if (skills.size > 0) {
102
- return Array.from(skills);
103
- }
100
+
104
101
  }
105
102
 
106
- // Fallback: Get skills from external repo cache (only if no package skills)
103
+ // Merge with skills from external repo cache
107
104
  if (fs.existsSync(REPO_SKILLS_DIR)) {
108
105
  fs.readdirSync(REPO_SKILLS_DIR).forEach((name) => {
109
106
  const skillPath = path.join(REPO_SKILLS_DIR, name);
@@ -240,7 +237,7 @@ function installToPlatform(platform, options = {}) {
240
237
  * Install skills to all detected platforms
241
238
  */
242
239
  function install(options = {}) {
243
- const { platform = null, force = false, skill = null, sync = true } = options;
240
+ const { force = false, skill = null, sync = true } = options;
244
241
 
245
242
  // Sync repo first if needed
246
243
  if (sync && !isRepoCached()) {
@@ -251,29 +248,17 @@ function install(options = {}) {
251
248
  }
252
249
 
253
250
  if (!isRepoCached()) {
254
- console.log("\n⚠️ Skills repository not cached. Run 'ai-agent sync' first.");
255
- return { skillsCount: 0, platformsCount: 0, details: [] };
251
+ console.log("\n⚠️ Skills repository not cached. Run 'ai-agent update' first.");
252
+ return { skillsCount: 0, platformsCount: 0, workflowsCount: 0, details: [] };
256
253
  }
257
254
 
258
- let targetPlatforms;
259
-
260
- if (platform) {
261
- const platformObj = platforms.getByName(platform);
262
- if (!platformObj) {
263
- throw new Error(
264
- `Unknown platform: ${platform}. Available: ${platforms.getAllNames().join(", ")}`
265
- );
266
- }
267
- targetPlatforms = [platformObj];
268
- } else {
269
- targetPlatforms = platforms.detectAll().map((p) => platforms.getByName(p.name));
270
- }
255
+ // Always install to all detected platforms
256
+ const targetPlatforms = platforms.detectAll().map((p) => platforms.getByName(p.name));
271
257
 
272
258
  if (targetPlatforms.length === 0) {
273
259
  console.log("\n⚠️ No AI coding platforms detected.");
274
260
  console.log(" Supported platforms:", platforms.getAllNames().join(", "));
275
- console.log("\n Force install with: ai-agent install --platform <name>");
276
- return { skillsCount: 0, platformsCount: 0, details: [] };
261
+ return { skillsCount: 0, platformsCount: 0, workflowsCount: 0, details: [] };
277
262
  }
278
263
 
279
264
  const details = [];
@@ -0,0 +1,234 @@
1
+ /**
2
+ * Sync Manager Module
3
+ * Handles pushing/pulling skills to/from GitHub repository
4
+ */
5
+
6
+ const fs = require("fs");
7
+ const path = require("path");
8
+ const { execSync } = require("child_process");
9
+
10
+ class SyncManager {
11
+ constructor(config) {
12
+ this.config = config;
13
+ this.repoPath = this.expandPath(config.repository.local);
14
+ }
15
+
16
+ /**
17
+ * Push local changes to GitHub
18
+ */
19
+ push(options = {}) {
20
+ if (!this.config.repository.url) {
21
+ return { pushed: false, reason: "No repository configured" };
22
+ }
23
+
24
+ // 1. Check if repo exists locally
25
+ if (!fs.existsSync(this.repoPath)) {
26
+ return { pushed: false, reason: `Repository not found at ${this.repoPath}` };
27
+ }
28
+
29
+ // 2. Check for local changes
30
+ if (!this.hasLocalChanges()) {
31
+ return { pushed: false, reason: "No changes to push" };
32
+ }
33
+
34
+ // 3. Auto-sync: pull before push (if enabled)
35
+ if (this.config.repository.autoSync) {
36
+ console.log("🔄 Auto-syncing from remote...");
37
+ const pullResult = this.pull();
38
+
39
+ if (!pullResult.pulled) {
40
+ return {
41
+ pushed: false,
42
+ reason: "Pull failed before push",
43
+ conflicts: pullResult.conflicts,
44
+ };
45
+ }
46
+ }
47
+
48
+ // 4. Commit and push
49
+ try {
50
+ const message = options.message || "Update skills and workflows";
51
+ this.gitCommit(message);
52
+ this.gitPush();
53
+
54
+ // Update last sync time
55
+ this.updateLastSync();
56
+
57
+ return { pushed: true };
58
+ } catch (error) {
59
+ return { pushed: false, reason: error.message };
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Pull from GitHub to local
65
+ */
66
+ pull() {
67
+ if (!this.config.repository.url) {
68
+ throw new Error("No repository configured");
69
+ }
70
+
71
+ if (!fs.existsSync(this.repoPath)) {
72
+ throw new Error(`Repository not found at ${this.repoPath}`);
73
+ }
74
+
75
+ try {
76
+ const output = execSync("git pull", {
77
+ cwd: this.repoPath,
78
+ encoding: "utf-8",
79
+ });
80
+
81
+ // Check for conflicts
82
+ if (output.includes("CONFLICT")) {
83
+ const conflicts = this.parseConflicts(output);
84
+ return { pulled: false, conflicts };
85
+ }
86
+
87
+ this.updateLastSync();
88
+ return { pulled: true };
89
+ } catch (error) {
90
+ // Check if error message contains conflict info
91
+ const errorMsg = error.message || error.stdout || error.stderr || "";
92
+ if (errorMsg.includes("CONFLICT")) {
93
+ const conflicts = this.parseConflicts(errorMsg);
94
+ return { pulled: false, conflicts };
95
+ }
96
+ return { pulled: false, reason: error.message };
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Bi-directional sync (pull + push)
102
+ */
103
+ sync(options = {}) {
104
+ // Pull first
105
+ const pullResult = this.pull();
106
+ if (!pullResult.pulled) {
107
+ return {
108
+ synced: false,
109
+ reason: "Pull failed",
110
+ conflicts: pullResult.conflicts,
111
+ };
112
+ }
113
+
114
+ // Then push
115
+ const pushResult = this.push(options);
116
+ if (!pushResult.pushed) {
117
+ return {
118
+ synced: false,
119
+ reason: pushResult.reason,
120
+ };
121
+ }
122
+
123
+ return { synced: true };
124
+ }
125
+
126
+ /**
127
+ * Check if local has uncommitted changes
128
+ */
129
+ hasLocalChanges() {
130
+ try {
131
+ const status = execSync("git status --porcelain", {
132
+ cwd: this.repoPath,
133
+ encoding: "utf-8",
134
+ });
135
+ return status.trim().length > 0;
136
+ } catch (error) {
137
+ return false;
138
+ }
139
+ }
140
+
141
+ /**
142
+ * Check for remote changes (potential conflicts)
143
+ */
144
+ checkRemoteConflicts() {
145
+ try {
146
+ // Fetch remote
147
+ execSync("git fetch", { cwd: this.repoPath, stdio: "pipe" });
148
+
149
+ const branch = this.config.repository.branch || "main";
150
+
151
+ // Compare local vs remote
152
+ const diff = execSync(`git diff HEAD origin/${branch} --name-only`, {
153
+ cwd: this.repoPath,
154
+ encoding: "utf-8",
155
+ });
156
+
157
+ return diff.trim().split("\n").filter(Boolean);
158
+ } catch (error) {
159
+ return [];
160
+ }
161
+ }
162
+
163
+ /**
164
+ * Git commit
165
+ */
166
+ gitCommit(message) {
167
+ try {
168
+ // Add all .agent/ files except bundled package skills
169
+ execSync("git add .agent/workflows/", { cwd: this.repoPath, stdio: "pipe" });
170
+
171
+ // Add skills individually, excluding bundled ones
172
+ const fs = require("fs");
173
+ const path = require("path");
174
+ const skillsDir = path.join(this.repoPath, ".agent/skills");
175
+ const bundledSkills = ["ai-agent-config", "config-manager"];
176
+
177
+ if (fs.existsSync(skillsDir)) {
178
+ const skills = fs.readdirSync(skillsDir);
179
+ skills.forEach(skill => {
180
+ if (!bundledSkills.includes(skill)) {
181
+ execSync(`git add .agent/skills/${skill}`, {
182
+ cwd: this.repoPath,
183
+ stdio: "pipe"
184
+ });
185
+ }
186
+ });
187
+ }
188
+
189
+ execSync(`git commit -m "${message}"`, { cwd: this.repoPath, stdio: "pipe" });
190
+ } catch (error) {
191
+ // Ignore commit errors if nothing to commit
192
+ if (!error.message.includes("nothing to commit")) {
193
+ throw error;
194
+ }
195
+ }
196
+ }
197
+
198
+ /**
199
+ * Git push
200
+ */
201
+ gitPush() {
202
+ const branch = this.config.repository.branch || "main";
203
+ execSync(`git push origin ${branch}`, { cwd: this.repoPath, stdio: "inherit" });
204
+ }
205
+
206
+ /**
207
+ * Update last sync timestamp
208
+ */
209
+ updateLastSync() {
210
+ const configManager = require("./config-manager");
211
+ configManager.setConfigValue("repository.lastSync", new Date().toISOString());
212
+ }
213
+
214
+ /**
215
+ * Parse git conflicts
216
+ */
217
+ parseConflicts(output) {
218
+ const lines = output.split("\n");
219
+ return lines
220
+ .filter((line) => line.includes("CONFLICT"))
221
+ .map((line) => line.replace("CONFLICT (content): Merge conflict in ", "").trim())
222
+ .filter(Boolean);
223
+ }
224
+
225
+ /**
226
+ * Expand ~ to home directory
227
+ */
228
+ expandPath(p) {
229
+ if (!p) return null;
230
+ return p.replace(/^~/, process.env.HOME || process.env.USERPROFILE);
231
+ }
232
+ }
233
+
234
+ module.exports = SyncManager;
@@ -1,167 +0,0 @@
1
- # Skill Updater
2
-
3
- Automatically update skills from all configured sources (official and custom).
4
-
5
- ## When to Use This Skill
6
-
7
- Use this skill when the user wants to:
8
- - Update all skills from configured sources
9
- - Update a specific source
10
- - Update a specific skill
11
- - Sync latest changes from external repositories
12
- - Keep skills up to date with latest best practices
13
-
14
- ## Capabilities
15
-
16
- - **Multi-Source Updates**: Updates from both official and custom sources
17
- - **Selective Updates**: Update specific source or skill
18
- - **Force Updates**: Overwrite local changes
19
- - **Progress Reporting**: Shows what was updated, copied, or skipped
20
-
21
- ## Command Reference
22
-
23
- ```bash
24
- # Update all skills from all sources
25
- ai-agent update
26
-
27
- # Update from specific source
28
- ai-agent update --source vercel-labs
29
-
30
- # Update specific skill
31
- ai-agent update --skill react-best-practices
32
-
33
- # Force overwrite existing skills
34
- ai-agent update --force
35
-
36
- # Combine options
37
- ai-agent update --source company-skills --force
38
- ```
39
-
40
- ## How It Works (v2.0)
41
-
42
- 1. **Reads User Config**: Loads `~/.ai-agent/config.json`
43
- 2. **Gets Enabled Sources**: Filters for enabled sources (official + custom)
44
- 3. **Clones/Updates Repos**: For each source, clones to `~/.ai-agent-external-cache/`
45
- 4. **Copies Skills**: Copies skills to `.agent/skills/` in the package directory
46
- 5. **Reports Results**: Shows what was updated
47
-
48
- ## Examples
49
-
50
- ### Regular Update
51
-
52
- **User**: "Update my skills"
53
-
54
- **Assistant**: I'll update all your skills from configured sources:
55
-
56
- ```bash
57
- ai-agent update
58
- ```
59
-
60
- This will:
61
- - Pull latest from Vercel Labs, Everything Claude Code, etc.
62
- - Update your custom sources too
63
- - Copy new/updated skills to your system
64
- - Show what changed
65
-
66
- ### Update After Adding Custom Source
67
-
68
- **User**: "I just added a custom source, how do I get the skills?"
69
-
70
- **Assistant**: After adding a source, update it:
71
-
72
- ```bash
73
- # Update just your new source
74
- ai-agent update --source your-source-name
75
-
76
- # Then install to platforms
77
- ai-agent install
78
- ```
79
-
80
- ### Force Update
81
-
82
- **User**: "Some skills aren't updating"
83
-
84
- **Assistant**: Use `--force` to overwrite existing skills:
85
-
86
- ```bash
87
- ai-agent update --force
88
- ```
89
-
90
- ⚠️ Warning: This will overwrite any local modifications you made to skills.
91
-
92
- ## What's New in v2.0
93
-
94
- - ✅ **Custom Sources**: Updates from your custom sources, not just official ones
95
- - ✅ **User Config**: Reads from `~/.ai-agent/config.json` instead of hard-coded list
96
- - ✅ **Selective Sync**: Update specific sources or skills
97
- - ✅ **Better Reporting**: Shows which sources succeeded/failed
98
-
99
- ## Update vs Install
100
-
101
- - **`ai-agent update`**: Downloads latest skills from sources to cache
102
- - **`ai-agent install`**: Installs cached skills to AI platforms (Claude, Antigravity, etc.)
103
-
104
- Typical workflow:
105
- ```bash
106
- ai-agent update # Get latest skills
107
- ai-agent install # Install to platforms
108
- ```
109
-
110
- ## Configuration
111
-
112
- Skills are defined in your config file:
113
-
114
- ```json
115
- {
116
- "sources": {
117
- "official": [
118
- {
119
- "name": "vercel-labs",
120
- "enabled": true,
121
- "skills": [
122
- { "path": "skills/react-best-practices", "name": "react-best-practices" }
123
- ]
124
- }
125
- ],
126
- "custom": [
127
- {
128
- "name": "my-skills",
129
- "enabled": true,
130
- "skills": [
131
- { "path": "skills/my-skill", "name": "my-skill" }
132
- ]
133
- }
134
- ]
135
- }
136
- }
137
- ```
138
-
139
- ## Backward Compatibility
140
-
141
- The old command still works:
142
- ```bash
143
- ai-agent sync-external
144
- ```
145
-
146
- This is now an alias for `ai-agent update`.
147
-
148
- ## Tips
149
-
150
- 1. **Regular Updates**: Run `ai-agent update` weekly to get latest skills
151
- 2. **Check Before Install**: After update, review changes before installing
152
- 3. **Test Custom Sources**: When adding custom sources, test with `--source` flag first
153
- 4. **Use Version Control**: If modifying skills, use git to track changes
154
-
155
- ## Troubleshooting
156
-
157
- **Problem**: "Failed to load user config"
158
- **Solution**: Run `ai-agent init` to create config file
159
-
160
- **Problem**: Update fails for a source
161
- **Solution**: Check repo URL is correct: `ai-agent source info <name>`
162
-
163
- **Problem**: Skills not appearing
164
- **Solution**: Make sure source is enabled: `ai-agent source list`
165
-
166
- **Problem**: Git errors
167
- **Solution**: Check internet connection and git is installed