mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-03-30 13:43:26 +08:00
fix: codex sync merges AGENTS.md instead of replacing it (#715)
The sync script previously overwrote ~/.codex/AGENTS.md on every run, destroying any user-authored content. This adds marker-based merging (<!-- BEGIN ECC --> / <!-- END ECC -->) so only the ECC-managed section is replaced on subsequent runs, preserving user content outside the markers. Merge logic: - No file → create with markers - Both markers present (ordered, CRLF-safe) → replace only the ECC section - BEGIN without END (corrupted) → full replace (backup saved) - No markers at all → append ECC block (preserves existing content) Also fixes: - Symlink preservation: uses cat > instead of mv to write through symlinks - CRLF handling: strips \r in marker detection to handle Windows-edited files - Marker ordering: validates BEGIN appears before END, not just that both exist The legacy heading-match heuristic was intentionally removed per council review: any unmarked file is either user-authored (append is safe) or legacy ECC-generated (duplicates once, deduplicates on next run via markers). A timestamped backup is always saved before any mutation. Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Happy <yesreply@happy.engineering>
This commit is contained in:
@@ -3,7 +3,7 @@ set -euo pipefail
|
||||
|
||||
# Sync Everything Claude Code (ECC) assets into a local Codex CLI setup.
|
||||
# - Backs up ~/.codex config and AGENTS.md
|
||||
# - Replaces AGENTS.md with ECC AGENTS.md
|
||||
# - Merges ECC AGENTS.md into existing AGENTS.md (marker-based, preserves user content)
|
||||
# - Syncs Codex-ready skills from .agents/skills
|
||||
# - Generates prompt files from commands/*.md
|
||||
# - Generates Codex QA wrappers and optional language rule-pack prompts
|
||||
@@ -143,16 +143,68 @@ if [[ -f "$AGENTS_FILE" ]]; then
|
||||
run_or_echo "cp \"$AGENTS_FILE\" \"$BACKUP_DIR/AGENTS.md\""
|
||||
fi
|
||||
|
||||
log "Replacing global AGENTS.md with ECC AGENTS + Codex supplement"
|
||||
ECC_BEGIN_MARKER="<!-- BEGIN ECC -->"
|
||||
ECC_END_MARKER="<!-- END ECC -->"
|
||||
|
||||
compose_ecc_block() {
|
||||
printf '%s\n' "$ECC_BEGIN_MARKER"
|
||||
cat "$AGENTS_ROOT_SRC"
|
||||
printf '\n\n---\n\n'
|
||||
printf '# Codex Supplement (From ECC .codex/AGENTS.md)\n\n'
|
||||
cat "$AGENTS_CODEX_SUPP_SRC"
|
||||
printf '\n%s\n' "$ECC_END_MARKER"
|
||||
}
|
||||
|
||||
log "Merging ECC AGENTS into $AGENTS_FILE (preserving user content)"
|
||||
if [[ "$MODE" == "dry-run" ]]; then
|
||||
printf '[dry-run] compose %s from %s + %s\n' "$AGENTS_FILE" "$AGENTS_ROOT_SRC" "$AGENTS_CODEX_SUPP_SRC"
|
||||
printf '[dry-run] merge ECC block into %s from %s + %s\n' "$AGENTS_FILE" "$AGENTS_ROOT_SRC" "$AGENTS_CODEX_SUPP_SRC"
|
||||
else
|
||||
{
|
||||
cat "$AGENTS_ROOT_SRC"
|
||||
printf '\n\n---\n\n'
|
||||
printf '# Codex Supplement (From ECC .codex/AGENTS.md)\n\n'
|
||||
cat "$AGENTS_CODEX_SUPP_SRC"
|
||||
} > "$AGENTS_FILE"
|
||||
replace_ecc_section() {
|
||||
# Replace the ECC block between markers in $AGENTS_FILE with fresh content.
|
||||
# Uses awk to correctly handle all positions including line 1.
|
||||
local tmp
|
||||
tmp="$(mktemp)"
|
||||
local ecc_tmp
|
||||
ecc_tmp="$(mktemp)"
|
||||
compose_ecc_block > "$ecc_tmp"
|
||||
awk -v begin="$ECC_BEGIN_MARKER" -v end="$ECC_END_MARKER" -v ecc="$ecc_tmp" '
|
||||
{ gsub(/\r$/, "") }
|
||||
$0 == begin { skip = 1; while ((getline line < ecc) > 0) print line; close(ecc); next }
|
||||
$0 == end { skip = 0; next }
|
||||
!skip { print }
|
||||
' "$AGENTS_FILE" > "$tmp"
|
||||
# Write through the path (preserves symlinks) instead of mv
|
||||
cat "$tmp" > "$AGENTS_FILE"
|
||||
rm -f "$tmp" "$ecc_tmp"
|
||||
}
|
||||
|
||||
if [[ ! -f "$AGENTS_FILE" ]]; then
|
||||
# No existing file — create fresh with markers
|
||||
compose_ecc_block > "$AGENTS_FILE"
|
||||
elif awk -v b="$ECC_BEGIN_MARKER" -v e="$ECC_END_MARKER" '
|
||||
{ gsub(/\r$/, "") }
|
||||
$0 == b { found_b = NR } $0 == e { found_e = NR }
|
||||
END { exit !(found_b && found_e && found_b < found_e) }
|
||||
' "$AGENTS_FILE"; then
|
||||
# Existing file with matched, correctly ordered ECC markers — replace only the ECC section
|
||||
replace_ecc_section
|
||||
elif grep -qF "$ECC_BEGIN_MARKER" "$AGENTS_FILE"; then
|
||||
# BEGIN marker exists but END marker is missing (corrupted). Warn and
|
||||
# replace the file entirely to restore a valid state. Backup was saved.
|
||||
log "WARNING: found BEGIN marker but no END marker — replacing file (backup saved)"
|
||||
compose_ecc_block > "$AGENTS_FILE"
|
||||
else
|
||||
# Existing file without markers — append ECC block, preserve user content.
|
||||
# Note: legacy ECC-only files (from old '>' overwrite) will get a second copy
|
||||
# on this first run. This is intentional — the alternative (heading-match
|
||||
# heuristic) risks false-positive overwrites of user-authored files. The next
|
||||
# run deduplicates via markers, and a timestamped backup was saved above.
|
||||
log "No ECC markers found — appending managed block (backup saved)"
|
||||
{
|
||||
printf '\n\n'
|
||||
compose_ecc_block
|
||||
} >> "$AGENTS_FILE"
|
||||
fi
|
||||
fi
|
||||
|
||||
log "Syncing ECC Codex skills"
|
||||
|
||||
Reference in New Issue
Block a user