@bitkyc08/agent-sync 0.1.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 +61 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +290 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/agents-md.d.ts +11 -0
- package/dist/core/agents-md.js +49 -0
- package/dist/core/agents-md.js.map +1 -0
- package/dist/core/config.d.ts +6 -0
- package/dist/core/config.js +18 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/mcp-sync.d.ts +18 -0
- package/dist/core/mcp-sync.js +240 -0
- package/dist/core/mcp-sync.js.map +1 -0
- package/dist/core/skill-sync.d.ts +13 -0
- package/dist/core/skill-sync.js +105 -0
- package/dist/core/skill-sync.js.map +1 -0
- package/dist/core/symlink.d.ts +24 -0
- package/dist/core/symlink.js +81 -0
- package/dist/core/symlink.js.map +1 -0
- package/dist/utils/log.d.ts +13 -0
- package/dist/utils/log.js +23 -0
- package/dist/utils/log.js.map +1 -0
- package/dist/utils/prompt.d.ts +2 -0
- package/dist/utils/prompt.js +23 -0
- package/dist/utils/prompt.js.map +1 -0
- package/package.json +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# agent-sync
|
|
2
|
+
|
|
3
|
+
> Sync MCP, skills, and AGENTS.md across **all** AI coding agents — one command.
|
|
4
|
+
|
|
5
|
+
Supports: **Claude Code** · **Codex** · **Copilot** · **Gemini CLI** · **Antigravity** · **OpenCode**
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install -g agent-sync
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Interactive wizard — guides you through prompt, skills, and MCP setup
|
|
17
|
+
agent-sync
|
|
18
|
+
|
|
19
|
+
# Individual commands
|
|
20
|
+
agent-sync mcp # Sync MCP config globally (→ 6 CLIs)
|
|
21
|
+
agent-sync skills # Sync skill symlinks in project
|
|
22
|
+
agent-sync agents # Generate AGENTS.md in project
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## What It Does
|
|
26
|
+
|
|
27
|
+
### 1. AGENTS.md (Project-level)
|
|
28
|
+
Auto-detects prompt files (`AGENTS.md`, `CLAUDE.md`, `COPILOT.md`, etc.) in your project.
|
|
29
|
+
Writes a unified `AGENTS.md` that Codex, Copilot, and OpenCode discover automatically.
|
|
30
|
+
|
|
31
|
+
### 2. Skills Sync (Project-level)
|
|
32
|
+
Creates symlinks so all agents find the same skills:
|
|
33
|
+
```
|
|
34
|
+
.agent/skills/ ← source (real files)
|
|
35
|
+
.agents/skills/ → .agent/skills (symlink)
|
|
36
|
+
.claude/skills/ → .agent/skills (symlink)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### 3. MCP Config (Global)
|
|
40
|
+
One `~/.agent-sync/mcp.json` → synced to all CLI configs:
|
|
41
|
+
|
|
42
|
+
| Target | Path | Format |
|
|
43
|
+
|--------|------|--------|
|
|
44
|
+
| Claude Code | `~/.mcp.json` | JSON `mcpServers` |
|
|
45
|
+
| Codex | `~/.codex/config.toml` | TOML `[mcp_servers.*]` |
|
|
46
|
+
| Gemini CLI | `~/.gemini/settings.json` | JSON `mcpServers` |
|
|
47
|
+
| OpenCode | `~/.config/opencode/opencode.json` | JSON `mcp` |
|
|
48
|
+
| Copilot | `~/.copilot/mcp-config.json` | JSON `mcpServers` |
|
|
49
|
+
| Antigravity | `~/.gemini/antigravity/mcp_config.json` | JSON `mcpServers` |
|
|
50
|
+
|
|
51
|
+
## Config Location
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
~/.agent-sync/
|
|
55
|
+
├── mcp.json # Unified MCP source of truth
|
|
56
|
+
└── backups/ # Auto-backups on conflict
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## License
|
|
60
|
+
|
|
61
|
+
MIT
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* agent-sync CLI — Interactive wizard for syncing AI agent configs
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* agent-sync Run interactive wizard (prompt → skills → MCP → sync)
|
|
7
|
+
* agent-sync mcp MCP sync only (global)
|
|
8
|
+
* agent-sync skills Skills sync only (project)
|
|
9
|
+
* agent-sync agents AGENTS.md sync only (project)
|
|
10
|
+
* agent-sync all Run all without prompts (uses detected defaults)
|
|
11
|
+
*/
|
|
12
|
+
import fs from 'node:fs';
|
|
13
|
+
import { join } from 'node:path';
|
|
14
|
+
import { log } from './utils/log.js';
|
|
15
|
+
import { ask, choose } from './utils/prompt.js';
|
|
16
|
+
import { ensureHome, MCP_PATH, AGENT_SYNC_HOME } from './core/config.js';
|
|
17
|
+
import { detectPromptFiles, generateAgentsMd } from './core/agents-md.js';
|
|
18
|
+
import { detectSkillSources, syncSkills, listSkills } from './core/skill-sync.js';
|
|
19
|
+
import { detectMcpConfigs, loadMcpConfig, saveMcpConfig, syncToAll, importFromClaude } from './core/mcp-sync.js';
|
|
20
|
+
const VERSION = '0.1.0';
|
|
21
|
+
const cwd = process.cwd();
|
|
22
|
+
// ─── Subcommand routing ───────────────────────────
|
|
23
|
+
async function main() {
|
|
24
|
+
const args = process.argv.slice(2);
|
|
25
|
+
const cmd = args[0];
|
|
26
|
+
if (cmd === '--version' || cmd === '-v') {
|
|
27
|
+
console.log(`agent-sync v${VERSION}`);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if (cmd === '--help' || cmd === '-h') {
|
|
31
|
+
printHelp();
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
ensureHome();
|
|
35
|
+
if (!cmd || cmd === 'all') {
|
|
36
|
+
await wizardFull();
|
|
37
|
+
}
|
|
38
|
+
else if (cmd === 'mcp') {
|
|
39
|
+
await wizardMcp();
|
|
40
|
+
}
|
|
41
|
+
else if (cmd === 'skills') {
|
|
42
|
+
await wizardSkills();
|
|
43
|
+
}
|
|
44
|
+
else if (cmd === 'agents') {
|
|
45
|
+
await wizardAgents();
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
log.err(`Unknown command: ${cmd}`);
|
|
49
|
+
printHelp();
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function printHelp() {
|
|
54
|
+
console.log(`
|
|
55
|
+
agent-sync v${VERSION}
|
|
56
|
+
Sync MCP, skills, and AGENTS.md across all AI coding agents.
|
|
57
|
+
|
|
58
|
+
Usage:
|
|
59
|
+
agent-sync Interactive wizard (all steps)
|
|
60
|
+
agent-sync mcp MCP config sync (global → 6 CLIs)
|
|
61
|
+
agent-sync skills Skills symlink sync (project-level)
|
|
62
|
+
agent-sync agents AGENTS.md generation (project-level)
|
|
63
|
+
agent-sync all Run all with detected defaults
|
|
64
|
+
|
|
65
|
+
Options:
|
|
66
|
+
-h, --help Show this help
|
|
67
|
+
-v, --version Show version
|
|
68
|
+
`);
|
|
69
|
+
}
|
|
70
|
+
// ─── Full wizard ──────────────────────────────────
|
|
71
|
+
async function wizardFull() {
|
|
72
|
+
console.log(`\n agent-sync v${VERSION}\n`);
|
|
73
|
+
// Step 1: AGENTS.md / Prompt
|
|
74
|
+
log.header('Step 1/3 — AGENTS.md (Prompt File)');
|
|
75
|
+
await wizardAgents();
|
|
76
|
+
// Step 2: Skills
|
|
77
|
+
log.header('Step 2/3 — Skills Sync');
|
|
78
|
+
await wizardSkills();
|
|
79
|
+
// Step 3: MCP
|
|
80
|
+
log.header('Step 3/3 — MCP Config Sync (Global)');
|
|
81
|
+
await wizardMcp();
|
|
82
|
+
console.log('');
|
|
83
|
+
log.ok('All done! Your agent configs are synced.');
|
|
84
|
+
}
|
|
85
|
+
// ─── Agents wizard ────────────────────────────────
|
|
86
|
+
async function wizardAgents() {
|
|
87
|
+
const candidates = detectPromptFiles(cwd);
|
|
88
|
+
if (candidates.length === 0) {
|
|
89
|
+
log.choice(1, 'NONE', '(no prompt files detected)');
|
|
90
|
+
const selection = await choose('Select prompt source', 1);
|
|
91
|
+
if (selection === 1) {
|
|
92
|
+
console.log('');
|
|
93
|
+
log.info('Enter your prompt content below.');
|
|
94
|
+
log.info('Press Ctrl+D (EOF) when done, or type "SKIP" to skip this step.\n');
|
|
95
|
+
const content = await readMultiline();
|
|
96
|
+
if (content.trim() === 'SKIP' || content.trim() === '') {
|
|
97
|
+
log.warn('Skipped AGENTS.md generation.');
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
// Confirm no conflict
|
|
101
|
+
const existing = join(cwd, 'AGENTS.md');
|
|
102
|
+
if (fs.existsSync(existing)) {
|
|
103
|
+
const ans = await ask(' AGENTS.md already exists. Overwrite? [y/N]: ');
|
|
104
|
+
if (ans.toLowerCase() !== 'y') {
|
|
105
|
+
log.warn('Skipped (not overwriting).');
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
generateAgentsMd(cwd, content);
|
|
110
|
+
}
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
// Show detected candidates
|
|
114
|
+
for (let i = 0; i < candidates.length; i++) {
|
|
115
|
+
const c = candidates[i];
|
|
116
|
+
log.choice(i + 1, c.label, `(${c.sizeKB}KB)`);
|
|
117
|
+
}
|
|
118
|
+
log.choice(candidates.length + 1, 'NONE', '(enter raw prompt manually)');
|
|
119
|
+
const selection = await choose('Select prompt source', candidates.length + 1);
|
|
120
|
+
if (selection <= candidates.length) {
|
|
121
|
+
// Use selected file
|
|
122
|
+
const chosen = candidates[selection - 1];
|
|
123
|
+
const content = fs.readFileSync(chosen.path, 'utf8');
|
|
124
|
+
log.info(`Using: ${chosen.label}`);
|
|
125
|
+
generateAgentsMd(cwd, content);
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
// Manual input
|
|
129
|
+
log.info('Enter your prompt content (Ctrl+D to finish, "SKIP" to skip):');
|
|
130
|
+
const content = await readMultiline();
|
|
131
|
+
if (content.trim() === 'SKIP' || content.trim() === '') {
|
|
132
|
+
log.warn('Skipped AGENTS.md generation.');
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
generateAgentsMd(cwd, content);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// ─── Skills wizard ────────────────────────────────
|
|
139
|
+
async function wizardSkills() {
|
|
140
|
+
const candidates = detectSkillSources(cwd);
|
|
141
|
+
if (candidates.length === 0) {
|
|
142
|
+
log.choice(1, 'NONE', '(no skill directories detected)');
|
|
143
|
+
const selection = await choose('Select skill source', 1);
|
|
144
|
+
if (selection === 1) {
|
|
145
|
+
const defaultDir = join(cwd, '.agent', 'skills');
|
|
146
|
+
fs.mkdirSync(defaultDir, { recursive: true });
|
|
147
|
+
console.log('');
|
|
148
|
+
log.info(`Created: ${defaultDir}`);
|
|
149
|
+
log.info('Place your SKILL.md folders here and run agent-sync again.');
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
// Show detected candidates
|
|
155
|
+
for (let i = 0; i < candidates.length; i++) {
|
|
156
|
+
const c = candidates[i];
|
|
157
|
+
log.choice(i + 1, c.label, `(${c.count} skills)`);
|
|
158
|
+
}
|
|
159
|
+
log.choice(candidates.length + 1, 'NONE', '(create empty skill directory)');
|
|
160
|
+
const selection = await choose('Select skill source', candidates.length + 1);
|
|
161
|
+
if (selection <= candidates.length) {
|
|
162
|
+
const chosen = candidates[selection - 1];
|
|
163
|
+
log.info(`Using: ${chosen.label} (${chosen.count} skills)`);
|
|
164
|
+
console.log(' Syncing...');
|
|
165
|
+
const result = syncSkills(cwd, chosen.path);
|
|
166
|
+
for (const link of result.links) {
|
|
167
|
+
if (link.status === 'ok') {
|
|
168
|
+
log.ok(`${link.name}: ${link.linkPath} → ${link.target}`);
|
|
169
|
+
}
|
|
170
|
+
else if (link.status === 'skip') {
|
|
171
|
+
log.dim(`${link.name}: ${link.action}`);
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
log.err(`${link.name}: ${link.error}`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
const skills = listSkills(chosen.path);
|
|
178
|
+
log.info(`Active skills: ${skills.join(', ')}`);
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
const defaultDir = join(cwd, '.agent', 'skills');
|
|
182
|
+
fs.mkdirSync(defaultDir, { recursive: true });
|
|
183
|
+
console.log('');
|
|
184
|
+
log.info(`Created: ${defaultDir}`);
|
|
185
|
+
log.info('Place your SKILL.md folders here and run agent-sync again.');
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
// ─── MCP wizard ───────────────────────────────────
|
|
189
|
+
async function wizardMcp() {
|
|
190
|
+
const candidates = detectMcpConfigs();
|
|
191
|
+
if (candidates.length === 0) {
|
|
192
|
+
log.choice(1, 'NONE', '(no MCP configs detected)');
|
|
193
|
+
const selection = await choose('Select MCP source', 1);
|
|
194
|
+
if (selection === 1) {
|
|
195
|
+
fs.mkdirSync(AGENT_SYNC_HOME, { recursive: true });
|
|
196
|
+
const defaultConfig = {
|
|
197
|
+
servers: {
|
|
198
|
+
context7: {
|
|
199
|
+
command: 'npx',
|
|
200
|
+
args: ['-y', '@upstash/context7-mcp'],
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
saveMcpConfig(defaultConfig);
|
|
205
|
+
console.log('');
|
|
206
|
+
log.info(`Created: ${MCP_PATH}`);
|
|
207
|
+
log.dim(JSON.stringify(defaultConfig, null, 2).split('\n').slice(0, 8).join('\n '));
|
|
208
|
+
log.info('Edit this file to add your MCP servers, then run agent-sync again.');
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
// Show detected candidates
|
|
214
|
+
for (let i = 0; i < candidates.length; i++) {
|
|
215
|
+
const c = candidates[i];
|
|
216
|
+
log.choice(i + 1, c.label, `(${c.count} servers) ${c.path}`);
|
|
217
|
+
}
|
|
218
|
+
log.choice(candidates.length + 1, 'NONE', '(create default MCP config)');
|
|
219
|
+
const selection = await choose('Select MCP source', candidates.length + 1);
|
|
220
|
+
if (selection <= candidates.length) {
|
|
221
|
+
const chosen = candidates[selection - 1];
|
|
222
|
+
log.info(`Using: ${chosen.label} (${chosen.count} servers)`);
|
|
223
|
+
// Import to unified format if not already agent-sync config
|
|
224
|
+
let config;
|
|
225
|
+
if (chosen.label === 'agent-sync') {
|
|
226
|
+
config = loadMcpConfig();
|
|
227
|
+
}
|
|
228
|
+
else if (chosen.label === 'Claude') {
|
|
229
|
+
config = importFromClaude() ?? { servers: {} };
|
|
230
|
+
saveMcpConfig(config);
|
|
231
|
+
log.ok(`Imported to ${MCP_PATH}`);
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
// For other sources, import from Claude format (similar structure)
|
|
235
|
+
try {
|
|
236
|
+
const raw = JSON.parse(fs.readFileSync(chosen.path, 'utf8'));
|
|
237
|
+
const servers = {};
|
|
238
|
+
const mcpServers = raw.mcpServers || raw.mcp || {};
|
|
239
|
+
for (const [name, srv] of Object.entries(mcpServers)) {
|
|
240
|
+
servers[name] = { command: srv.command, args: srv.args || [] };
|
|
241
|
+
if (srv.env)
|
|
242
|
+
servers[name].env = srv.env;
|
|
243
|
+
}
|
|
244
|
+
config = { servers };
|
|
245
|
+
saveMcpConfig(config);
|
|
246
|
+
log.ok(`Imported to ${MCP_PATH}`);
|
|
247
|
+
}
|
|
248
|
+
catch {
|
|
249
|
+
log.err('Failed to parse selected config');
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
// Sync to all
|
|
254
|
+
console.log(' Syncing to all CLIs...');
|
|
255
|
+
const results = syncToAll(config);
|
|
256
|
+
const synced = Object.values(results).filter(Boolean).length;
|
|
257
|
+
log.info(`Synced to ${synced}/6 CLIs.`);
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
fs.mkdirSync(AGENT_SYNC_HOME, { recursive: true });
|
|
261
|
+
const defaultConfig = {
|
|
262
|
+
servers: {
|
|
263
|
+
context7: {
|
|
264
|
+
command: 'npx',
|
|
265
|
+
args: ['-y', '@upstash/context7-mcp'],
|
|
266
|
+
},
|
|
267
|
+
},
|
|
268
|
+
};
|
|
269
|
+
saveMcpConfig(defaultConfig);
|
|
270
|
+
console.log('');
|
|
271
|
+
log.info(`Created: ${MCP_PATH}`);
|
|
272
|
+
log.info('Edit this file to add your MCP servers, then run agent-sync again.');
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
// ─── Helpers ──────────────────────────────────────
|
|
276
|
+
function readMultiline() {
|
|
277
|
+
return new Promise((resolve) => {
|
|
278
|
+
const chunks = [];
|
|
279
|
+
process.stdin.setEncoding('utf8');
|
|
280
|
+
process.stdin.on('data', (chunk) => chunks.push(String(chunk)));
|
|
281
|
+
process.stdin.on('end', () => resolve(chunks.join('')));
|
|
282
|
+
process.stdin.resume();
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
// ─── Run ──────────────────────────────────────────
|
|
286
|
+
main().catch((e) => {
|
|
287
|
+
log.err(e.message);
|
|
288
|
+
process.exit(1);
|
|
289
|
+
});
|
|
290
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface PromptCandidate {
|
|
2
|
+
label: string;
|
|
3
|
+
path: string;
|
|
4
|
+
sizeKB: number;
|
|
5
|
+
}
|
|
6
|
+
export declare function detectPromptFiles(cwd: string): PromptCandidate[];
|
|
7
|
+
export interface AgentsMdResult {
|
|
8
|
+
targets: string[];
|
|
9
|
+
size: number;
|
|
10
|
+
}
|
|
11
|
+
export declare function generateAgentsMd(cwd: string, content: string): AgentsMdResult;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* core/agents-md.ts — AGENTS.md generation (project-level)
|
|
3
|
+
*
|
|
4
|
+
* Auto-detects prompt template files from project.
|
|
5
|
+
* Writes AGENTS.md to project root for Codex/Copilot/OpenCode discovery.
|
|
6
|
+
*/
|
|
7
|
+
import fs from 'node:fs';
|
|
8
|
+
import { join } from 'node:path';
|
|
9
|
+
import { log } from '../utils/log.js';
|
|
10
|
+
export function detectPromptFiles(cwd) {
|
|
11
|
+
const candidates = [];
|
|
12
|
+
// Only check files directly in project root (no subdirectory scanning)
|
|
13
|
+
const patterns = [
|
|
14
|
+
'AGENTS.md',
|
|
15
|
+
'CLAUDE.md',
|
|
16
|
+
'COPILOT.md',
|
|
17
|
+
'INSTRUCTIONS.md',
|
|
18
|
+
'PROMPT.md',
|
|
19
|
+
'CODEX.md',
|
|
20
|
+
'.github/copilot-instructions.md',
|
|
21
|
+
];
|
|
22
|
+
for (const pattern of patterns) {
|
|
23
|
+
const fullPath = join(cwd, pattern);
|
|
24
|
+
try {
|
|
25
|
+
const stat = fs.statSync(fullPath);
|
|
26
|
+
if (stat.isFile() && stat.size > 0) {
|
|
27
|
+
candidates.push({
|
|
28
|
+
label: pattern,
|
|
29
|
+
path: fullPath,
|
|
30
|
+
sizeKB: Math.round(stat.size / 1024),
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
catch { /* skip */ }
|
|
35
|
+
}
|
|
36
|
+
return candidates;
|
|
37
|
+
}
|
|
38
|
+
export function generateAgentsMd(cwd, content) {
|
|
39
|
+
const targets = [
|
|
40
|
+
join(cwd, 'AGENTS.md'),
|
|
41
|
+
];
|
|
42
|
+
for (const target of targets) {
|
|
43
|
+
fs.mkdirSync(join(target, '..'), { recursive: true });
|
|
44
|
+
fs.writeFileSync(target, content);
|
|
45
|
+
log.ok(`Written: ${target}`);
|
|
46
|
+
}
|
|
47
|
+
return { targets, size: content.length };
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=agents-md.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agents-md.js","sourceRoot":"","sources":["../../src/core/agents-md.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,IAAI,EAAY,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAUtC,MAAM,UAAU,iBAAiB,CAAC,GAAW;IACzC,MAAM,UAAU,GAAsB,EAAE,CAAC;IAEzC,uEAAuE;IACvE,MAAM,QAAQ,GAAG;QACb,WAAW;QACX,WAAW;QACX,YAAY;QACZ,iBAAiB;QACjB,WAAW;QACX,UAAU;QACV,iCAAiC;KACpC,CAAC;IAEF,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QACpC,IAAI,CAAC;YACD,MAAM,IAAI,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACnC,IAAI,IAAI,CAAC,MAAM,EAAE,IAAI,IAAI,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;gBACjC,UAAU,CAAC,IAAI,CAAC;oBACZ,KAAK,EAAE,OAAO;oBACd,IAAI,EAAE,QAAQ;oBACd,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;iBACvC,CAAC,CAAC;YACP,CAAC;QACL,CAAC;QAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC;IAC1B,CAAC;IACD,OAAO,UAAU,CAAC;AACtB,CAAC;AASD,MAAM,UAAU,gBAAgB,CAAC,GAAW,EAAE,OAAe;IACzD,MAAM,OAAO,GAAG;QACZ,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC;KACzB,CAAC;IAEF,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC3B,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtD,EAAE,CAAC,aAAa,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAClC,GAAG,CAAC,EAAE,CAAC,YAAY,MAAM,EAAE,CAAC,CAAC;IACjC,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;AAC7C,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* core/config.ts — Configuration & paths
|
|
3
|
+
*/
|
|
4
|
+
import { join, resolve } from 'node:path';
|
|
5
|
+
import os from 'node:os';
|
|
6
|
+
import fs from 'node:fs';
|
|
7
|
+
export const HOME = os.homedir();
|
|
8
|
+
export const AGENT_SYNC_HOME = process.env.AGENT_SYNC_HOME
|
|
9
|
+
? resolve(process.env.AGENT_SYNC_HOME.replace(/^~(?=\/|$)/, HOME))
|
|
10
|
+
: join(HOME, '.agent-sync');
|
|
11
|
+
export const MCP_PATH = join(AGENT_SYNC_HOME, 'mcp.json');
|
|
12
|
+
export const SKILLS_DIR = join(AGENT_SYNC_HOME, 'skills');
|
|
13
|
+
export const SKILLS_REF_DIR = join(AGENT_SYNC_HOME, 'skills_ref');
|
|
14
|
+
export function ensureHome() {
|
|
15
|
+
fs.mkdirSync(AGENT_SYNC_HOME, { recursive: true });
|
|
16
|
+
fs.mkdirSync(SKILLS_DIR, { recursive: true });
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB,MAAM,CAAC,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;AACjC,MAAM,CAAC,MAAM,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe;IACtD,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,OAAO,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;IAClE,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;AAEhC,MAAM,CAAC,MAAM,QAAQ,GAAG,IAAI,CAAC,eAAe,EAAE,UAAU,CAAC,CAAC;AAC1D,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC;AAC1D,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,CAAC,eAAe,EAAE,YAAY,CAAC,CAAC;AAElE,MAAM,UAAU,UAAU;IACtB,EAAE,CAAC,SAAS,CAAC,eAAe,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACnD,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAClD,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare function loadMcpConfig(): Record<string, any>;
|
|
2
|
+
export declare function saveMcpConfig(config: Record<string, any>): void;
|
|
3
|
+
export declare function importFromClaude(): Record<string, any> | null;
|
|
4
|
+
export interface McpCandidate {
|
|
5
|
+
label: string;
|
|
6
|
+
path: string;
|
|
7
|
+
count: number;
|
|
8
|
+
}
|
|
9
|
+
export declare function detectMcpConfigs(): McpCandidate[];
|
|
10
|
+
export interface SyncResults {
|
|
11
|
+
claude: boolean;
|
|
12
|
+
codex: boolean;
|
|
13
|
+
gemini: boolean;
|
|
14
|
+
opencode: boolean;
|
|
15
|
+
copilot: boolean;
|
|
16
|
+
antigravity: boolean;
|
|
17
|
+
}
|
|
18
|
+
export declare function syncToAll(config: Record<string, any>): SyncResults;
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* core/mcp-sync.ts — MCP config sync to all AI coding CLIs (global)
|
|
3
|
+
* Extracted from cli-jaw lib/mcp-sync.ts
|
|
4
|
+
*
|
|
5
|
+
* Source of truth: ~/.agent-sync/mcp.json
|
|
6
|
+
* Targets (all global):
|
|
7
|
+
* Claude Code → ~/.mcp.json (JSON, mcpServers)
|
|
8
|
+
* Codex → ~/.codex/config.toml (TOML, [mcp_servers.*])
|
|
9
|
+
* Gemini CLI → ~/.gemini/settings.json (JSON, mcpServers)
|
|
10
|
+
* OpenCode → ~/.config/opencode/opencode.json (JSON, mcp)
|
|
11
|
+
* Copilot → ~/.copilot/mcp-config.json (JSON, mcpServers)
|
|
12
|
+
* Antigravity → ~/.gemini/antigravity/mcp_config.json (JSON, mcpServers)
|
|
13
|
+
*/
|
|
14
|
+
import fs from 'node:fs';
|
|
15
|
+
import { join, dirname } from 'node:path';
|
|
16
|
+
import os from 'node:os';
|
|
17
|
+
import { MCP_PATH, ensureHome } from './config.js';
|
|
18
|
+
import { log } from '../utils/log.js';
|
|
19
|
+
const HOME = os.homedir();
|
|
20
|
+
// ─── Load / Save ──────────────────────────────────
|
|
21
|
+
export function loadMcpConfig() {
|
|
22
|
+
try {
|
|
23
|
+
return JSON.parse(fs.readFileSync(MCP_PATH, 'utf8'));
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return { servers: {} };
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export function saveMcpConfig(config) {
|
|
30
|
+
ensureHome();
|
|
31
|
+
fs.writeFileSync(MCP_PATH, JSON.stringify(config, null, 4) + '\n');
|
|
32
|
+
}
|
|
33
|
+
// ─── Format converters ────────────────────────────
|
|
34
|
+
function toClaudeMcp(config) {
|
|
35
|
+
const servers = config.servers || {};
|
|
36
|
+
const result = {};
|
|
37
|
+
for (const [name, srv] of Object.entries(servers)) {
|
|
38
|
+
result[name] = { command: srv.command, args: srv.args || [] };
|
|
39
|
+
if (srv.env)
|
|
40
|
+
result[name].env = srv.env;
|
|
41
|
+
}
|
|
42
|
+
return { mcpServers: result };
|
|
43
|
+
}
|
|
44
|
+
function toCodexToml(config) {
|
|
45
|
+
const servers = config.servers || {};
|
|
46
|
+
let toml = '';
|
|
47
|
+
for (const [name, srv] of Object.entries(servers)) {
|
|
48
|
+
toml += `[mcp_servers.${name}]\n`;
|
|
49
|
+
toml += `command = "${srv.command}"\n`;
|
|
50
|
+
if (srv.args?.length) {
|
|
51
|
+
toml += `args = [${srv.args.map((a) => `"${a}"`).join(', ')}]\n`;
|
|
52
|
+
}
|
|
53
|
+
if (srv.env) {
|
|
54
|
+
toml += `[mcp_servers.${name}.env]\n`;
|
|
55
|
+
for (const [k, v] of Object.entries(srv.env)) {
|
|
56
|
+
toml += `${k} = "${v}"\n`;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
toml += '\n';
|
|
60
|
+
}
|
|
61
|
+
return toml;
|
|
62
|
+
}
|
|
63
|
+
function toOpenCodeMcp(config) {
|
|
64
|
+
const servers = config.servers || {};
|
|
65
|
+
const result = {};
|
|
66
|
+
for (const [name, srv] of Object.entries(servers)) {
|
|
67
|
+
result[name] = { command: srv.command, args: srv.args || [] };
|
|
68
|
+
if (srv.env)
|
|
69
|
+
result[name].env = srv.env;
|
|
70
|
+
}
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
73
|
+
function patchCodexToml(existingToml, newMcpToml) {
|
|
74
|
+
// Remove existing [mcp_servers.*] blocks
|
|
75
|
+
const cleaned = existingToml.replace(/\[mcp_servers\.[^\]]+\][\s\S]*?(?=\n\[(?!mcp_servers)|$)/g, '').trimEnd();
|
|
76
|
+
return cleaned + '\n\n' + newMcpToml;
|
|
77
|
+
}
|
|
78
|
+
function patchJsonFile(filePath, patchObj) {
|
|
79
|
+
let existing = {};
|
|
80
|
+
try {
|
|
81
|
+
existing = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
82
|
+
}
|
|
83
|
+
catch { }
|
|
84
|
+
Object.assign(existing, patchObj);
|
|
85
|
+
fs.writeFileSync(filePath, JSON.stringify(existing, null, 4) + '\n');
|
|
86
|
+
}
|
|
87
|
+
// ─── Import ───────────────────────────────────────
|
|
88
|
+
export function importFromClaude() {
|
|
89
|
+
const p = join(HOME, '.mcp.json');
|
|
90
|
+
try {
|
|
91
|
+
const data = JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
92
|
+
const mcpServers = data.mcpServers || {};
|
|
93
|
+
const servers = {};
|
|
94
|
+
for (const [name, srv] of Object.entries(mcpServers)) {
|
|
95
|
+
servers[name] = { command: srv.command, args: srv.args || [] };
|
|
96
|
+
if (srv.env)
|
|
97
|
+
servers[name].env = srv.env;
|
|
98
|
+
}
|
|
99
|
+
return { servers };
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
export function detectMcpConfigs() {
|
|
106
|
+
const candidates = [];
|
|
107
|
+
const checks = [
|
|
108
|
+
['agent-sync', MCP_PATH],
|
|
109
|
+
['Claude', join(HOME, '.mcp.json')],
|
|
110
|
+
['Codex', join(HOME, '.codex', 'config.toml')],
|
|
111
|
+
['Gemini', join(HOME, '.gemini', 'settings.json')],
|
|
112
|
+
['Copilot', join(HOME, '.copilot', 'mcp-config.json')],
|
|
113
|
+
['Antigravity', join(HOME, '.gemini', 'antigravity', 'mcp_config.json')],
|
|
114
|
+
['OpenCode', join(HOME, '.config', 'opencode', 'opencode.json')],
|
|
115
|
+
];
|
|
116
|
+
for (const [label, path] of checks) {
|
|
117
|
+
try {
|
|
118
|
+
const raw = fs.readFileSync(path, 'utf8');
|
|
119
|
+
let count = 0;
|
|
120
|
+
if (path.endsWith('.toml')) {
|
|
121
|
+
count = (raw.match(/\[mcp_servers\./g) || []).length;
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
const data = JSON.parse(raw);
|
|
125
|
+
const servers = data.mcpServers || data.servers || data.mcp || {};
|
|
126
|
+
count = Object.keys(servers).length;
|
|
127
|
+
}
|
|
128
|
+
if (count > 0)
|
|
129
|
+
candidates.push({ label, path, count });
|
|
130
|
+
}
|
|
131
|
+
catch { /* skip */ }
|
|
132
|
+
}
|
|
133
|
+
return candidates;
|
|
134
|
+
}
|
|
135
|
+
export function syncToAll(config) {
|
|
136
|
+
const results = {
|
|
137
|
+
claude: false, codex: false, gemini: false,
|
|
138
|
+
opencode: false, copilot: false, antigravity: false,
|
|
139
|
+
};
|
|
140
|
+
// 1. Claude Code: ~/.mcp.json
|
|
141
|
+
try {
|
|
142
|
+
const p = join(HOME, '.mcp.json');
|
|
143
|
+
const data = toClaudeMcp(config);
|
|
144
|
+
let existing = {};
|
|
145
|
+
try {
|
|
146
|
+
existing = JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
147
|
+
}
|
|
148
|
+
catch { }
|
|
149
|
+
existing.mcpServers = data.mcpServers;
|
|
150
|
+
fs.writeFileSync(p, JSON.stringify(existing, null, 4) + '\n');
|
|
151
|
+
results.claude = true;
|
|
152
|
+
log.ok(`Claude: ${p}`);
|
|
153
|
+
}
|
|
154
|
+
catch (e) {
|
|
155
|
+
log.err(`Claude: ${e.message}`);
|
|
156
|
+
}
|
|
157
|
+
// 2. Codex: ~/.codex/config.toml
|
|
158
|
+
try {
|
|
159
|
+
const p = join(HOME, '.codex', 'config.toml');
|
|
160
|
+
if (fs.existsSync(p)) {
|
|
161
|
+
const existing = fs.readFileSync(p, 'utf8');
|
|
162
|
+
fs.writeFileSync(p, patchCodexToml(existing, toCodexToml(config)));
|
|
163
|
+
results.codex = true;
|
|
164
|
+
log.ok(`Codex: ${p}`);
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
log.dim(`Codex: config.toml not found, skipping`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
catch (e) {
|
|
171
|
+
log.err(`Codex: ${e.message}`);
|
|
172
|
+
}
|
|
173
|
+
// 3. Gemini CLI: ~/.gemini/settings.json
|
|
174
|
+
try {
|
|
175
|
+
const p = join(HOME, '.gemini', 'settings.json');
|
|
176
|
+
if (fs.existsSync(p)) {
|
|
177
|
+
patchJsonFile(p, { mcpServers: toClaudeMcp(config).mcpServers });
|
|
178
|
+
results.gemini = true;
|
|
179
|
+
log.ok(`Gemini: ${p}`);
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
log.dim(`Gemini: settings.json not found, skipping`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
catch (e) {
|
|
186
|
+
log.err(`Gemini: ${e.message}`);
|
|
187
|
+
}
|
|
188
|
+
// 4. OpenCode: ~/.config/opencode/opencode.json
|
|
189
|
+
try {
|
|
190
|
+
const p = join(HOME, '.config', 'opencode', 'opencode.json');
|
|
191
|
+
if (fs.existsSync(p)) {
|
|
192
|
+
patchJsonFile(p, { mcp: toOpenCodeMcp(config) });
|
|
193
|
+
results.opencode = true;
|
|
194
|
+
log.ok(`OpenCode: ${p}`);
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
log.dim(`OpenCode: opencode.json not found, skipping`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
catch (e) {
|
|
201
|
+
log.err(`OpenCode: ${e.message}`);
|
|
202
|
+
}
|
|
203
|
+
// 5. Copilot: ~/.copilot/mcp-config.json
|
|
204
|
+
try {
|
|
205
|
+
const dir = join(HOME, '.copilot');
|
|
206
|
+
const p = join(dir, 'mcp-config.json');
|
|
207
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
208
|
+
let existing = {};
|
|
209
|
+
try {
|
|
210
|
+
existing = JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
211
|
+
}
|
|
212
|
+
catch { }
|
|
213
|
+
existing.mcpServers = toClaudeMcp(config).mcpServers;
|
|
214
|
+
fs.writeFileSync(p, JSON.stringify(existing, null, 4) + '\n');
|
|
215
|
+
results.copilot = true;
|
|
216
|
+
log.ok(`Copilot: ${p}`);
|
|
217
|
+
}
|
|
218
|
+
catch (e) {
|
|
219
|
+
log.err(`Copilot: ${e.message}`);
|
|
220
|
+
}
|
|
221
|
+
// 6. Antigravity: ~/.gemini/antigravity/mcp_config.json
|
|
222
|
+
try {
|
|
223
|
+
const p = join(HOME, '.gemini', 'antigravity', 'mcp_config.json');
|
|
224
|
+
fs.mkdirSync(dirname(p), { recursive: true });
|
|
225
|
+
let existing = {};
|
|
226
|
+
try {
|
|
227
|
+
existing = JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
228
|
+
}
|
|
229
|
+
catch { }
|
|
230
|
+
existing.mcpServers = toClaudeMcp(config).mcpServers;
|
|
231
|
+
fs.writeFileSync(p, JSON.stringify(existing, null, 4) + '\n');
|
|
232
|
+
results.antigravity = true;
|
|
233
|
+
log.ok(`Antigravity: ${p}`);
|
|
234
|
+
}
|
|
235
|
+
catch (e) {
|
|
236
|
+
log.err(`Antigravity: ${e.message}`);
|
|
237
|
+
}
|
|
238
|
+
return results;
|
|
239
|
+
}
|
|
240
|
+
//# sourceMappingURL=mcp-sync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-sync.js","sourceRoot":"","sources":["../../src/core/mcp-sync.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type SymlinkResult } from './symlink.js';
|
|
2
|
+
export interface SkillCandidate {
|
|
3
|
+
label: string;
|
|
4
|
+
path: string;
|
|
5
|
+
count: number;
|
|
6
|
+
}
|
|
7
|
+
export declare function detectSkillSources(cwd: string): SkillCandidate[];
|
|
8
|
+
export interface SkillSyncResult {
|
|
9
|
+
source: string;
|
|
10
|
+
links: SymlinkResult[];
|
|
11
|
+
}
|
|
12
|
+
export declare function syncSkills(cwd: string, sourcePath: string): SkillSyncResult;
|
|
13
|
+
export declare function listSkills(skillsDir: string): string[];
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* core/skill-sync.ts — Skills symlink sync (project-level)
|
|
3
|
+
* Extracted from cli-jaw lib/mcp-sync.ts
|
|
4
|
+
*
|
|
5
|
+
* Creates symlinks so all AI agents can find skills:
|
|
6
|
+
* {cwd}/.agent/skills/ ← source directory (real files)
|
|
7
|
+
* {cwd}/.agents/skills/ → .agent/skills (symlink)
|
|
8
|
+
* {cwd}/.claude/skills/ → .agent/skills (symlink)
|
|
9
|
+
*/
|
|
10
|
+
import fs from 'node:fs';
|
|
11
|
+
import { join } from 'node:path';
|
|
12
|
+
import { ensureSymlinkSafe, createBackupContext } from './symlink.js';
|
|
13
|
+
export function detectSkillSources(cwd) {
|
|
14
|
+
const candidates = [];
|
|
15
|
+
// Common locations to check
|
|
16
|
+
const checks = [
|
|
17
|
+
['Project .agent/skills', join(cwd, '.agent', 'skills')],
|
|
18
|
+
['Project .agents/skills', join(cwd, '.agents', 'skills')],
|
|
19
|
+
['Project .claude/skills', join(cwd, '.claude', 'skills')],
|
|
20
|
+
['Project skills_ref/', join(cwd, 'skills_ref')],
|
|
21
|
+
];
|
|
22
|
+
// Also walk one level of subdirectories for monorepo patterns
|
|
23
|
+
try {
|
|
24
|
+
for (const entry of fs.readdirSync(cwd, { withFileTypes: true })) {
|
|
25
|
+
if (!entry.isDirectory() || entry.name.startsWith('.'))
|
|
26
|
+
continue;
|
|
27
|
+
const sub = join(cwd, entry.name, 'skills_ref');
|
|
28
|
+
if (fs.existsSync(sub)) {
|
|
29
|
+
checks.push([`${entry.name}/skills_ref`, sub]);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
catch { /* ignore */ }
|
|
34
|
+
for (const [label, path] of checks) {
|
|
35
|
+
try {
|
|
36
|
+
const realPath = fs.realpathSync(path);
|
|
37
|
+
const stat = fs.statSync(realPath);
|
|
38
|
+
if (stat.isDirectory()) {
|
|
39
|
+
const items = fs.readdirSync(realPath).filter((f) => !f.startsWith('.') && f !== 'registry.json');
|
|
40
|
+
const skillCount = items.filter((f) => fs.statSync(join(realPath, f)).isDirectory()).length;
|
|
41
|
+
if (skillCount > 0) {
|
|
42
|
+
// Dedup by realPath
|
|
43
|
+
if (!candidates.some((c) => fs.realpathSync(c.path) === realPath)) {
|
|
44
|
+
candidates.push({ label, path, count: skillCount });
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
catch { /* skip broken paths */ }
|
|
50
|
+
}
|
|
51
|
+
return candidates;
|
|
52
|
+
}
|
|
53
|
+
export function syncSkills(cwd, sourcePath) {
|
|
54
|
+
const backupContext = createBackupContext();
|
|
55
|
+
const links = [];
|
|
56
|
+
// Target paths within the project
|
|
57
|
+
const targets = [
|
|
58
|
+
['agent_skills', join(cwd, '.agent', 'skills')],
|
|
59
|
+
['agents_skills', join(cwd, '.agents', 'skills')],
|
|
60
|
+
['claude_skills', join(cwd, '.claude', 'skills')],
|
|
61
|
+
];
|
|
62
|
+
// Determine canonical location (first real directory or the source itself)
|
|
63
|
+
const canonicalPath = join(cwd, '.agent', 'skills');
|
|
64
|
+
for (const [name, targetPath] of targets) {
|
|
65
|
+
if (targetPath === sourcePath) {
|
|
66
|
+
// Source IS this path — skip
|
|
67
|
+
links.push({
|
|
68
|
+
status: 'skip', action: 'is_source', name, linkPath: targetPath, target: sourcePath,
|
|
69
|
+
});
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (targetPath === canonicalPath && sourcePath !== canonicalPath) {
|
|
73
|
+
// .agent/skills is the canonical target — symlink to source
|
|
74
|
+
links.push(ensureSymlinkSafe(sourcePath, targetPath, {
|
|
75
|
+
onConflict: 'backup', backupContext, name,
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
// Others → symlink to canonical
|
|
80
|
+
links.push(ensureSymlinkSafe(canonicalPath, targetPath, {
|
|
81
|
+
onConflict: 'backup', backupContext, name,
|
|
82
|
+
}));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return { source: sourcePath, links };
|
|
86
|
+
}
|
|
87
|
+
// ─── List active skills ───────────────────────────
|
|
88
|
+
export function listSkills(skillsDir) {
|
|
89
|
+
try {
|
|
90
|
+
return fs.readdirSync(skillsDir).filter((f) => {
|
|
91
|
+
if (f.startsWith('.') || f === 'registry.json')
|
|
92
|
+
return false;
|
|
93
|
+
try {
|
|
94
|
+
return fs.statSync(join(skillsDir, f)).isDirectory();
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
return [];
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=skill-sync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-sync.js","sourceRoot":"","sources":["../../src/core/skill-sync.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
interface BackupContext {
|
|
2
|
+
root: string;
|
|
3
|
+
count: number;
|
|
4
|
+
}
|
|
5
|
+
export declare function createBackupContext(): BackupContext;
|
|
6
|
+
export declare function resolveSymlinkTarget(linkPath: string, rawTarget: string): string;
|
|
7
|
+
export interface SymlinkResult {
|
|
8
|
+
status: 'ok' | 'skip' | 'error';
|
|
9
|
+
action: string;
|
|
10
|
+
name: string;
|
|
11
|
+
linkPath: string;
|
|
12
|
+
target: string;
|
|
13
|
+
error?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function ensureSymlinkSafe(target: string, linkPath: string, opts?: {
|
|
16
|
+
onConflict?: string;
|
|
17
|
+
backupContext?: BackupContext;
|
|
18
|
+
name?: string;
|
|
19
|
+
}): SymlinkResult;
|
|
20
|
+
/**
|
|
21
|
+
* Recursively copy a directory (symlink-safe, error-resilient)
|
|
22
|
+
*/
|
|
23
|
+
export declare function copyDirRecursive(src: string, dst: string): void;
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* core/symlink.ts — Safe symlink creation with conflict resolution
|
|
3
|
+
* Extracted from cli-jaw lib/mcp-sync.ts
|
|
4
|
+
*/
|
|
5
|
+
import fs from 'node:fs';
|
|
6
|
+
import { join, dirname, resolve } from 'node:path';
|
|
7
|
+
import { AGENT_SYNC_HOME } from './config.js';
|
|
8
|
+
export function createBackupContext() {
|
|
9
|
+
const root = join(AGENT_SYNC_HOME, 'backups', new Date().toISOString().slice(0, 10));
|
|
10
|
+
return { root, count: 0 };
|
|
11
|
+
}
|
|
12
|
+
export function resolveSymlinkTarget(linkPath, rawTarget) {
|
|
13
|
+
if (rawTarget.startsWith('/'))
|
|
14
|
+
return rawTarget;
|
|
15
|
+
return resolve(dirname(linkPath), rawTarget);
|
|
16
|
+
}
|
|
17
|
+
export function ensureSymlinkSafe(target, linkPath, opts = {}) {
|
|
18
|
+
const onConflict = opts.onConflict ?? 'backup';
|
|
19
|
+
const name = opts.name ?? 'link';
|
|
20
|
+
const context = opts.backupContext ?? createBackupContext();
|
|
21
|
+
try {
|
|
22
|
+
fs.mkdirSync(dirname(linkPath), { recursive: true });
|
|
23
|
+
const stat = fs.lstatSync(linkPath, { throwIfNoEntry: false });
|
|
24
|
+
if (stat) {
|
|
25
|
+
if (stat.isSymbolicLink()) {
|
|
26
|
+
const rawTarget = fs.readlinkSync(linkPath);
|
|
27
|
+
const currentTarget = resolveSymlinkTarget(linkPath, rawTarget);
|
|
28
|
+
if (currentTarget === target) {
|
|
29
|
+
return { status: 'skip', action: 'already_correct', name, linkPath, target };
|
|
30
|
+
}
|
|
31
|
+
// Different target — update
|
|
32
|
+
fs.unlinkSync(linkPath);
|
|
33
|
+
fs.symlinkSync(target, linkPath);
|
|
34
|
+
return { status: 'ok', action: 'replace_symlink', name, linkPath, target };
|
|
35
|
+
}
|
|
36
|
+
// Real directory or file — conflict
|
|
37
|
+
if (onConflict === 'skip') {
|
|
38
|
+
return { status: 'skip', action: 'skip_conflict', name, linkPath, target };
|
|
39
|
+
}
|
|
40
|
+
// Backup and replace
|
|
41
|
+
movePathToBackup(linkPath, context);
|
|
42
|
+
fs.symlinkSync(target, linkPath);
|
|
43
|
+
return { status: 'ok', action: 'backup_and_link', name, linkPath, target };
|
|
44
|
+
}
|
|
45
|
+
// Nothing exists — create
|
|
46
|
+
fs.symlinkSync(target, linkPath);
|
|
47
|
+
return { status: 'ok', action: 'created', name, linkPath, target };
|
|
48
|
+
}
|
|
49
|
+
catch (e) {
|
|
50
|
+
return { status: 'error', action: 'error', name, linkPath, target, error: e.message };
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function movePathToBackup(pathToMove, context) {
|
|
54
|
+
fs.mkdirSync(context.root, { recursive: true });
|
|
55
|
+
const base = pathToMove.replace(/\//g, '__').replace(/^__/, '');
|
|
56
|
+
const dest = join(context.root, `${base}_${context.count++}`);
|
|
57
|
+
fs.renameSync(pathToMove, dest);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Recursively copy a directory (symlink-safe, error-resilient)
|
|
61
|
+
*/
|
|
62
|
+
export function copyDirRecursive(src, dst) {
|
|
63
|
+
fs.mkdirSync(dst, { recursive: true });
|
|
64
|
+
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
65
|
+
const srcPath = join(src, entry.name);
|
|
66
|
+
const dstPath = join(dst, entry.name);
|
|
67
|
+
try {
|
|
68
|
+
const realStat = fs.statSync(srcPath);
|
|
69
|
+
if (realStat.isDirectory()) {
|
|
70
|
+
copyDirRecursive(srcPath, dstPath);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
fs.copyFileSync(srcPath, dstPath);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
// Skip broken symlinks or permission errors
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=symlink.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"symlink.js","sourceRoot":"","sources":["../../src/core/symlink.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* utils/log.ts — Colored console output
|
|
3
|
+
*/
|
|
4
|
+
export declare const log: {
|
|
5
|
+
info: (msg: string) => void;
|
|
6
|
+
ok: (msg: string) => void;
|
|
7
|
+
warn: (msg: string) => void;
|
|
8
|
+
err: (msg: string) => void;
|
|
9
|
+
step: (n: number, total: number, msg: string) => void;
|
|
10
|
+
header: (msg: string) => void;
|
|
11
|
+
dim: (msg: string) => void;
|
|
12
|
+
choice: (n: number, label: string, detail?: string) => void;
|
|
13
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* utils/log.ts — Colored console output
|
|
3
|
+
*/
|
|
4
|
+
const RESET = '\x1b[0m';
|
|
5
|
+
const BOLD = '\x1b[1m';
|
|
6
|
+
const DIM = '\x1b[2m';
|
|
7
|
+
const CYAN = '\x1b[36m';
|
|
8
|
+
const GREEN = '\x1b[32m';
|
|
9
|
+
const YELLOW = '\x1b[33m';
|
|
10
|
+
const RED = '\x1b[31m';
|
|
11
|
+
const BLUE = '\x1b[34m';
|
|
12
|
+
const MAGENTA = '\x1b[35m';
|
|
13
|
+
export const log = {
|
|
14
|
+
info: (msg) => console.log(`${CYAN}ℹ${RESET} ${msg}`),
|
|
15
|
+
ok: (msg) => console.log(`${GREEN}✔${RESET} ${msg}`),
|
|
16
|
+
warn: (msg) => console.log(`${YELLOW}⚠${RESET} ${msg}`),
|
|
17
|
+
err: (msg) => console.error(`${RED}✖${RESET} ${msg}`),
|
|
18
|
+
step: (n, total, msg) => console.log(`${DIM}[${n}/${total}]${RESET} ${msg}`),
|
|
19
|
+
header: (msg) => console.log(`\n${BOLD}${BLUE}▸ ${msg}${RESET}`),
|
|
20
|
+
dim: (msg) => console.log(` ${DIM}${msg}${RESET}`),
|
|
21
|
+
choice: (n, label, detail) => console.log(` ${MAGENTA}${n})${RESET} ${label}${detail ? ` ${DIM}${detail}${RESET}` : ''}`),
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=log.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.js","sourceRoot":"","sources":["../../src/utils/log.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,KAAK,GAAG,SAAS,CAAC;AACxB,MAAM,IAAI,GAAG,SAAS,CAAC;AACvB,MAAM,GAAG,GAAG,SAAS,CAAC;AACtB,MAAM,IAAI,GAAG,UAAU,CAAC;AACxB,MAAM,KAAK,GAAG,UAAU,CAAC;AACzB,MAAM,MAAM,GAAG,UAAU,CAAC;AAC1B,MAAM,GAAG,GAAG,UAAU,CAAC;AACvB,MAAM,IAAI,GAAG,UAAU,CAAC;AACxB,MAAM,OAAO,GAAG,UAAU,CAAC;AAE3B,MAAM,CAAC,MAAM,GAAG,GAAG;IACf,IAAI,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,IAAI,KAAK,IAAI,GAAG,EAAE,CAAC;IAC7D,EAAE,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,IAAI,KAAK,IAAI,GAAG,EAAE,CAAC;IAC5D,IAAI,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,IAAI,KAAK,IAAI,GAAG,EAAE,CAAC;IAC/D,GAAG,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,KAAK,IAAI,GAAG,EAAE,CAAC;IAC7D,IAAI,EAAE,CAAC,CAAS,EAAE,KAAa,EAAE,GAAW,EAAE,EAAE,CAC5C,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,IAAI,KAAK,IAAI,KAAK,IAAI,GAAG,EAAE,CAAC;IACvD,MAAM,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,GAAG,IAAI,KAAK,GAAG,GAAG,KAAK,EAAE,CAAC;IACxE,GAAG,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,GAAG,GAAG,GAAG,GAAG,KAAK,EAAE,CAAC;IAC3D,MAAM,EAAE,CAAC,CAAS,EAAE,KAAa,EAAE,MAAe,EAAE,EAAE,CAClD,OAAO,CAAC,GAAG,CAAC,KAAK,OAAO,GAAG,CAAC,IAAI,KAAK,IAAI,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,GAAG,GAAG,MAAM,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;CACnG,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* utils/prompt.ts — Interactive stdin prompting
|
|
3
|
+
*/
|
|
4
|
+
import * as readline from 'node:readline';
|
|
5
|
+
export function ask(question) {
|
|
6
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
7
|
+
return new Promise((resolve) => {
|
|
8
|
+
rl.question(question, (answer) => {
|
|
9
|
+
rl.close();
|
|
10
|
+
resolve(answer.trim());
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
export async function choose(question, max) {
|
|
15
|
+
while (true) {
|
|
16
|
+
const raw = await ask(`${question} [1-${max}]: `);
|
|
17
|
+
const n = parseInt(raw, 10);
|
|
18
|
+
if (n >= 1 && n <= max)
|
|
19
|
+
return n;
|
|
20
|
+
console.log(` Please enter a number between 1 and ${max}.`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=prompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/utils/prompt.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAE1C,MAAM,UAAU,GAAG,CAAC,QAAgB;IAChC,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACtF,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC3B,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE;YAC7B,EAAE,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;QAC3B,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;AACP,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,QAAgB,EAAE,GAAW;IACtD,OAAO,IAAI,EAAE,CAAC;QACV,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,GAAG,QAAQ,OAAO,GAAG,KAAK,CAAC,CAAC;QAClD,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QAC5B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG;YAAE,OAAO,CAAC,CAAC;QACjC,OAAO,CAAC,GAAG,CAAC,yCAAyC,GAAG,GAAG,CAAC,CAAC;IACjE,CAAC;AACL,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bitkyc08/agent-sync",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Sync MCP, skills, and AGENTS.md across all AI coding agents (Claude, Codex, Copilot, Gemini, Antigravity, OpenCode)",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"agent-sync": "./dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "https://github.com/lidge-jun/agent-sync.git"
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc",
|
|
19
|
+
"dev": "tsx src/cli.ts",
|
|
20
|
+
"test": "vitest run",
|
|
21
|
+
"prepublishOnly": "npm run build"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"ai",
|
|
25
|
+
"agent",
|
|
26
|
+
"mcp",
|
|
27
|
+
"sync",
|
|
28
|
+
"claude",
|
|
29
|
+
"copilot",
|
|
30
|
+
"codex",
|
|
31
|
+
"gemini"
|
|
32
|
+
],
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=18"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"typescript": "^5.7",
|
|
39
|
+
"tsx": "^4.21",
|
|
40
|
+
"vitest": "^3.0",
|
|
41
|
+
"@types/node": "^22"
|
|
42
|
+
}
|
|
43
|
+
}
|