docs(framework): P4.1 — fix stale install.sh comments + cmp-equal early-exit
Non-blocking fast-follow from #590 dual-engine review: - install.sh: PRESERVE_PATHS "(never overwritten)" and the seed-block "never be overwritten once customized" comments contradicted P4's framework-owned overwrite — clarified both (PRESERVE protects from rsync --delete; reconcile re-applies framework-owned with backup-once). - reconcile (install.sh + file-adapter.ts): skip the copy when content already matches (cmp-equal early-exit) to avoid mtime churn. Parity preserved. install.sh fixtures 14/14 green; gate green; prettier clean. Refs #542, closes #592 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -19,7 +19,9 @@ SOURCE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|||||||
TARGET_DIR="${MOSAIC_HOME:-$HOME/.config/mosaic}"
|
TARGET_DIR="${MOSAIC_HOME:-$HOME/.config/mosaic}"
|
||||||
INSTALL_MODE="${MOSAIC_INSTALL_MODE:-prompt}"
|
INSTALL_MODE="${MOSAIC_INSTALL_MODE:-prompt}"
|
||||||
|
|
||||||
# Files/dirs preserved across upgrades (never overwritten).
|
# Files/dirs protected from rsync --delete during sync. NOTE: framework-owned
|
||||||
|
# entries (CONSTITUTION/AGENTS/STANDARDS) ARE re-applied afterward by
|
||||||
|
# reconcile_framework_files (overwrite + backup-once); the rest stay user-owned.
|
||||||
# User-created content in these paths survives rsync --delete.
|
# User-created content in these paths survives rsync --delete.
|
||||||
PRESERVE_PATHS=("CONSTITUTION.md" "AGENTS.md" "SOUL.md" "USER.md" "TOOLS.md" "STANDARDS.md" "memory" "sources" "credentials")
|
PRESERVE_PATHS=("CONSTITUTION.md" "AGENTS.md" "SOUL.md" "USER.md" "TOOLS.md" "STANDARDS.md" "memory" "sources" "credentials")
|
||||||
|
|
||||||
@@ -70,12 +72,14 @@ reconcile_framework_files() {
|
|||||||
[[ -d "$defaults" ]] || return 0
|
[[ -d "$defaults" ]] || return 0
|
||||||
for f in "${FRAMEWORK_OWNED[@]}"; do
|
for f in "${FRAMEWORK_OWNED[@]}"; do
|
||||||
[[ -f "$defaults/$f" ]] || continue
|
[[ -f "$defaults/$f" ]] || continue
|
||||||
if [[ -f "$TARGET_DIR/$f" ]] && ! cmp -s "$TARGET_DIR/$f" "$defaults/$f"; then
|
# Already current — skip to avoid mtime churn.
|
||||||
if [[ ! -f "$TARGET_DIR/${f}.pre-constitution.bak" ]]; then
|
if [[ -f "$TARGET_DIR/$f" ]] && cmp -s "$TARGET_DIR/$f" "$defaults/$f"; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [[ -f "$TARGET_DIR/$f" && ! -f "$TARGET_DIR/${f}.pre-constitution.bak" ]]; then
|
||||||
cp "$TARGET_DIR/$f" "$TARGET_DIR/${f}.pre-constitution.bak"
|
cp "$TARGET_DIR/$f" "$TARGET_DIR/${f}.pre-constitution.bak"
|
||||||
warn "$f is now framework-owned and was updated; your previous copy is saved as ${f}.pre-constitution.bak — re-apply intended changes as a .local overlay or policy/ file (see CONSTITUTION.md / constitution/LAYER-MODEL.md)."
|
warn "$f is now framework-owned and was updated; your previous copy is saved as ${f}.pre-constitution.bak — re-apply intended changes as a .local overlay or policy/ file (see CONSTITUTION.md / constitution/LAYER-MODEL.md)."
|
||||||
fi
|
fi
|
||||||
fi
|
|
||||||
cp "$defaults/$f" "$TARGET_DIR/$f"
|
cp "$defaults/$f" "$TARGET_DIR/$f"
|
||||||
done
|
done
|
||||||
for f in "${USER_SEEDED[@]}"; do
|
for f in "${USER_SEEDED[@]}"; do
|
||||||
@@ -281,9 +285,9 @@ sync_framework
|
|||||||
mkdir -p "$TARGET_DIR/memory"
|
mkdir -p "$TARGET_DIR/memory"
|
||||||
mkdir -p "$TARGET_DIR/credentials"
|
mkdir -p "$TARGET_DIR/credentials"
|
||||||
|
|
||||||
# Seed defaults — copy framework contract files from defaults/ to framework
|
# Reconcile contract files from defaults/ into the framework root: framework-owned
|
||||||
# root if not already present. These ship with sensible defaults but must
|
# files (CONSTITUTION/AGENTS/STANDARDS) are overwritten every upgrade (a divergent
|
||||||
# never be overwritten once the user has customized them.
|
# copy is backed up once); user-seeded files (TOOLS) are written on first install only.
|
||||||
#
|
#
|
||||||
# This list must match the framework-contract whitelist in
|
# This list must match the framework-contract whitelist in
|
||||||
# packages/mosaic/src/config/file-adapter.ts (FileConfigAdapter.syncFramework).
|
# packages/mosaic/src/config/file-adapter.ts (FileConfigAdapter.syncFramework).
|
||||||
|
|||||||
@@ -198,8 +198,10 @@ export class FileConfigAdapter implements ConfigService {
|
|||||||
const src = join(defaultsDir, entry);
|
const src = join(defaultsDir, entry);
|
||||||
const dest = join(this.mosaicHome, entry);
|
const dest = join(this.mosaicHome, entry);
|
||||||
if (!existsSync(src) || !statSync(src).isFile()) continue;
|
if (!existsSync(src) || !statSync(src).isFile()) continue;
|
||||||
|
// Already current — skip to avoid mtime churn.
|
||||||
|
if (existsSync(dest) && readFileSync(src).equals(readFileSync(dest))) continue;
|
||||||
const bak = `${dest}.pre-constitution.bak`;
|
const bak = `${dest}.pre-constitution.bak`;
|
||||||
if (existsSync(dest) && !readFileSync(src).equals(readFileSync(dest)) && !existsSync(bak)) {
|
if (existsSync(dest) && !existsSync(bak)) {
|
||||||
copyFileSync(dest, bak);
|
copyFileSync(dest, bak);
|
||||||
}
|
}
|
||||||
copyFileSync(src, dest);
|
copyFileSync(src, dest);
|
||||||
|
|||||||
Reference in New Issue
Block a user