feat: integrate framework files into monorepo under packages/mosaic/framework/
Moves all Mosaic framework runtime files from the separate bootstrap repo into the monorepo as canonical source. The @mosaic/mosaic npm package now ships the complete framework — bin scripts, runtime configs, tools, and templates — enabling standalone installation via npm install. Structure: packages/mosaic/framework/ ├── bin/ 28 CLI scripts (mosaic, mosaic-doctor, mosaic-sync-skills, etc.) ├── runtime/ Runtime adapters (claude, codex, opencode, pi, mcp) ├── tools/ Shell tooling (git, prdy, orchestrator, quality, etc.) ├── templates/ Agent and repo templates ├── defaults/ Default identity files (AGENTS.md, STANDARDS.md, SOUL.md, etc.) ├── install.sh Legacy bash installer └── remote-install.sh One-liner remote installer Key files with Pi support and recent fixes: - bin/mosaic: launch_pi() with skills-local loop - bin/mosaic-doctor: --fix auto-wiring for all 4 harnesses - bin/mosaic-sync-skills: Pi as 4th link target, symlink-aware find - bin/mosaic-link-runtime-assets: Pi settings.json patching - bin/mosaic-migrate-local-skills: Pi skill roots, symlink find - runtime/pi/RUNTIME.md + mosaic-extension.ts Package ships 251 framework files in the npm tarball (278KB compressed).
This commit is contained in:
260
packages/mosaic/framework/install.sh
Executable file
260
packages/mosaic/framework/install.sh
Executable file
@@ -0,0 +1,260 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SOURCE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
TARGET_DIR="${MOSAIC_HOME:-$HOME/.config/mosaic}"
|
||||
INSTALL_MODE="${MOSAIC_INSTALL_MODE:-prompt}" # prompt|keep|overwrite
|
||||
PRESERVE_PATHS=("SOUL.md" "USER.md" "TOOLS.md" "memory")
|
||||
|
||||
# Colors (disabled if not a terminal)
|
||||
if [[ -t 1 ]]; then
|
||||
GREEN='\033[0;32m' YELLOW='\033[0;33m' RED='\033[0;31m'
|
||||
CYAN='\033[0;36m' BOLD='\033[1m' RESET='\033[0m'
|
||||
else
|
||||
GREEN='' YELLOW='' RED='' CYAN='' BOLD='' RESET=''
|
||||
fi
|
||||
|
||||
ok() { echo -e " ${GREEN}✓${RESET} $1"; }
|
||||
warn() { echo -e " ${YELLOW}⚠${RESET} $1" >&2; }
|
||||
fail() { echo -e " ${RED}✗${RESET} $1" >&2; }
|
||||
step() { echo -e "\n${BOLD}$1${RESET}"; }
|
||||
|
||||
is_existing_install() {
|
||||
[[ -d "$TARGET_DIR" ]] || return 1
|
||||
[[ -f "$TARGET_DIR/bin/mosaic" || -f "$TARGET_DIR/AGENTS.md" || -f "$TARGET_DIR/SOUL.md" ]]
|
||||
}
|
||||
|
||||
select_install_mode() {
|
||||
case "$INSTALL_MODE" in
|
||||
keep|overwrite|prompt) ;;
|
||||
*)
|
||||
fail "Invalid MOSAIC_INSTALL_MODE='$INSTALL_MODE'. Use: prompt, keep, overwrite."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
if ! is_existing_install; then
|
||||
INSTALL_MODE="overwrite"
|
||||
return
|
||||
fi
|
||||
|
||||
case "$INSTALL_MODE" in
|
||||
keep|overwrite)
|
||||
;;
|
||||
prompt)
|
||||
if [[ -t 0 ]]; then
|
||||
echo ""
|
||||
echo "Existing Mosaic install detected at: $TARGET_DIR"
|
||||
echo "Choose reinstall mode:"
|
||||
echo " 1) keep Keep local files (SOUL.md, USER.md, TOOLS.md, memory/) while updating framework"
|
||||
echo " 2) overwrite Replace everything in $TARGET_DIR"
|
||||
echo " 3) cancel Abort install"
|
||||
printf "Selection [1/2/3] (default: 1): "
|
||||
read -r selection
|
||||
|
||||
case "${selection:-1}" in
|
||||
1|k|K|keep|KEEP) INSTALL_MODE="keep" ;;
|
||||
2|o|O|overwrite|OVERWRITE) INSTALL_MODE="overwrite" ;;
|
||||
3|c|C|cancel|CANCEL|n|N|no|NO)
|
||||
fail "Install cancelled."
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
warn "Unrecognized selection '$selection'; defaulting to keep."
|
||||
INSTALL_MODE="keep"
|
||||
;;
|
||||
esac
|
||||
else
|
||||
warn "Existing install detected without interactive input; defaulting to keep local files."
|
||||
INSTALL_MODE="keep"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
sync_framework() {
|
||||
local source_real target_real
|
||||
source_real="$(cd "$SOURCE_DIR" && pwd -P)"
|
||||
target_real="$(mkdir -p "$TARGET_DIR" && cd "$TARGET_DIR" && pwd -P)"
|
||||
|
||||
if [[ "$source_real" == "$target_real" ]]; then
|
||||
warn "Source and target are the same directory; skipping file sync."
|
||||
return
|
||||
fi
|
||||
|
||||
if command -v rsync >/dev/null 2>&1; then
|
||||
local rsync_args=(-a --delete --exclude ".git")
|
||||
|
||||
if [[ "$INSTALL_MODE" == "keep" ]]; then
|
||||
local path
|
||||
for path in "${PRESERVE_PATHS[@]}"; do
|
||||
rsync_args+=(--exclude "$path")
|
||||
done
|
||||
fi
|
||||
|
||||
rsync "${rsync_args[@]}" "$SOURCE_DIR/" "$TARGET_DIR/"
|
||||
return
|
||||
fi
|
||||
|
||||
local preserve_tmp=""
|
||||
if [[ "$INSTALL_MODE" == "keep" ]]; then
|
||||
preserve_tmp="$(mktemp -d "${TMPDIR:-/tmp}/mosaic-preserve-XXXXXX")"
|
||||
local path
|
||||
for path in "${PRESERVE_PATHS[@]}"; do
|
||||
if [[ -e "$TARGET_DIR/$path" ]]; then
|
||||
mkdir -p "$preserve_tmp/$(dirname "$path")"
|
||||
cp -R "$TARGET_DIR/$path" "$preserve_tmp/$path"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
find "$TARGET_DIR" -mindepth 1 -maxdepth 1 ! -name ".git" -exec rm -rf {} +
|
||||
cp -R "$SOURCE_DIR"/. "$TARGET_DIR"/
|
||||
rm -rf "$TARGET_DIR/.git"
|
||||
|
||||
if [[ -n "$preserve_tmp" ]]; then
|
||||
local path
|
||||
for path in "${PRESERVE_PATHS[@]}"; do
|
||||
if [[ -e "$preserve_tmp/$path" ]]; then
|
||||
rm -rf "$TARGET_DIR/$path"
|
||||
mkdir -p "$TARGET_DIR/$(dirname "$path")"
|
||||
cp -R "$preserve_tmp/$path" "$TARGET_DIR/$path"
|
||||
fi
|
||||
done
|
||||
rm -rf "$preserve_tmp"
|
||||
fi
|
||||
}
|
||||
|
||||
step "Installing Mosaic framework"
|
||||
|
||||
mkdir -p "$TARGET_DIR"
|
||||
select_install_mode
|
||||
|
||||
if [[ "$INSTALL_MODE" == "keep" ]]; then
|
||||
ok "Install mode: keep local SOUL.md/USER.md/TOOLS.md/memory while updating framework"
|
||||
else
|
||||
ok "Install mode: overwrite existing files"
|
||||
fi
|
||||
|
||||
sync_framework
|
||||
|
||||
# Ensure memory directory exists (preserved across upgrades, may not exist on fresh install)
|
||||
mkdir -p "$TARGET_DIR/memory"
|
||||
|
||||
chmod +x "$TARGET_DIR"/bin/*
|
||||
chmod +x "$TARGET_DIR"/install.sh
|
||||
|
||||
# Ensure tool scripts are executable
|
||||
find "$TARGET_DIR/tools" -name "*.sh" -exec chmod +x {} + 2>/dev/null || true
|
||||
|
||||
# Create backward-compat symlink: rails/ → tools/
|
||||
if [[ -d "$TARGET_DIR/tools" ]]; then
|
||||
if [[ -d "$TARGET_DIR/rails" ]] && [[ ! -L "$TARGET_DIR/rails" ]]; then
|
||||
rm -rf "$TARGET_DIR/rails"
|
||||
fi
|
||||
ln -sfn "tools" "$TARGET_DIR/rails"
|
||||
fi
|
||||
|
||||
ok "Framework installed to $TARGET_DIR"
|
||||
|
||||
step "Post-install tasks"
|
||||
|
||||
if "$TARGET_DIR/bin/mosaic-link-runtime-assets" >/dev/null 2>&1; then
|
||||
ok "Runtime assets linked"
|
||||
else
|
||||
warn "Runtime asset linking failed (non-fatal)"
|
||||
fi
|
||||
|
||||
if "$TARGET_DIR/bin/mosaic-ensure-sequential-thinking" >/dev/null 2>&1; then
|
||||
ok "sequential-thinking MCP configured"
|
||||
else
|
||||
if [[ "${MOSAIC_ALLOW_MISSING_SEQUENTIAL_THINKING:-0}" == "1" ]]; then
|
||||
warn "sequential-thinking MCP setup failed but bypassed (MOSAIC_ALLOW_MISSING_SEQUENTIAL_THINKING=1)"
|
||||
else
|
||||
fail "sequential-thinking MCP setup failed (hard requirement)."
|
||||
fail "Set MOSAIC_ALLOW_MISSING_SEQUENTIAL_THINKING=1 only for temporary bypass scenarios."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if "$TARGET_DIR/bin/mosaic-ensure-excalidraw" >/dev/null 2>&1; then
|
||||
ok "excalidraw MCP configured"
|
||||
else
|
||||
warn "excalidraw MCP setup failed (non-fatal) — run 'mosaic-ensure-excalidraw' to retry"
|
||||
fi
|
||||
|
||||
if [[ "${MOSAIC_SKIP_SKILLS_SYNC:-0}" == "1" ]]; then
|
||||
ok "Skills sync skipped (MOSAIC_SKIP_SKILLS_SYNC=1)"
|
||||
else
|
||||
if "$TARGET_DIR/bin/mosaic-sync-skills" >/dev/null 2>&1; then
|
||||
ok "Skills synced"
|
||||
else
|
||||
warn "Skills sync failed (non-fatal)"
|
||||
fi
|
||||
fi
|
||||
|
||||
if "$TARGET_DIR/bin/mosaic-migrate-local-skills" --apply >/dev/null 2>&1; then
|
||||
ok "Local skills migrated"
|
||||
else
|
||||
warn "Local skill migration failed (non-fatal)"
|
||||
fi
|
||||
|
||||
if "$TARGET_DIR/bin/mosaic-doctor" >/dev/null 2>&1; then
|
||||
ok "Health audit passed"
|
||||
else
|
||||
warn "Health audit reported issues — run 'mosaic doctor' for details"
|
||||
fi
|
||||
|
||||
step "PATH configuration"
|
||||
|
||||
PATH_LINE="export PATH=\"$TARGET_DIR/bin:\$PATH\""
|
||||
|
||||
# Find the right shell profile
|
||||
if [[ -n "${ZSH_VERSION:-}" ]] || [[ "$(basename "${SHELL:-}")" == "zsh" ]]; then
|
||||
SHELL_PROFILE="$HOME/.zshrc"
|
||||
elif [[ -f "$HOME/.bashrc" ]]; then
|
||||
SHELL_PROFILE="$HOME/.bashrc"
|
||||
elif [[ -f "$HOME/.profile" ]]; then
|
||||
SHELL_PROFILE="$HOME/.profile"
|
||||
else
|
||||
SHELL_PROFILE="$HOME/.profile"
|
||||
fi
|
||||
|
||||
PATH_CHANGED=false
|
||||
if grep -qF "$TARGET_DIR/bin" "$SHELL_PROFILE" 2>/dev/null; then
|
||||
ok "Already in PATH via $SHELL_PROFILE"
|
||||
else
|
||||
{
|
||||
echo ""
|
||||
echo "# Mosaic agent framework"
|
||||
echo "$PATH_LINE"
|
||||
} >> "$SHELL_PROFILE"
|
||||
ok "Added to PATH in $SHELL_PROFILE"
|
||||
PATH_CHANGED=true
|
||||
fi
|
||||
|
||||
# ── Summary ──────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo -e "${GREEN}${BOLD} Mosaic installed successfully.${RESET}"
|
||||
echo ""
|
||||
|
||||
# Collect next steps
|
||||
NEXT_STEPS=()
|
||||
|
||||
if [[ "$PATH_CHANGED" == "true" ]]; then
|
||||
NEXT_STEPS+=("Run ${CYAN}source $SHELL_PROFILE${RESET} or log out and back in to activate PATH.")
|
||||
fi
|
||||
|
||||
if [[ ! -f "$TARGET_DIR/SOUL.md" ]]; then
|
||||
NEXT_STEPS+=("Run ${CYAN}mosaic init${RESET} to set up your agent identity (SOUL.md), user profile (USER.md), and tool config (TOOLS.md).")
|
||||
elif grep -q "not configured" "$TARGET_DIR/USER.md" 2>/dev/null; then
|
||||
NEXT_STEPS+=("Run ${CYAN}mosaic init${RESET} to personalize your user profile (USER.md) and tool config (TOOLS.md).")
|
||||
fi
|
||||
|
||||
if [[ ${#NEXT_STEPS[@]} -gt 0 ]]; then
|
||||
echo -e " ${BOLD}Next steps:${RESET}"
|
||||
for i in "${!NEXT_STEPS[@]}"; do
|
||||
echo -e " $((i+1)). ${NEXT_STEPS[$i]}"
|
||||
done
|
||||
echo ""
|
||||
fi
|
||||
Reference in New Issue
Block a user