@vikasagarwal101/skill-sync 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/install.sh ADDED
@@ -0,0 +1,516 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ # skill-sync installer
5
+ # Usage: ./install.sh [options]
6
+ # --with-rules <agents> Register rules (non-interactive). Agents: opencode,claude,codex,kilo,gemini,auggie,devin,all
7
+ # --no-rules Skip agent rule registration (CLI only)
8
+ # --uninstall Remove everything (prompts for rule removal)
9
+ # (no flags) Interactive: prompt for each detected agent
10
+
11
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
12
+ BIN_DIR="${SKILLSYNC_BIN_DIR:-$HOME/.local/bin}"
13
+ CONFIG_DIR="${SKILLSYNC_CONFIG_DIR:-$HOME/.config/skill-sync}"
14
+
15
+ # Agent paths
16
+ OPENCODE_CONFIG="$HOME/.config/opencode/opencode.json"
17
+ OPENCODE_RULES_DIR="$HOME/.config/opencode/rules"
18
+ CLAUDE_DIR="$HOME/.claude"
19
+ CLAUDE_RULES_DIR="$CLAUDE_DIR/rules"
20
+ CLAUDE_MD="$CLAUDE_DIR/CLAUDE.md"
21
+ CODEX_HOME="${CODEX_HOME:-$HOME/.codex}"
22
+ CODEX_AGENTS_MD="$CODEX_HOME/AGENTS.md"
23
+ KILO_CONFIG_DIR="$HOME/.config/kilo"
24
+ KILO_RULES_DIR="$KILO_CONFIG_DIR/rules"
25
+ KILO_CONFIG="$KILO_CONFIG_DIR/kilo.jsonc"
26
+ GEMINI_DIR="$HOME/.gemini"
27
+ GEMINI_RULES_DIR="$GEMINI_DIR/rules"
28
+ GEMINI_MD="$GEMINI_DIR/GEMINI.md"
29
+ AUGMENT_DIR="$HOME/.augment"
30
+ AUGMENT_RULES_DIR="$AUGMENT_DIR/rules"
31
+ DEVIN_DIR="$HOME/.devin"
32
+ DEVIN_AGENTS_MD="$DEVIN_DIR/AGENTS.md"
33
+ ANTIGRAVITY_DIR="$HOME/.gemini/antigravity"
34
+
35
+ # Codex AGENTS.md section markers
36
+ CODEX_SECTION_START="<!-- SKILL_SYNC_START -->"
37
+ CODEX_SECTION_END="<!-- SKILL_SYNC_END -->"
38
+ # Shared markers for codex + devin (same pattern)
39
+ SECTION_START="<!-- SKILL_SYNC_START -->"
40
+ SECTION_END="<!-- SKILL_SYNC_END -->"
41
+
42
+ # Defaults
43
+ UNINSTALL=false
44
+ RULES_MODE="prompt"
45
+ RULES_AGENTS=""
46
+
47
+ # Parse args
48
+ while [[ $# -gt 0 ]]; do
49
+ case "$1" in
50
+ --uninstall) UNINSTALL=true; shift ;;
51
+ --with-rules) RULES_MODE="with"; RULES_AGENTS="${2:-all}"; shift 2 ;;
52
+ --no-rules) RULES_MODE="without"; shift ;;
53
+ *) shift ;;
54
+ esac
55
+ done
56
+
57
+ info() { echo " $*"; }
58
+
59
+ prompt_yesno() {
60
+ local question="$1" default="${2:-y}"
61
+ local hint
62
+ [ "$default" = "y" ] && hint="[Y/n]" || hint="[y/N]"
63
+ printf "%s %s " "$question" "$hint" >&2
64
+ read -r answer </dev/tty 2>/dev/null || answer="$default"
65
+ answer="${answer:-$default}"
66
+ [[ "$answer" =~ ^[Yy] ]] && return 0 || return 1
67
+ }
68
+
69
+ # ── Agent detection ──
70
+
71
+ agent_exists() {
72
+ case "$1" in
73
+ opencode) [ -d "$HOME/.config/opencode" ] ;;
74
+ claude) [ -d "$CLAUDE_DIR" ] ;;
75
+ codex) [ -d "$CODEX_HOME" ] ;;
76
+ kilo) [ -d "$KILO_CONFIG_DIR" ] ;;
77
+ gemini) [ -d "$GEMINI_DIR" ] ;;
78
+ auggie) [ -d "$AUGMENT_DIR" ] ;;
79
+ devin) [ -d "$DEVIN_DIR" ] ;;
80
+ antigravity) [ -d "$ANTIGRAVITY_DIR" ] ;;
81
+ esac
82
+ }
83
+
84
+ list_agents() {
85
+ local found=()
86
+ for agent in opencode claude codex kilo gemini auggie devin antigravity; do
87
+ agent_exists "$agent" && found+=("$agent")
88
+ done
89
+ echo "${found[*]:-}"
90
+ }
91
+
92
+ agent_wants() {
93
+ # Check if agent is in the selected list
94
+ local agent="$1"
95
+ [[ "$RULES_AGENTS" == *"all"* ]] && return 0
96
+ [[ "$RULES_AGENTS" == *"$agent"* ]] && return 0
97
+ return 1
98
+ }
99
+
100
+ # ── OpenCode registration ──
101
+
102
+ register_opencode() {
103
+ _register_rule_file "$OPENCODE_RULES_DIR" "opencode"
104
+ if [ -f "$OPENCODE_CONFIG" ]; then
105
+ if ! grep -q 'skill-sync.md' "$OPENCODE_CONFIG"; then
106
+ sed -i '/]/i\ "~/.config/opencode/rules/skill-sync.md"' "$OPENCODE_CONFIG" 2>/dev/null || true
107
+ info "✅ Added to opencode.json instructions"
108
+ else
109
+ info " Already in opencode.json"
110
+ fi
111
+ fi
112
+ }
113
+
114
+ unregister_opencode() {
115
+ rm -f "$OPENCODE_RULES_DIR/skill-sync.md" && info "Removed opencode rule"
116
+ if [ -f "$OPENCODE_CONFIG" ]; then
117
+ local tmp; tmp=$(mktemp)
118
+ grep -v 'skill-sync.md' "$OPENCODE_CONFIG" > "$tmp" || true
119
+ cp "$tmp" "$OPENCODE_CONFIG" && rm "$tmp"
120
+ info "Removed from opencode.json"
121
+ fi
122
+ }
123
+
124
+ # ── Claude Code registration ──
125
+
126
+ register_claude() {
127
+ _register_rule_file "$CLAUDE_RULES_DIR" "claude"
128
+ if [ -f "$CLAUDE_MD" ]; then
129
+ if ! grep -q '@rules/skill-sync.md' "$CLAUDE_MD"; then
130
+ local last_import_line
131
+ last_import_line=$(grep -n '@rules/' "$CLAUDE_MD" | tail -1 | cut -d: -f1)
132
+ if [ -n "$last_import_line" ]; then
133
+ sed -i "${last_import_line}a\\@rules/skill-sync.md" "$CLAUDE_MD"
134
+ else
135
+ echo "" >> "$CLAUDE_MD"
136
+ echo "## Skill Management" >> "$CLAUDE_MD"
137
+ echo "@rules/skill-sync.md" >> "$CLAUDE_MD"
138
+ fi
139
+ info "✅ Added @rules/skill-sync.md to CLAUDE.md"
140
+ else
141
+ info " Already in CLAUDE.md"
142
+ fi
143
+ else
144
+ mkdir -p "$CLAUDE_DIR"
145
+ cat > "$CLAUDE_MD" << 'EOF'
146
+ # Claude Code Instructions
147
+
148
+ ## Skill Management
149
+
150
+ @rules/skill-sync.md
151
+ EOF
152
+ info "✅ Created CLAUDE.md with skill-sync rule"
153
+ fi
154
+ }
155
+
156
+ unregister_claude() {
157
+ rm -f "$CLAUDE_RULES_DIR/skill-sync.md" && info "Removed claude rule file"
158
+ if [ -f "$CLAUDE_MD" ]; then
159
+ local tmp; tmp=$(mktemp)
160
+ grep -v '@rules/skill-sync.md' "$CLAUDE_MD" > "$tmp" || true
161
+ cp "$tmp" "$CLAUDE_MD" && rm "$tmp"
162
+ info "Removed from CLAUDE.md"
163
+ fi
164
+ }
165
+
166
+ # ── Codex registration ──
167
+
168
+ register_codex() {
169
+ mkdir -p "$CODEX_HOME"
170
+ _register_section "$CODEX_AGENTS_MD" "codex (~/.codex/AGENTS.md)"
171
+ }
172
+
173
+ unregister_codex() {
174
+ _unregister_section "$CODEX_AGENTS_MD"
175
+ }
176
+
177
+ # ── Shared marker-section helper (codex, devin) ──
178
+
179
+ _register_section() {
180
+ local target_file="$1" target_name="$2"
181
+ mkdir -p "$(dirname "$target_file")"
182
+
183
+ local section
184
+ section=$(cat << EOF
185
+ $SECTION_START
186
+
187
+ ## Skill Management — \`skill-sync\`
188
+
189
+ **Use \`skill-sync\` for all skill deployment and syncing.** Do not \`cp -r\` skills between directories manually — \`skill-sync\` tracks what syncs where via a manifest and prevents drift.
190
+
191
+ The CLI is self-documenting — run \`skill-sync help\` for the full command reference.
192
+
193
+ **Quick reference:**
194
+ \`\`\`bash
195
+ skill-sync # sync all tracked skills
196
+ skill-sync add <name> # deploy skill to a target
197
+ skill-sync create <name> # scaffold new skill
198
+ skill-sync search <query> # find skills by keyword
199
+ skill-sync doctor # full health check
200
+ \`\`\`
201
+ $SECTION_END
202
+ EOF
203
+ )
204
+
205
+ if [ -f "$target_file" ] && grep -q "$SECTION_START" "$target_file"; then
206
+ local tmp; tmp=$(mktemp)
207
+ awk -v start="$SECTION_START" -v end="$SECTION_END" -v section="$section" '
208
+ $0 ~ start { print section; in_section=1; next }
209
+ in_section && $0 ~ end { in_section=0; next }
210
+ !in_section
211
+ ' "$target_file" > "$tmp"
212
+ cp "$tmp" "$target_file" && rm "$tmp"
213
+ info "✅ Updated $target_name section"
214
+ else
215
+ echo "" >> "$target_file"
216
+ echo "$section" >> "$target_file"
217
+ info "✅ Added section to $target_file"
218
+ fi
219
+ }
220
+
221
+ _unregister_section() {
222
+ local target_file="$1"
223
+ if [ -f "$target_file" ] && grep -q "$SECTION_START" "$target_file"; then
224
+ local tmp; tmp=$(mktemp)
225
+ awk -v start="$SECTION_START" -v end="$SECTION_END" '
226
+ $0 ~ start { skip=1; next }
227
+ skip && $0 ~ end { skip=0; next }
228
+ !skip
229
+ ' "$target_file" > "$tmp"
230
+ cp "$tmp" "$target_file" && rm "$tmp"
231
+ info "Removed section from $target_file"
232
+ fi
233
+ }
234
+
235
+ # ── Shared rule-file helper (opencode, claude, kilo, gemini, auggie) ──
236
+
237
+ _register_rule_file() {
238
+ local rules_dir="$1" agent_name="$2"
239
+ mkdir -p "$rules_dir"
240
+
241
+ if [ -f "$rules_dir/skill-sync.md" ]; then
242
+ if ! diff -q "$SCRIPT_DIR/rules/skill-sync.md" "$rules_dir/skill-sync.md" >/dev/null 2>&1; then
243
+ cp "$SCRIPT_DIR/rules/skill-sync.md" "$rules_dir/skill-sync.md"
244
+ info "✅ Updated $agent_name rule file"
245
+ else
246
+ info " Rule file already current"
247
+ fi
248
+ else
249
+ cp "$SCRIPT_DIR/rules/skill-sync.md" "$rules_dir/skill-sync.md"
250
+ info "✅ Installed $agent_name rule → $rules_dir/skill-sync.md"
251
+ fi
252
+ }
253
+
254
+ _unregister_rule_file() {
255
+ local rules_dir="$1" agent_name="$2"
256
+ rm -f "$rules_dir/skill-sync.md" && info "Removed $agent_name rule file"
257
+ }
258
+
259
+ # ── Kilo Code registration ──
260
+
261
+ register_kilo() {
262
+ _register_rule_file "$KILO_RULES_DIR" "kilo"
263
+
264
+ if [ ! -f "$KILO_CONFIG" ]; then
265
+ # Create minimal kilo.jsonc
266
+ mkdir -p "$KILO_CONFIG_DIR"
267
+ cat > "$KILO_CONFIG" << 'EOF'
268
+ {
269
+ "instructions": [
270
+ "~/.config/kilo/rules/skill-sync.md"
271
+ ]
272
+ }
273
+ EOF
274
+ info "✅ Created kilo.jsonc with skill-sync instruction"
275
+ elif grep -q 'skill-sync.md' "$KILO_CONFIG"; then
276
+ info " Already in kilo.jsonc"
277
+ elif grep -q '"instructions"' "$KILO_CONFIG"; then
278
+ # Add to existing instructions array (before its closing ])
279
+ local tmp; tmp=$(mktemp)
280
+ awk '
281
+ /^ "instructions"/ { in_instr=1 }
282
+ in_instr && /\]/ {
283
+ sub(/\]/, " \"~/.config/kilo/rules/skill-sync.md\"\n ]")
284
+ in_instr=0
285
+ }
286
+ { print }
287
+ ' "$KILO_CONFIG" > "$tmp"
288
+ cp "$tmp" "$KILO_CONFIG" && rm "$tmp"
289
+ info "✅ Added to kilo.jsonc instructions"
290
+ else
291
+ # No instructions key — add one after opening {
292
+ local tmp; tmp=$(mktemp)
293
+ awk 'NR==1{print; print " \"instructions\": ["; print " \"~/.config/kilo/rules/skill-sync.md\""; print " ],"; next} {print}' "$KILO_CONFIG" > "$tmp"
294
+ cp "$tmp" "$KILO_CONFIG" && rm "$tmp"
295
+ info "✅ Added instructions array to kilo.jsonc"
296
+ fi
297
+ }
298
+
299
+ unregister_kilo() {
300
+ _unregister_rule_file "$KILO_RULES_DIR" "kilo"
301
+ if [ -f "$KILO_CONFIG" ]; then
302
+ local tmp; tmp=$(mktemp)
303
+ grep -v 'skill-sync.md' "$KILO_CONFIG" > "$tmp" || true
304
+ cp "$tmp" "$KILO_CONFIG" && rm "$tmp"
305
+ info "Removed from kilo.jsonc"
306
+ fi
307
+ }
308
+
309
+ # ── Gemini CLI registration ──
310
+
311
+ register_gemini() {
312
+ _register_rule_file "$GEMINI_RULES_DIR" "gemini"
313
+ if [ -f "$GEMINI_MD" ]; then
314
+ if ! grep -q '@rules/skill-sync.md' "$GEMINI_MD"; then
315
+ echo "" >> "$GEMINI_MD"
316
+ echo "@rules/skill-sync.md" >> "$GEMINI_MD"
317
+ info "✅ Added @rules/skill-sync.md to GEMINI.md"
318
+ else
319
+ info " Already in GEMINI.md"
320
+ fi
321
+ else
322
+ mkdir -p "$GEMINI_DIR"
323
+ echo "@rules/skill-sync.md" > "$GEMINI_MD"
324
+ info "✅ Created GEMINI.md with skill-sync import"
325
+ fi
326
+ }
327
+
328
+ unregister_gemini() {
329
+ _unregister_rule_file "$GEMINI_RULES_DIR" "gemini"
330
+ if [ -f "$GEMINI_MD" ]; then
331
+ local tmp; tmp=$(mktemp)
332
+ grep -v '@rules/skill-sync.md' "$GEMINI_MD" > "$tmp" || true
333
+ cp "$tmp" "$GEMINI_MD" && rm "$tmp"
334
+ info "Removed from GEMINI.md"
335
+ fi
336
+ }
337
+
338
+ # ── Auggie (Augment Code) registration ──
339
+
340
+ register_auggie() {
341
+ _register_rule_file "$AUGMENT_RULES_DIR" "auggie"
342
+ info " (auto-discovered by Auggie — no config change needed)"
343
+ }
344
+
345
+ unregister_auggie() {
346
+ _unregister_rule_file "$AUGMENT_RULES_DIR" "auggie"
347
+ }
348
+
349
+ # ── Devin CLI registration ──
350
+
351
+ register_devin() {
352
+ _register_section "$DEVIN_AGENTS_MD" "devin"
353
+ }
354
+
355
+ unregister_devin() {
356
+ _unregister_section "$DEVIN_AGENTS_MD"
357
+ }
358
+
359
+ # ── Generic register/unregister dispatchers ──
360
+
361
+ do_register() {
362
+ local agent="$1"
363
+ case "$agent" in
364
+ opencode) register_opencode ;;
365
+ claude) register_claude ;;
366
+ codex) register_codex ;;
367
+ kilo) register_kilo ;;
368
+ gemini) register_gemini ;;
369
+ auggie) register_auggie ;;
370
+ devin) register_devin ;;
371
+ antigravity) info "⏭️ Antigravity reads AGENTS.md + scans ~/.agents/skills/ natively — no registration needed" ;;
372
+ esac
373
+ }
374
+
375
+ do_unregister() {
376
+ local agent="$1"
377
+ case "$agent" in
378
+ opencode) unregister_opencode ;;
379
+ claude) unregister_claude ;;
380
+ codex) unregister_codex ;;
381
+ kilo) unregister_kilo ;;
382
+ gemini) unregister_gemini ;;
383
+ auggie) unregister_auggie ;;
384
+ devin) unregister_devin ;;
385
+ antigravity) ;; # nothing to unregister
386
+ esac
387
+ }
388
+
389
+ # ── Uninstall ──
390
+
391
+ do_uninstall() {
392
+ echo "Uninstalling skill-sync..."
393
+ echo ""
394
+
395
+ rm -f "$BIN_DIR/skill-sync" && info "Removed CLI from $BIN_DIR/"
396
+ rm -rf "$CONFIG_DIR" && info "Removed config from $CONFIG_DIR/"
397
+
398
+ # Check each agent for existing registrations
399
+ echo ""
400
+ echo "Checking agent registrations..."
401
+ for agent in opencode claude codex kilo gemini auggie devin; do
402
+ if agent_exists "$agent"; then
403
+ local has_reg=false
404
+ case "$agent" in
405
+ opencode) [ -f "$OPENCODE_RULES_DIR/skill-sync.md" ] && has_reg=true ;;
406
+ claude) [ -f "$CLAUDE_RULES_DIR/skill-sync.md" ] && has_reg=true ;;
407
+ codex) grep -q "$SECTION_START" "$CODEX_AGENTS_MD" 2>/dev/null && has_reg=true ;;
408
+ kilo) [ -f "$KILO_RULES_DIR/skill-sync.md" ] && has_reg=true ;;
409
+ gemini) [ -f "$GEMINI_RULES_DIR/skill-sync.md" ] && has_reg=true ;;
410
+ auggie) [ -f "$AUGMENT_RULES_DIR/skill-sync.md" ] && has_reg=true ;;
411
+ devin) grep -q "$SECTION_START" "$DEVIN_AGENTS_MD" 2>/dev/null && has_reg=true ;;
412
+ esac
413
+
414
+ if $has_reg; then
415
+ if [ "$RULES_MODE" = "with" ] || { [ "$RULES_MODE" = "prompt" ] && prompt_yesno "Remove $agent registration?" "y"; }; then
416
+ do_unregister "$agent"
417
+ else
418
+ info "Kept $agent registration"
419
+ fi
420
+ fi
421
+ fi
422
+ done
423
+
424
+ echo ""
425
+ echo "Uninstalled. Skill directories are untouched."
426
+ exit 0
427
+ }
428
+
429
+ # ── Install ──
430
+
431
+ do_install() {
432
+ echo "Installing skill-sync..."
433
+ echo ""
434
+
435
+ # 1. CLI (always) — bundle lib modules into single file
436
+ mkdir -p "$BIN_DIR"
437
+ {
438
+ echo '#!/usr/bin/env bash'
439
+ echo 'set -euo pipefail'
440
+ echo ''
441
+ for _lib in core sync authoring inspect health targets; do
442
+ cat "$SCRIPT_DIR/lib/$_lib.sh" 2>/dev/null || true
443
+ echo ''
444
+ done
445
+ # Dispatch (everything from Main dispatch onward)
446
+ awk '/^# ── Main dispatch/{p=1} p' "$SCRIPT_DIR/skill-sync"
447
+ } > "$BIN_DIR/skill-sync"
448
+ chmod +x "$BIN_DIR/skill-sync"
449
+ info "✅ CLI installed → $BIN_DIR/skill-sync"
450
+
451
+ # 2. Config dir (always)
452
+ mkdir -p "$CONFIG_DIR"
453
+ info "✅ Config dir → $CONFIG_DIR/"
454
+
455
+ # 3. Agent rule registration
456
+ local found
457
+ found=$(list_agents)
458
+
459
+ if [ -z "$found" ]; then
460
+ echo ""
461
+ info "No AI agents detected — CLI installed without rule registration"
462
+ elif [ "$RULES_MODE" = "without" ]; then
463
+ echo ""
464
+ info "⏭️ Skipped agent rule registration (--no-rules)"
465
+ info " Register later with: ./install.sh --with-rules all"
466
+ else
467
+ echo ""
468
+ echo "Detected agents: ${found// /, }"
469
+ echo ""
470
+
471
+ for agent in $found; do
472
+ local should_register=false
473
+
474
+ if [ "$RULES_MODE" = "with" ]; then
475
+ agent_wants "$agent" && should_register=true
476
+ elif [ "$RULES_MODE" = "prompt" ]; then
477
+ local desc=""
478
+ case "$agent" in
479
+ opencode) desc="rule file + opencode.json" ;;
480
+ claude) desc="rule file + CLAUDE.md import" ;;
481
+ codex) desc="AGENTS.md section" ;;
482
+ kilo) desc="rule file + kilo.jsonc instructions" ;;
483
+ gemini) desc="rule file + GEMINI.md import" ;;
484
+ auggie) desc="rule file (auto-discovered)" ;;
485
+ devin) desc="AGENTS.md section" ;;
486
+ antigravity) desc="automatic — no registration needed" ;;
487
+ esac
488
+ if prompt_yesno " Register with $agent ($desc)?" "y"; then
489
+ should_register=true
490
+ fi
491
+ fi
492
+
493
+ if $should_register; then
494
+ do_register "$agent"
495
+ else
496
+ info " ⏭️ Skipped $agent"
497
+ fi
498
+ done
499
+ fi
500
+
501
+ echo ""
502
+ info "💡 Run 'skill-sync help' anytime for full command reference"
503
+
504
+ # 4. Generate manifest
505
+ echo ""
506
+ "$BIN_DIR/skill-sync" init 2>/dev/null || true
507
+
508
+ echo ""
509
+ echo "Installation complete!"
510
+ echo "Verify with: skill-sync doctor"
511
+ }
512
+
513
+ # ── Main ──
514
+
515
+ $UNINSTALL && do_uninstall
516
+ do_install