Skip to content

Commit d0d8cdb

Browse files
rtackclaude
andcommitted
feat: add sync-local.sh for local development sync
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 1324fc4 commit d0d8cdb

3 files changed

Lines changed: 227 additions & 0 deletions

File tree

.agents/scripts/sync-local.sh

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
# sync-local.sh - Sync updates from local dot-agents repository
5+
#
6+
# Similar to sync.sh but uses a local repository path instead of fetching from GitHub.
7+
# Useful for development and offline syncing.
8+
9+
SOURCE_REPO="${DOT_AGENTS_DEV_REPO:-}"
10+
METADATA_FILE=".agents/.dot-agents.json"
11+
12+
# Colors (only if terminal supports them)
13+
if [[ -t 1 ]]; then
14+
RED='\033[0;31m'
15+
GREEN='\033[0;32m'
16+
YELLOW='\033[0;33m'
17+
NC='\033[0m'
18+
else
19+
RED='' GREEN='' YELLOW='' NC=''
20+
fi
21+
22+
log_error() { echo -e "${RED}[ERROR]${NC} $1" >&2; }
23+
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
24+
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
25+
26+
do_version() {
27+
echo "dot-agents (local sync)"
28+
echo " Source repo: ${SOURCE_REPO}"
29+
30+
if [[ -f "$METADATA_FILE" ]]; then
31+
local ref installed_at last_synced_at synced_commit
32+
ref=$(sed -n 's/.*"ref"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$METADATA_FILE")
33+
installed_at=$(sed -n 's/.*"installedAt"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$METADATA_FILE")
34+
last_synced_at=$(sed -n 's/.*"lastSyncedAt"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$METADATA_FILE")
35+
synced_commit=$(sed -n 's/.*"syncedFromCommit"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$METADATA_FILE")
36+
37+
echo ""
38+
echo "Installation:"
39+
echo " Ref: ${ref:-unknown}"
40+
echo " Installed at: ${installed_at:-unknown}"
41+
if [[ -n "$last_synced_at" ]]; then
42+
echo " Last synced at: ${last_synced_at}"
43+
fi
44+
if [[ -n "$synced_commit" ]]; then
45+
echo " Synced from commit: ${synced_commit}"
46+
fi
47+
else
48+
echo ""
49+
echo "dot-agents not installed in this directory"
50+
fi
51+
}
52+
53+
usage() {
54+
cat <<EOF
55+
Usage: sync-local.sh [OPTIONS] [SOURCE_REPO]
56+
57+
Sync dot-agents from a local repository (for development).
58+
59+
Arguments:
60+
SOURCE_REPO Path to local dot-agents repository (or set \$DOT_AGENTS_DEV_REPO)
61+
62+
Options:
63+
--dry-run Show what would be changed without making changes
64+
--force Overwrite all files without prompting
65+
--yes Skip confirmation prompts
66+
--version Show version and installation info
67+
--help Show this help message
68+
69+
Examples:
70+
# Sync from default location
71+
.agents/scripts/sync-local.sh
72+
73+
# Sync from specific path
74+
.agents/scripts/sync-local.sh /path/to/dot-agents
75+
76+
# Preview changes
77+
.agents/scripts/sync-local.sh --dry-run
78+
79+
# Force update
80+
.agents/scripts/sync-local.sh --force
81+
EOF
82+
}
83+
84+
_main() {
85+
local dry_run=false yes=false
86+
local source_repo="${DOT_AGENTS_DEV_REPO:-}"
87+
88+
# Parse arguments
89+
while [[ $# -gt 0 ]]; do
90+
case "$1" in
91+
--help|-h)
92+
usage
93+
exit 0
94+
;;
95+
--version)
96+
do_version
97+
exit 0
98+
;;
99+
--dry-run)
100+
dry_run=true
101+
shift
102+
;;
103+
--force)
104+
yes=true
105+
shift
106+
;;
107+
--yes)
108+
yes=true
109+
shift
110+
;;
111+
-*)
112+
log_error "Unknown option: $1"
113+
usage
114+
exit 1
115+
;;
116+
*)
117+
source_repo="$1"
118+
shift
119+
;;
120+
esac
121+
done
122+
123+
# Require source repo
124+
if [[ -z "$source_repo" ]]; then
125+
log_error "Source repository path is required."
126+
log_error "Pass as argument or set \$DOT_AGENTS_DEV_REPO."
127+
echo ""
128+
usage
129+
exit 1
130+
fi
131+
132+
# Validate source repository
133+
if [[ ! -d "$source_repo/.agents" ]]; then
134+
log_error "Source .agents directory not found: $source_repo/.agents"
135+
exit 1
136+
fi
137+
138+
if [[ ! -d ".agents" ]]; then
139+
log_error "Target .agents directory not found in current directory"
140+
exit 1
141+
fi
142+
143+
log_info "Syncing from: $source_repo"
144+
echo ""
145+
146+
# Get source commit info (use subshell to avoid cd side effects)
147+
local latest_commit="" commit_date=""
148+
if latest_commit=$(cd "$source_repo" && git rev-parse HEAD 2>/dev/null); then
149+
commit_date=$(cd "$source_repo" && git log -1 --format='%aI' 2>/dev/null)
150+
log_info "Source commit: ${latest_commit:0:8} ($commit_date)"
151+
else
152+
log_warn "Source is not a git repository, continuing without commit info"
153+
latest_commit=""
154+
commit_date=""
155+
fi
156+
157+
if [[ "$dry_run" == true ]]; then
158+
log_info "Running in DRY-RUN mode"
159+
rsync -av --dry-run "$source_repo/.agents/" ".agents/"
160+
exit 0
161+
fi
162+
163+
# Confirm before syncing
164+
if [[ "$yes" != true ]]; then
165+
echo ""
166+
read -p "Proceed with sync? (y/N) " -n 1 -r
167+
echo
168+
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
169+
log_warn "Sync cancelled"
170+
exit 1
171+
fi
172+
fi
173+
174+
# Perform sync using rsync (without --delete to preserve local scripts)
175+
log_info "Syncing files..."
176+
rsync -av "$source_repo/.agents/" ".agents/"
177+
178+
# Update metadata (preserve existing installedAt)
179+
log_info "Updating metadata..."
180+
local now
181+
now=$(date -u +'%Y-%m-%dT%H:%M:%SZ')
182+
local installed_at="$now"
183+
if [[ -f "$METADATA_FILE" ]]; then
184+
local existing
185+
existing=$(sed -n 's/.*"installedAt"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$METADATA_FILE")
186+
if [[ -n "$existing" ]]; then
187+
installed_at="$existing"
188+
fi
189+
fi
190+
191+
local commit_fields=""
192+
if [[ -n "$latest_commit" ]]; then
193+
commit_fields=",
194+
\"syncedFromCommit\": \"$latest_commit\",
195+
\"commitDate\": \"$commit_date\""
196+
fi
197+
198+
cat > "$METADATA_FILE" << METADATA
199+
{
200+
"upstream": "https://github.com/colmarius/dot-agents",
201+
"ref": "main",
202+
"installedAt": "$installed_at",
203+
"lastSyncedAt": "$now"$commit_fields
204+
}
205+
METADATA
206+
207+
# Run post-sync to ensure Claude Code integration is complete
208+
if [[ -f ".agents/scripts/post-sync.sh" ]]; then
209+
log_info "Completing Claude Code integration..."
210+
bash .agents/scripts/post-sync.sh --quiet
211+
fi
212+
213+
echo ""
214+
log_info "✓ Sync complete!"
215+
if [[ -n "$latest_commit" ]]; then
216+
echo " Latest commit: $latest_commit"
217+
echo " Commit date: $commit_date"
218+
fi
219+
echo " Synced at: $now"
220+
}
221+
222+
# Only run if script is executed, not sourced
223+
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
224+
_main "$@"
225+
fi

AGENTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ dot-agents/
3232
│ │ └── REGISTRY.json # Machine-readable skill index (auto-generated)
3333
│ ├── scripts/
3434
│ │ ├── sync.sh # Sync from upstream GitHub
35+
│ │ ├── sync-local.sh # Sync from local repo (dev)
3536
│ │ ├── post-sync.sh # Post-sync Claude Code integration verification
3637
│ │ └── generate-registry.sh # Generate REGISTRY.json from SKILL.md frontmatter
3738
│ ├── plans/ # Implementation plans

scripts/lint.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ cd "$ROOT_DIR"
1313
SCRIPTS=(
1414
install.sh
1515
.agents/scripts/sync.sh
16+
.agents/scripts/sync-local.sh
1617
.agents/scripts/post-sync.sh
1718
.agents/scripts/generate-registry.sh
1819
scripts/check-registry.sh

0 commit comments

Comments
 (0)