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.
- package/.agent/skills/ai-agent-config/SKILL.md +236 -0
- package/README.md +8 -9
- package/bin/cli.js +196 -51
- package/package.json +3 -3
- package/scripts/config-manager.js +70 -8
- package/scripts/installer.js +10 -25
- package/scripts/sync-manager.js +234 -0
- package/.agent/skills/skill-updater/SKILL.md +0 -167
|
@@ -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 (
|
|
25
|
-
ai-agent init
|
|
24
|
+
# Initialize (optional)
|
|
25
|
+
ai-agent init --repo https://github.com/youruser/my-ai-skills.git
|
|
26
26
|
|
|
27
|
-
#
|
|
28
|
-
ai-agent
|
|
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.
|
|
36
|
-
2.
|
|
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
|
|
84
|
-
ai-agent
|
|
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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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.
|
|
24
|
-
init: "Initialize or migrate
|
|
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: "
|
|
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
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
--
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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
|
|
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
|
-
|
|
229
|
-
|
|
230
|
-
|
|
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] === "--
|
|
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
|
-
|
|
685
|
-
|
|
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}
|
|
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("
|
|
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("
|
|
840
|
+
console.log("\\n Run 'ai-agent install' to install to your platforms.\\n");
|
|
700
841
|
}
|
|
701
842
|
} catch (error) {
|
|
702
|
-
console.error(
|
|
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
|
-
|
|
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.
|
|
4
|
-
"description": "Universal
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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,
|
package/scripts/installer.js
CHANGED
|
@@ -81,12 +81,12 @@ function isRepoCached() {
|
|
|
81
81
|
|
|
82
82
|
/**
|
|
83
83
|
* Get list of available skills
|
|
84
|
-
*
|
|
84
|
+
* Merges package bundled skills + external repo cache
|
|
85
85
|
*/
|
|
86
86
|
function getAvailableSkills() {
|
|
87
87
|
const skills = new Set();
|
|
88
88
|
|
|
89
|
-
//
|
|
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
|
-
|
|
101
|
-
if (skills.size > 0) {
|
|
102
|
-
return Array.from(skills);
|
|
103
|
-
}
|
|
100
|
+
|
|
104
101
|
}
|
|
105
102
|
|
|
106
|
-
//
|
|
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 {
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|