fix: make mosaic init idempotent — detect existing config files
- mosaic-init bash script: detect existing SOUL.md/USER.md/TOOLS.md and prompt user to keep, import (re-use values as defaults), or overwrite. Non-interactive mode exits cleanly unless --force is passed. Overwrite creates timestamped backups before replacing files. - launch.ts checkSoul(): prefer 'mosaic wizard' over legacy bash script when SOUL.md is missing, with fallback to mosaic-init. - detect-install.ts: pre-populate wizard state with existing values when user chooses 'reconfigure', so they see current settings as defaults. - soul-setup.ts: show existing agent name and communication style as defaults during reconfiguration. - Added tests for reconfigure pre-population and reset non-population.
This commit is contained in:
@@ -60,12 +60,14 @@ Options:
|
||||
--timezone <tz> Your timezone (e.g., "America/Chicago")
|
||||
--non-interactive Fail if any required value is missing (no prompts)
|
||||
--soul-only Only generate SOUL.md
|
||||
--force Overwrite existing files without prompting
|
||||
-h, --help Show help
|
||||
USAGE
|
||||
}
|
||||
|
||||
NON_INTERACTIVE=0
|
||||
SOUL_ONLY=0
|
||||
FORCE=0
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
@@ -79,6 +81,7 @@ while [[ $# -gt 0 ]]; do
|
||||
--timezone) TIMEZONE="$2"; shift 2 ;;
|
||||
--non-interactive) NON_INTERACTIVE=1; shift ;;
|
||||
--soul-only) SOUL_ONLY=1; shift ;;
|
||||
--force) FORCE=1; shift ;;
|
||||
-h|--help) usage; exit 0 ;;
|
||||
*) echo "Unknown argument: $1" >&2; usage >&2; exit 1 ;;
|
||||
esac
|
||||
@@ -139,6 +142,134 @@ prompt_multiline() {
|
||||
eval "$var_name=\"$value\""
|
||||
}
|
||||
|
||||
# ── Existing file detection ────────────────────────────────────
|
||||
|
||||
detect_existing_config() {
|
||||
local found=0
|
||||
local existing_files=()
|
||||
|
||||
[[ -f "$SOUL_OUTPUT" ]] && { found=1; existing_files+=("SOUL.md"); }
|
||||
[[ -f "$USER_OUTPUT" ]] && { found=1; existing_files+=("USER.md"); }
|
||||
[[ -f "$TOOLS_OUTPUT" ]] && { found=1; existing_files+=("TOOLS.md"); }
|
||||
|
||||
if [[ $found -eq 0 || $FORCE -eq 1 ]]; then
|
||||
return 0 # No existing files or --force: proceed with fresh install
|
||||
fi
|
||||
|
||||
echo "[mosaic-init] Existing configuration detected:"
|
||||
for f in "${existing_files[@]}"; do
|
||||
echo " ✓ $f"
|
||||
done
|
||||
|
||||
# Show current agent name if SOUL.md exists
|
||||
if [[ -f "$SOUL_OUTPUT" ]]; then
|
||||
local current_name
|
||||
current_name=$(grep -oP 'You are \*\*\K[^*]+' "$SOUL_OUTPUT" 2>/dev/null || true)
|
||||
if [[ -n "$current_name" ]]; then
|
||||
echo " Agent: $current_name"
|
||||
fi
|
||||
fi
|
||||
echo ""
|
||||
|
||||
if [[ $NON_INTERACTIVE -eq 1 ]]; then
|
||||
echo "[mosaic-init] Existing config found. Use --force to overwrite in non-interactive mode."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "What would you like to do?"
|
||||
echo " 1) keep — Keep existing files, skip init (default)"
|
||||
echo " 2) import — Import values from existing files as defaults, then regenerate"
|
||||
echo " 3) overwrite — Start fresh, overwrite all files"
|
||||
printf "Choose [1/2/3]: "
|
||||
read -r choice
|
||||
|
||||
case "${choice:-1}" in
|
||||
1|keep)
|
||||
echo "[mosaic-init] Keeping existing configuration."
|
||||
# Still push to runtime adapters in case framework was updated
|
||||
if [[ -x "$MOSAIC_HOME/tools/_scripts/mosaic-link-runtime-assets" ]]; then
|
||||
echo "[mosaic-init] Updating runtime adapters..."
|
||||
"$MOSAIC_HOME/tools/_scripts/mosaic-link-runtime-assets"
|
||||
fi
|
||||
echo "[mosaic-init] Done. Launch with: mosaic claude"
|
||||
exit 0
|
||||
;;
|
||||
2|import)
|
||||
echo "[mosaic-init] Importing values from existing files as defaults..."
|
||||
import_existing_values
|
||||
;;
|
||||
3|overwrite)
|
||||
echo "[mosaic-init] Starting fresh install..."
|
||||
# Back up existing files
|
||||
local ts
|
||||
ts=$(date +%Y%m%d%H%M%S)
|
||||
for f in "${existing_files[@]}"; do
|
||||
local src="$MOSAIC_HOME/$f"
|
||||
if [[ -f "$src" ]]; then
|
||||
cp "$src" "${src}.bak.${ts}"
|
||||
echo " Backed up $f → ${f}.bak.${ts}"
|
||||
fi
|
||||
done
|
||||
;;
|
||||
*)
|
||||
echo "[mosaic-init] Invalid choice. Keeping existing configuration."
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
import_existing_values() {
|
||||
# Import SOUL.md values
|
||||
if [[ -f "$SOUL_OUTPUT" ]]; then
|
||||
local content
|
||||
content=$(cat "$SOUL_OUTPUT")
|
||||
|
||||
if [[ -z "$AGENT_NAME" ]]; then
|
||||
AGENT_NAME=$(echo "$content" | grep -oP 'You are \*\*\K[^*]+' 2>/dev/null || true)
|
||||
fi
|
||||
if [[ -z "$ROLE_DESCRIPTION" ]]; then
|
||||
ROLE_DESCRIPTION=$(echo "$content" | grep -oP 'Role identity: \K.+' 2>/dev/null || true)
|
||||
fi
|
||||
if [[ -z "$STYLE" ]]; then
|
||||
if echo "$content" | grep -q 'Be direct, concise'; then
|
||||
STYLE="direct"
|
||||
elif echo "$content" | grep -q 'Be warm and conversational'; then
|
||||
STYLE="friendly"
|
||||
elif echo "$content" | grep -q 'Use professional, structured'; then
|
||||
STYLE="formal"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Import USER.md values
|
||||
if [[ -f "$USER_OUTPUT" ]]; then
|
||||
local content
|
||||
content=$(cat "$USER_OUTPUT")
|
||||
|
||||
if [[ -z "$USER_NAME" ]]; then
|
||||
USER_NAME=$(echo "$content" | grep -oP '\*\*Name:\*\* \K.+' 2>/dev/null || true)
|
||||
fi
|
||||
if [[ -z "$PRONOUNS" ]]; then
|
||||
PRONOUNS=$(echo "$content" | grep -oP '\*\*Pronouns:\*\* \K.+' 2>/dev/null || true)
|
||||
fi
|
||||
if [[ -z "$TIMEZONE" ]]; then
|
||||
TIMEZONE=$(echo "$content" | grep -oP '\*\*Timezone:\*\* \K.+' 2>/dev/null || true)
|
||||
fi
|
||||
fi
|
||||
|
||||
# Import TOOLS.md values
|
||||
if [[ -f "$TOOLS_OUTPUT" ]]; then
|
||||
local content
|
||||
content=$(cat "$TOOLS_OUTPUT")
|
||||
|
||||
if [[ -z "$CREDENTIALS_LOCATION" ]]; then
|
||||
CREDENTIALS_LOCATION=$(echo "$content" | grep -oP '\*\*Location:\*\* \K.+' 2>/dev/null || true)
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
detect_existing_config
|
||||
|
||||
# ── SOUL.md Generation ────────────────────────────────────────
|
||||
echo "[mosaic-init] Generating SOUL.md — agent identity contract"
|
||||
echo ""
|
||||
|
||||
Reference in New Issue
Block a user