ai-agent-config 1.0.0

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/README.md ADDED
@@ -0,0 +1,115 @@
1
+ # AI Agent Config
2
+
3
+ > Universal Global Skills & Workflows for AI Coding Assistants
4
+
5
+ [![npm version](https://badge.fury.io/js/@dongitran%2Fai-agent-config.svg)](https://www.npmjs.com/package/@dongitran/ai-agent-config)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ Install a curated collection of AI agent skills from [github.com/dongitran/ai-agent-config](https://github.com/dongitran/ai-agent-config) to your global configuration.
9
+
10
+ ## How It Works
11
+
12
+ ```
13
+ ┌─────────────────────────────────────────────────────────────────┐
14
+ │ GitHub Repository │
15
+ │ github.com/dongitran/ai-agent-config │
16
+ │ └── .agent/ │
17
+ │ ├── skills/ ◄── Skills are defined here │
18
+ │ │ ├── code-review/ │
19
+ │ │ └── git-commit/ │
20
+ │ └── workflows/ │
21
+ └─────────────────────────────────────────────────────────────────┘
22
+
23
+ │ ai-agent sync
24
+
25
+ ┌─────────────────────────────────────────────────────────────────┐
26
+ │ Local Cache │
27
+ │ ~/.ai-agent-config-cache/ │
28
+ └─────────────────────────────────────────────────────────────────┘
29
+
30
+ │ ai-agent install
31
+
32
+ ┌─────────────────────────────────────────────────────────────────┐
33
+ │ Platform Global Directories │
34
+ │ ├── ~/.claude/skills/ (Claude Code) │
35
+ │ ├── ~/.gemini/antigravity/skills/ (Antigravity IDE) │
36
+ │ ├── ~/.cursor/skills/ (Cursor) │
37
+ │ └── ~/.windsurf/skills/ (Windsurf) │
38
+ └─────────────────────────────────────────────────────────────────┘
39
+ ```
40
+
41
+ ## Installation
42
+
43
+ ```bash
44
+ # Install the CLI globally
45
+ npm install -g @dongitran/ai-agent-config
46
+
47
+ # Sync skills from repository
48
+ ai-agent sync
49
+
50
+ # Install to your platforms
51
+ ai-agent install
52
+ ```
53
+
54
+ ## CLI Usage
55
+
56
+ ```bash
57
+ ai-agent help # Show all commands
58
+ ai-agent sync # Sync from GitHub repository
59
+ ai-agent install # Install to all detected platforms
60
+ ai-agent list # List available skills
61
+ ai-agent platforms # Show detected platforms
62
+ ai-agent uninstall # Remove installed skills
63
+ ```
64
+
65
+ ### Options
66
+
67
+ ```bash
68
+ ai-agent install --platform claude # Install to specific platform
69
+ ai-agent install --skill code-review # Install specific skill
70
+ ai-agent install --force # Overwrite existing files
71
+ ```
72
+
73
+ ## Supported Platforms
74
+
75
+ | Platform | Global Skills Path |
76
+ |----------|-------------------|
77
+ | Claude Code | `~/.claude/skills/` |
78
+ | Antigravity IDE | `~/.gemini/antigravity/skills/` |
79
+ | Cursor | `~/.cursor/skills/` |
80
+ | Windsurf | `~/.windsurf/skills/` |
81
+ | Codex CLI | `~/.codex/skills/` |
82
+
83
+ ## Available Skills
84
+
85
+ Skills are defined in the repository's `.agent/skills/` directory:
86
+
87
+ - **code-review** - Thorough code review with security, performance checks
88
+ - **git-commit** - Conventional commit message formatting
89
+ - *More coming soon...*
90
+
91
+ ## Configuration
92
+
93
+ Optional config at `~/.ai-agent-config.json`:
94
+
95
+ ```json
96
+ {
97
+ "platforms": ["claude", "antigravity"],
98
+ "skills": {
99
+ "include": ["*"],
100
+ "exclude": []
101
+ }
102
+ }
103
+ ```
104
+
105
+ ## Contributing
106
+
107
+ Add your skills to the repository:
108
+
109
+ 1. Fork [github.com/dongitran/ai-agent-config](https://github.com/dongitran/ai-agent-config)
110
+ 2. Create skill in `.agent/skills/your-skill/SKILL.md`
111
+ 3. Submit a pull request
112
+
113
+ ## License
114
+
115
+ MIT
package/bin/cli.js ADDED
@@ -0,0 +1,297 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * AI Agent Config CLI
5
+ * Install global skills from https://github.com/dongitran/ai-agent-config
6
+ */
7
+
8
+ const fs = require("fs");
9
+ const path = require("path");
10
+
11
+ const platforms = require("../scripts/platforms");
12
+ const installer = require("../scripts/installer");
13
+
14
+ const COMMANDS = {
15
+ init: "Initialize config file in home directory",
16
+ install: "Install skills to detected platforms",
17
+ sync: "Sync skills from GitHub repository",
18
+ list: "List available skills and workflows",
19
+ platforms: "Show detected platforms",
20
+ uninstall: "Remove installed skills",
21
+ help: "Show this help message",
22
+ };
23
+
24
+ function showHelp() {
25
+ console.log(`
26
+ ╔═══════════════════════════════════════════════════════════════╗
27
+ ║ AI Agent Config CLI ║
28
+ ║ Universal Global Skills for AI Coding Assistants ║
29
+ ╚═══════════════════════════════════════════════════════════════╝
30
+
31
+ Usage: ai-agent <command> [options]
32
+
33
+ Commands:`);
34
+
35
+ Object.entries(COMMANDS).forEach(([cmd, desc]) => {
36
+ console.log(` ${cmd.padEnd(12)} ${desc}`);
37
+ });
38
+
39
+ console.log(`
40
+ Options:
41
+ --platform <name> Target specific platform (claude, antigravity, cursor)
42
+ --skill <name> Install specific skill only
43
+ --force Overwrite existing files
44
+
45
+ Examples:
46
+ ai-agent sync # Sync from GitHub repository
47
+ ai-agent install # Install all skills to detected platforms
48
+ ai-agent install --platform claude
49
+ ai-agent install --skill code-review
50
+ ai-agent list # List available skills
51
+ ai-agent platforms # Show detected platforms
52
+ ai-agent uninstall # Remove all installed skills
53
+
54
+ Repository: https://github.com/dongitran/ai-agent-config
55
+ Skills are stored in: ~/.ai-agent-config-cache/.agent/skills/
56
+ `);
57
+ }
58
+
59
+ function showPlatforms() {
60
+ console.log("\n🔍 Detecting platforms...\n");
61
+
62
+ const detected = platforms.detectAll();
63
+
64
+ if (detected.length === 0) {
65
+ console.log("No AI coding platforms detected in home directory.\n");
66
+ console.log("Supported platforms:");
67
+ platforms.SUPPORTED.forEach((p) => {
68
+ console.log(` - ${p.displayName} (~/${p.configDir})`);
69
+ });
70
+ return;
71
+ }
72
+
73
+ console.log("Detected platforms:\n");
74
+ detected.forEach((p) => {
75
+ console.log(` ✓ ${p.displayName}`);
76
+ console.log(` Skills: ${p.skillsPath}`);
77
+ console.log("");
78
+ });
79
+ }
80
+
81
+ function listSkills() {
82
+ console.log("\n📦 Available Skills & Workflows\n");
83
+
84
+ if (!installer.isRepoCached()) {
85
+ console.log("⚠️ Repository not synced yet.");
86
+ console.log(" Run: ai-agent sync\n");
87
+ return;
88
+ }
89
+
90
+ const skills = installer.getAvailableSkills();
91
+ const workflows = installer.getAvailableWorkflows();
92
+
93
+ console.log("Skills:");
94
+ if (skills.length === 0) {
95
+ console.log(" (no skills found)");
96
+ } else {
97
+ skills.forEach((skill) => {
98
+ const skillFile = path.join(installer.REPO_SKILLS_DIR, skill, "SKILL.md");
99
+ let desc = "";
100
+ if (fs.existsSync(skillFile)) {
101
+ const content = fs.readFileSync(skillFile, "utf-8");
102
+ const match = content.match(/description:\s*(.+)/i);
103
+ if (match) desc = `- ${match[1]}`;
104
+ }
105
+ console.log(` • ${skill} ${desc}`);
106
+ });
107
+ }
108
+
109
+ console.log("\nWorkflows:");
110
+ if (workflows.length === 0) {
111
+ console.log(" (no workflows found)");
112
+ } else {
113
+ workflows.forEach((wf) => {
114
+ console.log(` • ${wf}`);
115
+ });
116
+ }
117
+
118
+ console.log(`\nSource: ${installer.CACHE_DIR}`);
119
+ console.log("");
120
+ }
121
+
122
+ function init(args) {
123
+ console.log("\n🚀 Initializing AI Agent Config...\n");
124
+
125
+ const configFile = path.join(platforms.HOME, ".ai-agent-config.json");
126
+
127
+ if (fs.existsSync(configFile) && !args.includes("--force")) {
128
+ console.log("⚠️ Config file already exists. Use --force to overwrite.");
129
+ return;
130
+ }
131
+
132
+ const defaultConfig = {
133
+ platforms: ["auto"],
134
+ skills: {
135
+ include: ["*"],
136
+ exclude: [],
137
+ },
138
+ sync: {
139
+ auto: false,
140
+ remote: "https://github.com/dongitran/ai-agent-config",
141
+ },
142
+ };
143
+
144
+ fs.writeFileSync(configFile, JSON.stringify(defaultConfig, null, 2));
145
+ console.log(`✓ Created ${configFile}`);
146
+
147
+ const detected = platforms.detectAll();
148
+ if (detected.length > 0) {
149
+ console.log("\nDetected platforms:");
150
+ detected.forEach((p) => console.log(` ✓ ${p.displayName}`));
151
+ }
152
+
153
+ console.log("\nNext steps:");
154
+ console.log(" 1. Run: ai-agent sync");
155
+ console.log(" 2. Run: ai-agent install");
156
+ console.log("");
157
+ }
158
+
159
+ function install(args) {
160
+ console.log("\n📥 Installing skills...\n");
161
+
162
+ const options = {
163
+ platform: null,
164
+ force: false,
165
+ skill: null,
166
+ sync: true,
167
+ };
168
+
169
+ for (let i = 0; i < args.length; i++) {
170
+ if (args[i] === "--platform" && args[i + 1]) {
171
+ options.platform = args[++i];
172
+ } else if (args[i] === "--force") {
173
+ options.force = true;
174
+ } else if (args[i] === "--skill" && args[i + 1]) {
175
+ options.skill = args[++i];
176
+ } else if (args[i] === "--no-sync") {
177
+ options.sync = false;
178
+ }
179
+ }
180
+
181
+ try {
182
+ const result = installer.install(options);
183
+
184
+ if (result.skillsCount > 0) {
185
+ console.log(`\n✓ Installed ${result.skillsCount} skill(s) to ${result.platformsCount} platform(s)\n`);
186
+ result.details.forEach((d) => {
187
+ console.log(` ${d.platform}: ${d.path}`);
188
+ d.skills.forEach((s) => {
189
+ const status = s.skipped > 0 ? `(${s.copied} new, ${s.skipped} skipped)` : "";
190
+ console.log(` • ${s.name} ${status}`);
191
+ });
192
+ });
193
+ } else {
194
+ console.log("\n⚠️ No skills installed.");
195
+ }
196
+ } catch (error) {
197
+ console.error(`\n❌ Installation failed: ${error.message}`);
198
+ process.exit(1);
199
+ }
200
+
201
+ console.log("");
202
+ }
203
+
204
+ function sync(args) {
205
+ console.log("\n🔄 Syncing from GitHub repository...\n");
206
+ console.log(` Repository: ${installer.REPO_URL}`);
207
+ console.log(` Cache: ${installer.CACHE_DIR}\n`);
208
+
209
+ try {
210
+ const success = installer.syncRepo();
211
+
212
+ if (success) {
213
+ console.log("\n✓ Sync complete!\n");
214
+
215
+ const skills = installer.getAvailableSkills();
216
+ const workflows = installer.getAvailableWorkflows();
217
+
218
+ console.log(` Found ${skills.length} skill(s), ${workflows.length} workflow(s)`);
219
+ console.log("\n Run 'ai-agent install' to install to your platforms.\n");
220
+ }
221
+ } catch (error) {
222
+ console.error(`\n❌ Sync failed: ${error.message}`);
223
+ process.exit(1);
224
+ }
225
+ }
226
+
227
+ function uninstall(args) {
228
+ console.log("\n🗑️ Uninstalling skills...\n");
229
+
230
+ const options = {
231
+ platform: null,
232
+ skill: null,
233
+ };
234
+
235
+ for (let i = 0; i < args.length; i++) {
236
+ if (args[i] === "--platform" && args[i + 1]) {
237
+ options.platform = args[++i];
238
+ } else if (args[i] === "--skill" && args[i + 1]) {
239
+ options.skill = args[++i];
240
+ }
241
+ }
242
+
243
+ try {
244
+ const result = installer.uninstall(options);
245
+
246
+ if (result.totalRemoved > 0) {
247
+ console.log(`✓ Removed ${result.totalRemoved} skill(s) from ${result.platformsCount} platform(s)\n`);
248
+ result.details.forEach((d) => {
249
+ if (d.removed > 0) {
250
+ console.log(` ${d.platform}: ${d.removed} removed`);
251
+ }
252
+ });
253
+ } else {
254
+ console.log("ℹ️ No skills to remove.");
255
+ }
256
+ } catch (error) {
257
+ console.error(`\n❌ Uninstall failed: ${error.message}`);
258
+ process.exit(1);
259
+ }
260
+
261
+ console.log("");
262
+ }
263
+
264
+ // Main
265
+ const args = process.argv.slice(2);
266
+ const command = args[0];
267
+
268
+ switch (command) {
269
+ case "init":
270
+ init(args.slice(1));
271
+ break;
272
+ case "install":
273
+ install(args.slice(1));
274
+ break;
275
+ case "sync":
276
+ sync(args.slice(1));
277
+ break;
278
+ case "list":
279
+ listSkills();
280
+ break;
281
+ case "platforms":
282
+ showPlatforms();
283
+ break;
284
+ case "uninstall":
285
+ uninstall(args.slice(1));
286
+ break;
287
+ case "help":
288
+ case "--help":
289
+ case "-h":
290
+ case undefined:
291
+ showHelp();
292
+ break;
293
+ default:
294
+ console.error(`Unknown command: ${command}`);
295
+ console.log('Run "ai-agent help" for usage information.');
296
+ process.exit(1);
297
+ }
package/index.js ADDED
@@ -0,0 +1,36 @@
1
+ /**
2
+ * AI Agent Config
3
+ * Universal Global Skills & Workflows for AI Coding Assistants
4
+ *
5
+ * @module @dongitran/ai-agent-config
6
+ */
7
+
8
+ const platforms = require("./scripts/platforms");
9
+ const installer = require("./scripts/installer");
10
+
11
+ module.exports = {
12
+ // Platform detection
13
+ platforms: {
14
+ detectAll: platforms.detectAll,
15
+ getByName: platforms.getByName,
16
+ getAllNames: platforms.getAllNames,
17
+ SUPPORTED: platforms.SUPPORTED,
18
+ },
19
+
20
+ // Installation
21
+ installer: {
22
+ install: installer.install,
23
+ uninstall: installer.uninstall,
24
+ syncRepo: installer.syncRepo,
25
+ isRepoCached: installer.isRepoCached,
26
+ getAvailableSkills: installer.getAvailableSkills,
27
+ getAvailableWorkflows: installer.getAvailableWorkflows,
28
+ },
29
+
30
+ // Constants
31
+ REPO_URL: installer.REPO_URL,
32
+ CACHE_DIR: installer.CACHE_DIR,
33
+
34
+ // Version
35
+ version: require("./package.json").version,
36
+ };
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "ai-agent-config",
3
+ "version": "1.0.0",
4
+ "description": "Universal Global Skills & Workflows for AI Coding Assistants (Claude Code, Antigravity, Cursor)",
5
+ "main": "index.js",
6
+ "bin": {
7
+ "ai-agent": "./bin/cli.js"
8
+ },
9
+ "scripts": {
10
+ "postinstall": "node scripts/postinstall.js",
11
+ "test": "node --test"
12
+ },
13
+ "keywords": [
14
+ "ai",
15
+ "agent",
16
+ "skills",
17
+ "claude-code",
18
+ "antigravity",
19
+ "cursor",
20
+ "windsurf",
21
+ "copilot",
22
+ "workflows",
23
+ "coding-assistant",
24
+ "global-skills"
25
+ ],
26
+ "author": "Dong Tran",
27
+ "license": "MIT",
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "git+https://github.com/dongitran/ai-agent-config.git"
31
+ },
32
+ "bugs": {
33
+ "url": "https://github.com/dongitran/ai-agent-config/issues"
34
+ },
35
+ "homepage": "https://github.com/dongitran/ai-agent-config#readme",
36
+ "engines": {
37
+ "node": ">=18.0.0"
38
+ },
39
+ "files": [
40
+ "bin/",
41
+ "scripts/",
42
+ "index.js"
43
+ ]
44
+ }
@@ -0,0 +1,280 @@
1
+ /**
2
+ * Installer module for AI Agent Config
3
+ * Handles syncing from GitHub repo and copying skills to platform directories
4
+ */
5
+
6
+ const fs = require("fs");
7
+ const path = require("path");
8
+ const { execSync } = require("child_process");
9
+ const platforms = require("./platforms");
10
+
11
+ const REPO_URL = "https://github.com/dongitran/ai-agent-config.git";
12
+ const CACHE_DIR = path.join(platforms.HOME, ".ai-agent-config-cache");
13
+ const REPO_SKILLS_DIR = path.join(CACHE_DIR, ".agent", "skills");
14
+ const REPO_WORKFLOWS_DIR = path.join(CACHE_DIR, ".agent", "workflows");
15
+
16
+ /**
17
+ * Copy directory recursively
18
+ */
19
+ function copyDir(src, dest, force = false) {
20
+ if (!fs.existsSync(src)) {
21
+ return { copied: 0, skipped: 0 };
22
+ }
23
+
24
+ if (!fs.existsSync(dest)) {
25
+ fs.mkdirSync(dest, { recursive: true });
26
+ }
27
+
28
+ let copied = 0;
29
+ let skipped = 0;
30
+
31
+ const entries = fs.readdirSync(src, { withFileTypes: true });
32
+
33
+ for (const entry of entries) {
34
+ const srcPath = path.join(src, entry.name);
35
+ const destPath = path.join(dest, entry.name);
36
+
37
+ if (entry.isDirectory()) {
38
+ const result = copyDir(srcPath, destPath, force);
39
+ copied += result.copied;
40
+ skipped += result.skipped;
41
+ } else {
42
+ if (fs.existsSync(destPath) && !force) {
43
+ skipped++;
44
+ } else {
45
+ fs.copyFileSync(srcPath, destPath);
46
+ copied++;
47
+ }
48
+ }
49
+ }
50
+
51
+ return { copied, skipped };
52
+ }
53
+
54
+ /**
55
+ * Sync repository from GitHub
56
+ * @returns {boolean} Success status
57
+ */
58
+ function syncRepo() {
59
+ try {
60
+ if (fs.existsSync(CACHE_DIR)) {
61
+ console.log(" Updating cached repository...");
62
+ execSync("git pull --quiet", { cwd: CACHE_DIR, stdio: "pipe" });
63
+ } else {
64
+ console.log(" Cloning repository...");
65
+ execSync(`git clone --quiet "${REPO_URL}" "${CACHE_DIR}"`, { stdio: "pipe" });
66
+ }
67
+ return true;
68
+ } catch (error) {
69
+ console.error(` Failed to sync: ${error.message}`);
70
+ return false;
71
+ }
72
+ }
73
+
74
+ /**
75
+ * Check if repo is cached
76
+ */
77
+ function isRepoCached() {
78
+ return fs.existsSync(CACHE_DIR) && fs.existsSync(REPO_SKILLS_DIR);
79
+ }
80
+
81
+ /**
82
+ * Get list of available skills from cached repo
83
+ */
84
+ function getAvailableSkills() {
85
+ if (!fs.existsSync(REPO_SKILLS_DIR)) {
86
+ return [];
87
+ }
88
+
89
+ return fs.readdirSync(REPO_SKILLS_DIR).filter((name) => {
90
+ const skillPath = path.join(REPO_SKILLS_DIR, name);
91
+ const skillFile = path.join(skillPath, "SKILL.md");
92
+ return fs.statSync(skillPath).isDirectory() && fs.existsSync(skillFile);
93
+ });
94
+ }
95
+
96
+ /**
97
+ * Get list of available workflows from cached repo
98
+ */
99
+ function getAvailableWorkflows() {
100
+ if (!fs.existsSync(REPO_WORKFLOWS_DIR)) {
101
+ return [];
102
+ }
103
+
104
+ return fs
105
+ .readdirSync(REPO_WORKFLOWS_DIR)
106
+ .filter((name) => name.endsWith(".md"))
107
+ .map((name) => name.replace(".md", ""));
108
+ }
109
+
110
+ /**
111
+ * Install skills to a specific platform
112
+ */
113
+ function installToPlatform(platform, options = {}) {
114
+ const { force = false, skill = null } = options;
115
+
116
+ const skillsPath = platforms.ensureSkillsDir(platform);
117
+ const results = { platform: platform.name, path: skillsPath, skills: [] };
118
+
119
+ let skillsToInstall = getAvailableSkills();
120
+
121
+ if (skill) {
122
+ skillsToInstall = skillsToInstall.filter((s) => s === skill);
123
+ if (skillsToInstall.length === 0) {
124
+ throw new Error(`Skill "${skill}" not found in repository`);
125
+ }
126
+ }
127
+
128
+ for (const skillName of skillsToInstall) {
129
+ const srcPath = path.join(REPO_SKILLS_DIR, skillName);
130
+ const destPath = path.join(skillsPath, skillName);
131
+
132
+ const copyResult = copyDir(srcPath, destPath, force);
133
+ results.skills.push({
134
+ name: skillName,
135
+ ...copyResult,
136
+ });
137
+ }
138
+
139
+ return results;
140
+ }
141
+
142
+ /**
143
+ * Install skills to all detected platforms
144
+ */
145
+ function install(options = {}) {
146
+ const { platform = null, force = false, skill = null, sync = true } = options;
147
+
148
+ // Sync repo first if needed
149
+ if (sync && !isRepoCached()) {
150
+ console.log("\n📦 Syncing skills from repository...");
151
+ if (!syncRepo()) {
152
+ throw new Error("Failed to sync repository. Check your internet connection.");
153
+ }
154
+ }
155
+
156
+ if (!isRepoCached()) {
157
+ console.log("\n⚠️ Skills repository not cached. Run 'ai-agent sync' first.");
158
+ return { skillsCount: 0, platformsCount: 0, details: [] };
159
+ }
160
+
161
+ let targetPlatforms;
162
+
163
+ if (platform) {
164
+ const platformObj = platforms.getByName(platform);
165
+ if (!platformObj) {
166
+ throw new Error(
167
+ `Unknown platform: ${platform}. Available: ${platforms.getAllNames().join(", ")}`
168
+ );
169
+ }
170
+ targetPlatforms = [platformObj];
171
+ } else {
172
+ targetPlatforms = platforms.detectAll().map((p) => platforms.getByName(p.name));
173
+ }
174
+
175
+ if (targetPlatforms.length === 0) {
176
+ console.log("\n⚠️ No AI coding platforms detected.");
177
+ console.log(" Supported platforms:", platforms.getAllNames().join(", "));
178
+ console.log("\n Force install with: ai-agent install --platform <name>");
179
+ return { skillsCount: 0, platformsCount: 0, details: [] };
180
+ }
181
+
182
+ const details = [];
183
+ let totalSkills = 0;
184
+
185
+ for (const platformObj of targetPlatforms) {
186
+ try {
187
+ const result = installToPlatform(platformObj, { force, skill });
188
+ details.push(result);
189
+ totalSkills += result.skills.length;
190
+ } catch (error) {
191
+ console.error(` Failed to install to ${platformObj.name}: ${error.message}`);
192
+ }
193
+ }
194
+
195
+ return {
196
+ skillsCount: totalSkills,
197
+ platformsCount: details.length,
198
+ details,
199
+ };
200
+ }
201
+
202
+ /**
203
+ * Uninstall skills from a platform
204
+ */
205
+ function uninstallFromPlatform(platform, skill = null) {
206
+ const skillsPath = platform.skillsPath;
207
+
208
+ if (!fs.existsSync(skillsPath)) {
209
+ return { platform: platform.name, removed: 0 };
210
+ }
211
+
212
+ let removed = 0;
213
+ const ourSkills = getAvailableSkills();
214
+
215
+ if (skill) {
216
+ const skillPath = path.join(skillsPath, skill);
217
+ if (fs.existsSync(skillPath) && ourSkills.includes(skill)) {
218
+ fs.rmSync(skillPath, { recursive: true });
219
+ removed++;
220
+ }
221
+ } else {
222
+ for (const skillName of ourSkills) {
223
+ const skillPath = path.join(skillsPath, skillName);
224
+ if (fs.existsSync(skillPath)) {
225
+ fs.rmSync(skillPath, { recursive: true });
226
+ removed++;
227
+ }
228
+ }
229
+ }
230
+
231
+ return { platform: platform.name, removed };
232
+ }
233
+
234
+ /**
235
+ * Uninstall skills from all platforms
236
+ */
237
+ function uninstall(options = {}) {
238
+ const { platform = null, skill = null } = options;
239
+
240
+ let targetPlatforms;
241
+
242
+ if (platform) {
243
+ const platformObj = platforms.getByName(platform);
244
+ if (!platformObj) {
245
+ throw new Error(`Unknown platform: ${platform}`);
246
+ }
247
+ targetPlatforms = [platformObj];
248
+ } else {
249
+ targetPlatforms = platforms.detectAll().map((p) => platforms.getByName(p.name));
250
+ }
251
+
252
+ const results = [];
253
+ let totalRemoved = 0;
254
+
255
+ for (const platformObj of targetPlatforms) {
256
+ const result = uninstallFromPlatform(platformObj, skill);
257
+ results.push(result);
258
+ totalRemoved += result.removed;
259
+ }
260
+
261
+ return {
262
+ totalRemoved,
263
+ platformsCount: results.length,
264
+ details: results,
265
+ };
266
+ }
267
+
268
+ module.exports = {
269
+ install,
270
+ uninstall,
271
+ syncRepo,
272
+ isRepoCached,
273
+ getAvailableSkills,
274
+ getAvailableWorkflows,
275
+ copyDir,
276
+ CACHE_DIR,
277
+ REPO_URL,
278
+ REPO_SKILLS_DIR,
279
+ REPO_WORKFLOWS_DIR,
280
+ };
@@ -0,0 +1,182 @@
1
+ /**
2
+ * Platform detection for AI coding assistants
3
+ * Detects which platforms are installed and returns their global skills paths
4
+ */
5
+
6
+ const fs = require("fs");
7
+ const path = require("path");
8
+ const os = require("os");
9
+
10
+ const HOME = os.homedir();
11
+
12
+ /**
13
+ * Supported platforms configuration
14
+ */
15
+ const SUPPORTED = [
16
+ {
17
+ name: "claude",
18
+ displayName: "Claude Code",
19
+ configDir: ".claude",
20
+ skillsDir: "skills",
21
+ commandsDir: "commands",
22
+ get configPath() {
23
+ return path.join(HOME, this.configDir);
24
+ },
25
+ get skillsPath() {
26
+ return path.join(HOME, this.configDir, this.skillsDir);
27
+ },
28
+ get commandsPath() {
29
+ return path.join(HOME, this.configDir, this.commandsDir);
30
+ },
31
+ detect() {
32
+ return fs.existsSync(this.configPath);
33
+ },
34
+ },
35
+ {
36
+ name: "antigravity",
37
+ displayName: "Antigravity IDE",
38
+ configDir: ".gemini/antigravity",
39
+ skillsDir: "skills",
40
+ workflowsDir: "workflows",
41
+ get configPath() {
42
+ return path.join(HOME, this.configDir);
43
+ },
44
+ get skillsPath() {
45
+ return path.join(HOME, this.configDir, this.skillsDir);
46
+ },
47
+ get workflowsPath() {
48
+ return path.join(HOME, this.configDir, this.workflowsDir);
49
+ },
50
+ detect() {
51
+ // Check for .gemini directory or Antigravity app
52
+ return (
53
+ fs.existsSync(path.join(HOME, ".gemini")) ||
54
+ fs.existsSync("/Applications/Antigravity.app") ||
55
+ fs.existsSync(path.join(HOME, "Applications", "Antigravity.app"))
56
+ );
57
+ },
58
+ },
59
+ {
60
+ name: "cursor",
61
+ displayName: "Cursor",
62
+ configDir: ".cursor",
63
+ skillsDir: "skills",
64
+ rulesDir: "rules",
65
+ get configPath() {
66
+ return path.join(HOME, this.configDir);
67
+ },
68
+ get skillsPath() {
69
+ return path.join(HOME, this.configDir, this.skillsDir);
70
+ },
71
+ get rulesPath() {
72
+ return path.join(HOME, this.configDir, this.rulesDir);
73
+ },
74
+ detect() {
75
+ return (
76
+ fs.existsSync(this.configPath) ||
77
+ fs.existsSync("/Applications/Cursor.app") ||
78
+ fs.existsSync(path.join(HOME, "Applications", "Cursor.app"))
79
+ );
80
+ },
81
+ },
82
+ {
83
+ name: "windsurf",
84
+ displayName: "Windsurf",
85
+ configDir: ".windsurf",
86
+ skillsDir: "skills",
87
+ get configPath() {
88
+ return path.join(HOME, this.configDir);
89
+ },
90
+ get skillsPath() {
91
+ return path.join(HOME, this.configDir, this.skillsDir);
92
+ },
93
+ detect() {
94
+ return (
95
+ fs.existsSync(this.configPath) ||
96
+ fs.existsSync("/Applications/Windsurf.app")
97
+ );
98
+ },
99
+ },
100
+ {
101
+ name: "codex",
102
+ displayName: "Codex CLI",
103
+ configDir: ".codex",
104
+ skillsDir: "skills",
105
+ get configPath() {
106
+ return path.join(HOME, this.configDir);
107
+ },
108
+ get skillsPath() {
109
+ return path.join(HOME, this.configDir, this.skillsDir);
110
+ },
111
+ detect() {
112
+ return fs.existsSync(this.configPath);
113
+ },
114
+ },
115
+ {
116
+ name: "copilot",
117
+ displayName: "GitHub Copilot",
118
+ configDir: ".github",
119
+ instructionsFile: "copilot-instructions.md",
120
+ get configPath() {
121
+ return path.join(HOME, this.configDir);
122
+ },
123
+ get instructionsPath() {
124
+ return path.join(HOME, this.configDir, this.instructionsFile);
125
+ },
126
+ detect() {
127
+ // Copilot is usually detected via VS Code extensions
128
+ return fs.existsSync(this.configPath);
129
+ },
130
+ },
131
+ ];
132
+
133
+ /**
134
+ * Detect all installed platforms
135
+ * @returns {Array} Array of detected platform objects
136
+ */
137
+ function detectAll() {
138
+ return SUPPORTED.filter((platform) => platform.detect()).map((platform) => ({
139
+ name: platform.name,
140
+ displayName: platform.displayName,
141
+ configPath: platform.configPath,
142
+ skillsPath: platform.skillsPath,
143
+ }));
144
+ }
145
+
146
+ /**
147
+ * Get platform by name
148
+ * @param {string} name - Platform name
149
+ * @returns {Object|null} Platform object or null
150
+ */
151
+ function getByName(name) {
152
+ return SUPPORTED.find((p) => p.name === name.toLowerCase()) || null;
153
+ }
154
+
155
+ /**
156
+ * Ensure skills directory exists for a platform
157
+ * @param {Object} platform - Platform object
158
+ */
159
+ function ensureSkillsDir(platform) {
160
+ const skillsPath = platform.skillsPath;
161
+ if (!fs.existsSync(skillsPath)) {
162
+ fs.mkdirSync(skillsPath, { recursive: true });
163
+ }
164
+ return skillsPath;
165
+ }
166
+
167
+ /**
168
+ * Get all supported platform names
169
+ * @returns {Array} Array of platform names
170
+ */
171
+ function getAllNames() {
172
+ return SUPPORTED.map((p) => p.name);
173
+ }
174
+
175
+ module.exports = {
176
+ SUPPORTED,
177
+ detectAll,
178
+ getByName,
179
+ ensureSkillsDir,
180
+ getAllNames,
181
+ HOME,
182
+ };
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Post-install script for AI Agent Config
5
+ * Shows usage instructions after npm install
6
+ */
7
+
8
+ const platforms = require("./platforms");
9
+
10
+ function main() {
11
+ console.log("\n╔═══════════════════════════════════════════════════════════════╗");
12
+ console.log("║ AI Agent Config Installed! ║");
13
+ console.log("╚═══════════════════════════════════════════════════════════════╝\n");
14
+
15
+ // Detect platforms
16
+ const detected = platforms.detectAll();
17
+
18
+ if (detected.length > 0) {
19
+ console.log("🔍 Detected platforms:\n");
20
+ detected.forEach((p) => {
21
+ console.log(` ✓ ${p.displayName}`);
22
+ });
23
+ console.log("");
24
+ }
25
+
26
+ console.log("📖 Quick Start:\n");
27
+ console.log(" 1. Sync skills from repository:");
28
+ console.log(" $ ai-agent sync\n");
29
+ console.log(" 2. Install to your platforms:");
30
+ console.log(" $ ai-agent install\n");
31
+ console.log(" 3. View available skills:");
32
+ console.log(" $ ai-agent list\n");
33
+ console.log("📦 Repository: https://github.com/dongitran/ai-agent-config\n");
34
+ }
35
+
36
+ main();