Initial release: iai-mcp v0.1.0
Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: XNLLLLH <XNLLLLH@users.noreply.github.com>
This commit is contained in:
commit
f6b876fbe7
332 changed files with 97258 additions and 0 deletions
143
scripts/update.sh
Executable file
143
scripts/update.sh
Executable file
|
|
@ -0,0 +1,143 @@
|
|||
#!/usr/bin/env bash
|
||||
# scripts/update.sh — pull + rebuild + restart daemon for collaborators
|
||||
#
|
||||
# Usage (from repo root or anywhere inside the clone):
|
||||
# bash scripts/update.sh
|
||||
#
|
||||
# Idempotent. Aborts on a dirty working tree so local changes are never
|
||||
# clobbered. Re-runs safely — each step detects whether it is needed.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Resolve repo root no matter where the script is invoked from.
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
cd "${REPO_ROOT}"
|
||||
|
||||
step() { printf '\n\033[1;34m==> %s\033[0m\n' "$*"; }
|
||||
ok() { printf ' \033[0;32m✓\033[0m %s\n' "$*"; }
|
||||
warn() { printf ' \033[0;33m!\033[0m %s\n' "$*"; }
|
||||
die() { printf '\n\033[0;31m✗ %s\033[0m\n' "$*" >&2; exit 1; }
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 0. Preconditions
|
||||
# ---------------------------------------------------------------------------
|
||||
step "preflight"
|
||||
[ -d .git ] || die "not a git repository (run from an iai-mcp clone)"
|
||||
|
||||
# Require a clean working tree — never trample local edits.
|
||||
if [ -n "$(git status --porcelain)" ]; then
|
||||
git status --short
|
||||
die "working tree is dirty. commit or stash first, then re-run."
|
||||
fi
|
||||
ok "working tree clean"
|
||||
|
||||
VENV_PY="${REPO_ROOT}/.venv/bin/python"
|
||||
[ -x "${VENV_PY}" ] || die ".venv/bin/python not found — run 'python3 -m venv .venv && .venv/bin/pip install -e .' once, then rerun"
|
||||
ok "venv detected"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 1. git pull (fast-forward only — never merge surprises)
|
||||
# ---------------------------------------------------------------------------
|
||||
step "git pull --ff-only origin main"
|
||||
BEFORE="$(git rev-parse HEAD)"
|
||||
git fetch --quiet origin main
|
||||
git pull --ff-only --quiet origin main
|
||||
AFTER="$(git rev-parse HEAD)"
|
||||
if [ "${BEFORE}" = "${AFTER}" ]; then
|
||||
ok "already at $(git rev-parse --short HEAD) — no upstream commits"
|
||||
NOOP=1
|
||||
else
|
||||
ok "advanced $(git rev-parse --short "${BEFORE}") → $(git rev-parse --short "${AFTER}")"
|
||||
NOOP=0
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 2. Python package (editable reinstall — picks up deps or entry-point drift)
|
||||
# ---------------------------------------------------------------------------
|
||||
step "python package refresh (editable)"
|
||||
"${VENV_PY}" -m pip install --quiet -e . || die "pip install -e failed"
|
||||
ok "iai-mcp python package up to date"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 3. TypeScript MCP wrapper
|
||||
# ---------------------------------------------------------------------------
|
||||
step "TS wrapper build"
|
||||
if [ -d mcp-wrapper ]; then
|
||||
pushd mcp-wrapper >/dev/null
|
||||
if [ -f package-lock.json ]; then
|
||||
npm ci --silent --no-audit --no-fund
|
||||
else
|
||||
npm install --silent --no-audit --no-fund
|
||||
fi
|
||||
npm run build --silent
|
||||
popd >/dev/null
|
||||
ok "mcp-wrapper/dist rebuilt"
|
||||
else
|
||||
warn "mcp-wrapper/ missing — skipping"
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 4. Global CLI symlink (idempotent — ensures ~/.local/bin/iai-mcp exists)
|
||||
# ---------------------------------------------------------------------------
|
||||
step "global CLI symlink"
|
||||
LOCAL_BIN="${HOME}/.local/bin"
|
||||
LINK_PATH="${LOCAL_BIN}/iai-mcp"
|
||||
TARGET="${REPO_ROOT}/.venv/bin/iai-mcp"
|
||||
if [ -e "${LINK_PATH}" ] && [ ! -L "${LINK_PATH}" ]; then
|
||||
warn "${LINK_PATH} exists as a regular file — skipping symlink refresh"
|
||||
else
|
||||
mkdir -p "${LOCAL_BIN}"
|
||||
ln -sf "${TARGET}" "${LINK_PATH}"
|
||||
ok "${LINK_PATH} -> ${TARGET}"
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 5. Daemon (restart only if currently running; plist drift advisory)
|
||||
# ---------------------------------------------------------------------------
|
||||
step "daemon lifecycle"
|
||||
IAI_MCP="${REPO_ROOT}/.venv/bin/iai-mcp"
|
||||
|
||||
# Check template drift using a python one-liner (avoids shell grep, which is
|
||||
# hook-blocked in this repo's dev env).
|
||||
TEMPLATE_CHECK="$("${VENV_PY}" - <<'PY'
|
||||
import pathlib, sys
|
||||
home = pathlib.Path.home()
|
||||
installed = home / "Library/LaunchAgents/com.iai-mcp.daemon.plist"
|
||||
template = pathlib.Path.cwd() / "deploy/launchd/com.iai-mcp.daemon.plist"
|
||||
if not installed.exists() or not template.exists():
|
||||
print("none"); sys.exit(0)
|
||||
# Substitute USERNAME placeholder and compare env-var + args payload.
|
||||
rendered = template.read_text().replace("{USERNAME}", home.name)
|
||||
a_env = "IAI_MCP_STORE" in installed.read_text() and home.as_posix() + "/.iai-mcp" in installed.read_text()
|
||||
b_env = "IAI_MCP_STORE" in rendered and home.as_posix() + "/.iai-mcp" in rendered
|
||||
print("drift" if a_env != b_env else "same")
|
||||
PY
|
||||
)"
|
||||
|
||||
if [ "${TEMPLATE_CHECK}" = "drift" ]; then
|
||||
warn "launchd plist template drift detected"
|
||||
warn "run: '${IAI_MCP} daemon uninstall --yes && ${IAI_MCP} daemon install --yes' to pick up the new plist"
|
||||
fi
|
||||
|
||||
if "${IAI_MCP}" daemon status >/dev/null 2>&1; then
|
||||
# daemon status exits 0 only when running
|
||||
"${IAI_MCP}" daemon stop >/dev/null 2>&1 || true
|
||||
sleep 2
|
||||
"${IAI_MCP}" daemon start >/dev/null 2>&1 || warn "daemon start returned non-zero; check 'iai-mcp daemon status'"
|
||||
ok "daemon restarted on new code"
|
||||
else
|
||||
ok "daemon not running — nothing to restart"
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 5. Summary
|
||||
# ---------------------------------------------------------------------------
|
||||
step "done"
|
||||
if [ "${NOOP}" = "1" ]; then
|
||||
ok "no-op — everything already current"
|
||||
else
|
||||
ok "updated to $(git rev-parse --short HEAD)"
|
||||
echo
|
||||
git log --oneline "${BEFORE}..${AFTER}"
|
||||
fi
|
||||
Loading…
Add table
Add a link
Reference in a new issue