From 8b3940990184d8855bcef4d4bfe73fc97697e539 Mon Sep 17 00:00:00 2001 From: Alan Kahn Date: Thu, 26 Feb 2026 11:15:39 -0500 Subject: [PATCH] feat(iknowyou): add SSH tunnel script, Synap space header, and hydration fix - Add tunnel.sh for SSH tunneling to vLLM server (port 8000 is firewalled, tunnel required for local dev) - Add dev:tunnel script to package.json for running dev with tunnel - Add SYNAP_SPACE env var support to synap.ts, sends X-Memory-Space-Id header when set - Fix SSR hydration mismatch in person-switcher by deferring personId render until client mount Co-Authored-By: Claude Opus 4.6 --- .../components/sidebar/person-switcher.tsx | 2 +- applications/iknowyou/lib/synap.ts | 2 ++ applications/iknowyou/package.json | 1 + applications/iknowyou/tunnel.sh | 30 +++++++++++++++++++ 4 files changed, 34 insertions(+), 1 deletion(-) create mode 100755 applications/iknowyou/tunnel.sh diff --git a/applications/iknowyou/components/sidebar/person-switcher.tsx b/applications/iknowyou/components/sidebar/person-switcher.tsx index d8347c1..1c423b5 100644 --- a/applications/iknowyou/components/sidebar/person-switcher.tsx +++ b/applications/iknowyou/components/sidebar/person-switcher.tsx @@ -6,10 +6,10 @@ import { useChatStore } from "@/lib/store"; export function PersonSwitcher() { const personId = useChatStore((s) => s.personId); const switchPerson = useChatStore((s) => s.switchPerson); + const [mounted, setMounted] = useState(false); // Defer personId render to avoid SSR/client hydration mismatch // (server generates a fresh UUID, client rehydrates from localStorage) - const [mounted, setMounted] = useState(false); useEffect(() => setMounted(true), []); const short = mounted ? personId.slice(0, 8) : "\u00A0"; diff --git a/applications/iknowyou/lib/synap.ts b/applications/iknowyou/lib/synap.ts index ff92787..60a5f25 100644 --- a/applications/iknowyou/lib/synap.ts +++ b/applications/iknowyou/lib/synap.ts @@ -1,6 +1,7 @@ const SYNAP_URL = process.env.SYNAP_URL ?? "https://api.synap.orchard9.ai"; const SYNAP_API_KEY = process.env.SYNAP_API_KEY ?? ""; +const SYNAP_SPACE = process.env.SYNAP_SPACE ?? ""; // --- Response types --- @@ -68,6 +69,7 @@ async function request( headers: { "Content-Type": "application/json", Authorization: `Bearer ${SYNAP_API_KEY}`, + ...(SYNAP_SPACE ? { "X-Memory-Space-Id": SYNAP_SPACE } : {}), ...init?.headers, }, }); diff --git a/applications/iknowyou/package.json b/applications/iknowyou/package.json index 08bc7aa..484736d 100644 --- a/applications/iknowyou/package.json +++ b/applications/iknowyou/package.json @@ -6,6 +6,7 @@ "dev": "next dev -p 59521", "dev:engine": "cargo run -p iknowyou-engine --bin server --features synap-aux", "dev:all": "sh -c 'npm run dev:engine & npm run dev'", + "dev:tunnel": "./tunnel.sh && next dev -p 59521", "build": "next build", "start": "next start -p 59521", "lint": "next lint" diff --git a/applications/iknowyou/tunnel.sh b/applications/iknowyou/tunnel.sh new file mode 100755 index 0000000..65c488a --- /dev/null +++ b/applications/iknowyou/tunnel.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# Ensure SSH tunnel to msd5685 vLLM (Qwen3-8B) is running on localhost:8000 +# Port 8000 is firewalled on the box — tunnel is required. + +HOST="msd5685.mjhst.com" +LOCAL_PORT=8000 +REMOTE_PORT=8000 +SSH_KEY="$HOME/.ssh/id_rsa" +SSH_USER="ubuntu" + +# Check if tunnel is already up +if lsof -i ":$LOCAL_PORT" -sTCP:LISTEN &>/dev/null; then + echo "vLLM tunnel already active on localhost:$LOCAL_PORT" +else + echo "Starting SSH tunnel to $HOST..." + ssh -f -N -L "$LOCAL_PORT:localhost:$REMOTE_PORT" \ + -i "$SSH_KEY" \ + -o StrictHostKeyChecking=no \ + -o UserKnownHostsFile=/dev/null \ + -o ServerAliveInterval=60 \ + -o ServerAliveCountMax=3 \ + "$SSH_USER@$HOST" + + if lsof -i ":$LOCAL_PORT" -sTCP:LISTEN &>/dev/null; then + echo "vLLM tunnel active → localhost:$LOCAL_PORT" + else + echo "Failed to start tunnel" >&2 + exit 1 + fi +fi