diff --git a/start.sh b/start.sh new file mode 100644 index 0000000..5e821e8 --- /dev/null +++ b/start.sh @@ -0,0 +1,152 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(dirname "$0")" +# ── OTA update ──────────────────────────────────────────────────────────────── +# Uses curl + Python stdlib tarfile — no git or unzip required. +# +# Flow: +# 1. Fetch latest GitHub Release tag via API (tiny JSON, 5 s timeout). +# 2. Compare against .poke_version (last installed version tag). Skip if +# already up to date or if the remote is unreachable. +# 3. Download the release tarball only when an update exists (30 s timeout). +# 4. Extract with Python tarfile, stripping the GitHub top-level prefix and +# skipping protected local files (.env, config.yml, .venv). +# 5. Persist new version tag to .poke_version and reinstall deps if +# requirements.txt changed. +if command -v curl &>/dev/null && command -v python3 &>/dev/null; then + _OTA_REPO="kacperkwapisz/poke-mail" + _VERSION_FILE=".poke_version" + echo "Checking for updates..." + # Step 1: fetch latest release tag and tarball URL (fail silently if offline) + _RELEASE_JSON=$(curl -sf --max-time 5 \ "https://api.github.com/repos/${_OTA_REPO}/releases/latest" \ 2>/dev/null || echo "") + _REMOTE_TAG="" + _TARBALL_URL="" + if [ -n "$_RELEASE_JSON" ]; then + _REMOTE_TAG=$(echo "$_RELEASE_JSON" | python3 -c \ "import json,sys; print(json.load(sys.stdin).get('tag_name',''))" \ 2>/dev/null || echo "") + _TARBALL_URL=$(echo "$_RELEASE_JSON" | python3 -c \ "import json,sys; print(json.load(sys.stdin).get('tarball_url',''))" \ 2>/dev/null || echo "") + fi + _LOCAL_TAG=$(cat "$_VERSION_FILE" 2>/dev/null || echo "") + if [ -z "$_REMOTE_TAG" ]; then + echo " ℹ Could not reach remote — continuing with local version." + echo "" + elif [ "$_REMOTE_TAG" = "$_LOCAL_TAG" ]; then + echo " ✓ Already up to date (${_LOCAL_TAG})" + echo "" + else + if [ -n "$_LOCAL_TAG" ]; then + echo " ↳ Update found (${_LOCAL_TAG} → ${_REMOTE_TAG}), downloading..." + else + echo " ↳ Update found (${_REMOTE_TAG}), downloading..." + fi + # Hash requirements.txt before extraction so we can detect changes + _REQS_BEFORE=$(python3 -c \ "import hashlib; print(hashlib.md5(open('requirements.txt','rb').read()).hexdigest())" \ 2>/dev/null || echo "") + _TMP_TAR=$(mktemp /tmp/poke-mail-update.XXXXXX.tar.gz) + if curl -sfL --max-time 30 \ "$_TARBALL_URL" \ -o "$_TMP_TAR" 2>/dev/null; then + # Extract with Python: strip GitHub's top-level dir, skip protected paths + python3 - <<'PYEOF' +import tarfile, sys +TMP_TAR = sys.argv[1] +PROTECTED = {'.env', 'config.yml', '.venv'} +with tarfile.open(TMP_TAR, 'r:gz') as tf: + members = tf.getmembers() + prefix = members[0].name.split('/')[0] + '/' + for m in members: + if not m.name.startswith(prefix): + continue + rel = m.name[len(prefix):] + if not rel: + continue + top = rel.split('/')[0] + if top in PROTECTED: + continue + m.name = rel + try: + tf.extract(m, path='.', set_attrs=False) + except Exception: + pass +PYEOF "$_TMP_TAR" + # Persist new version tag + echo "$_REMOTE_TAG" > "$_VERSION_FILE" + echo " ✓ Updated to ${_REMOTE_TAG}" + # Reinstall deps if requirements.txt changed + _REQS_AFTER=$(python3 -c \ "import hashlib; print(hashlib.md5(open('requirements.txt','rb').read()).hexdigest())" \ 2>/dev/null || echo "") + if [ -n "$_REQS_BEFORE" ] && [ "$_REQS_BEFORE" != "$_REQS_AFTER" ]; then + echo " ↳ requirements.txt changed — reinstalling dependencies..." + [ -d .venv ] && source .venv/bin/activate + pip install -q -r requirements.txt + echo " ✓ Dependencies updated" + fi + else + echo " ℹ Download failed — continuing with local version." + fi + rm -f "$_TMP_TAR" + echo "" + fi +fi +# ── One-time setup (skipped on subsequent runs) ─────────────────────────────── +# 1. Python virtualenv + dependencies +if [ ! -d .venv ]; then + echo "First run — setting up poke-mail..." + echo "" + echo "Creating Python virtualenv (.venv)..." + python3 -m venv .venv +fi +source .venv/bin/activate +if ! python3 -c "import fastmcp" &>/dev/null 2>&1; then + echo "Installing Python dependencies..." + pip install -q -r requirements.txt + echo " ✓ Dependencies installed" + echo "" +fi +# 2. config.yml — copy example if missing +if [ ! -f config.yml ]; then + echo "Copying config.example.yml → config.yml..." + cp config.example.yml config.yml + echo " ✓ config.yml created" + echo "" +fi +# 3. Poke API key — read from 'poke login' credentials, inject into config.yml +if grep -q 'your-api-key-here' config.yml 2>/dev/null; then + POKE_CREDENTIALS_FILE="${XDG_CONFIG_HOME:-$HOME/.config}/poke/credentials.json" + POKE_TOKEN="" + if [ -f "$POKE_CREDENTIALS_FILE" ]; then + POKE_TOKEN=$(python3 -c "import json,sys; print(json.load(open('$POKE_CREDENTIALS_FILE')).get('token',''))" 2>/dev/null || echo "") + fi + if [ -n "$POKE_TOKEN" ]; then + echo " ✓ Poke API key detected from 'poke login'" + # Generate MCP_API_KEY if not set + if ! grep -Eq '^[[:space:]]*MCP_API_KEY=' .env 2>/dev/null; then + RANDOM_KEY=$(python3 -c "import secrets, string; print(''.join(secrets.choice(string.ascii_letters + string.digits) for _ in range(48)))") + echo "MCP_API_KEY=$RANDOM_KEY" >> .env + echo " ✓ MCP_API_KEY generated and saved to .env" + echo "" + fi + export POKE_TUNNEL=1 + fi +fi +# ── Tunnel-mode enforcement ─────────────────────────────────────────────────── +if [ "${POKE_TUNNEL}" != "1" ]; then + : "${MCP_API_KEY:?MCP_API_KEY is not set — add it to .env or export it}" +else + if [ -z "${MCP_API_KEY:-}" ]; then + echo " ℹ MCP_API_KEY not set — server runs unauthenticated (safe: poke tunnel handles auth)." + fi + export POKE_TUNNEL +fi +# ── Start server + tunnel ───────────────────────────────────────────────────── +echo "Starting poke-mail server..." +python3 src/server.py & SERVER_PID=$! +trap "kill $SERVER_PID 2>/dev/null" EXIT +sleep 2 +echo "Starting tunnel to Poke..." +if command -v poke &>/dev/null; then + poke tunnel http://localhost:3000/mcp --name "poke-mail" +else + echo " ℹ 'poke' binary not found in PATH — using npx poke (requires Node.js)." + if ! command -v npx &>/dev/null; then + echo " ✗ Neither 'poke' nor 'npx' found. Install Node.js (nodejs.org) and run:" + echo " npm install -g poke OR npx poke tunnel ..." + exit 1 + fi + npx --yes poke tunnel http://localhost:3000/mcp --name "poke-mail" +fi