diff --git a/aiui/packages/app/server/dev-auth.ts b/aiui/packages/app/server/dev-auth.ts index f51699df..f9c937db 100644 --- a/aiui/packages/app/server/dev-auth.ts +++ b/aiui/packages/app/server/dev-auth.ts @@ -46,13 +46,14 @@ interface RateBucket { const rateBuckets = new Map() -// Clean up stale buckets every 5 minutes +// Vite imports this module during builds too; cleanup must not keep the +// process alive once compilation has finished. setInterval(() => { const now = Date.now() for (const [key, bucket] of rateBuckets) { if (now > bucket.resetAt) rateBuckets.delete(key) } -}, 5 * 60_000) +}, 5 * 60_000).unref() function getClientIp(req: IncomingMessage): string { return req.socket.remoteAddress ?? 'unknown' diff --git a/aiui/packages/app/src/main.ts b/aiui/packages/app/src/main.ts index c9af5b01..bd72088b 100644 --- a/aiui/packages/app/src/main.ts +++ b/aiui/packages/app/src/main.ts @@ -33,6 +33,7 @@ const PWA_CACHE_VERSION = '2' // Only embedded when explicitly requested via ?embedded param const _embeddedFlag = new URLSearchParams(window.location.search).has('embedded') ;(window as unknown as Record).__AIUI_EMBEDDED__ = _embeddedFlag +document.documentElement.classList.toggle('aiui-embedded', _embeddedFlag) const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), diff --git a/aiui/packages/app/src/styles/main.css b/aiui/packages/app/src/styles/main.css index 9a81a685..e6ac3ad8 100644 --- a/aiui/packages/app/src/styles/main.css +++ b/aiui/packages/app/src/styles/main.css @@ -57,12 +57,8 @@ body { width: 100%; height: 100%; overflow: hidden; - /* Every page paints its own explicit background (bg-[#0a0a0a] / bg-[#faf9f6]) - EXCEPT the embedded Chat page, which intentionally goes transparent so - Archy's own dark chrome can show behind it (Chat.vue's iframe host). With - no background-color here, "transparent" fell through to the browser's - default white canvas instead. Match the theme's own dark/light default so - nothing above this ever needs to guess. */ + /* Standalone canvas fallback. Embedded mode overrides this below so + Archy's wallpaper remains visible through the iframe. */ background-color: #0a0a0a; } @@ -70,6 +66,13 @@ html.light body { background-color: #faf9f6; } +/* The host owns the wallpaper when AIUI is embedded. The document canvas + must be transparent too, otherwise it hides the host behind ChatPage. */ +html.aiui-embedded, +html.aiui-embedded body { + background: transparent; +} + /* ===== DARK MODE GLASSMORPHISM — from Archy ===== */ @layer components { diff --git a/scripts/create-release-manifest.sh b/scripts/create-release-manifest.sh index e4865310..5a765956 100755 --- a/scripts/create-release-manifest.sh +++ b/scripts/create-release-manifest.sh @@ -78,15 +78,17 @@ if [ -z "$FRONTEND_ARCHIVE" ]; then STAGING_DIR=$(mktemp -d -t archipelago-frontend.XXXXXX) echo "Staging frontend archive in $STAGING_DIR..." cp -r "$FRONTEND_DIST/." "$STAGING_DIR/" - # Bake AIUI in so fresh installs pick it up. OTA already - # carries-forward the existing aiui/ if the tarball lacks one - # (update.rs:922), but including it here makes the tarball - # the single source of truth instead of relying on a side- - # effect of the in-place swap. - if [ -d "$PROJECT_ROOT/demo/aiui" ] && [ -f "$PROJECT_ROOT/demo/aiui/index.html" ]; then - echo " Including AIUI from demo/aiui/" - cp -r "$PROJECT_ROOT/demo/aiui" "$STAGING_DIR/aiui" + # create-release.sh folds the freshly built AIUI into FRONTEND_DIST. + # Never overlay it with the older demo bundle (or nest aiui/aiui/). + if [ ! -f "$STAGING_DIR/aiui/index.html" ] || \ + [ ! -f "$STAGING_DIR/aiui/BUILD-INFO" ]; then + echo "Error: fresh AIUI payload missing from frontend dist" >&2 + exit 1 fi + grep -Fxq "commit=$(git -C "$PROJECT_ROOT" rev-parse HEAD)" "$STAGING_DIR/aiui/BUILD-INFO" || { + echo "Error: AIUI payload was not built from the current commit" >&2 + exit 1 + } # OTA bridge for nodes running older updaters: they only know how to # apply the backend binary and frontend archive. Carry host runtime # assets inside the frontend tarball; the new backend promotes them diff --git a/scripts/create-release.sh b/scripts/create-release.sh index b4b8c4dd..954bc224 100755 --- a/scripts/create-release.sh +++ b/scripts/create-release.sh @@ -169,15 +169,11 @@ else fi cd "$PROJECT_ROOT" -# npm run build wipes web/dist — fold AIUI straight back in. The OTA tarball -# bakes it from demo/aiui independently, but build-iso-release.sh's -# verify-artifacts guard checks web/dist/neode-ui/aiui and failed on two -# consecutive releases (.127, .129) because this fold-in was manual. -if [ -d "$PROJECT_ROOT/demo/aiui" ] && [ -f "$PROJECT_ROOT/demo/aiui/index.html" ]; then - rm -rf "$PROJECT_ROOT/web/dist/neode-ui/aiui" - cp -r "$PROJECT_ROOT/demo/aiui" "$PROJECT_ROOT/web/dist/neode-ui/aiui" - echo " AIUI folded into web/dist from demo/aiui" -fi +# Build AIUI from the same source as the release. The checked-in demo bundle +# can predate source fixes and must never overwrite the production payload. +bash "$SCRIPT_DIR/build-aiui.sh" +rm -rf "$PROJECT_ROOT/web/dist/neode-ui/aiui" +cp -r "$PROJECT_ROOT/aiui/packages/app/dist" "$PROJECT_ROOT/web/dist/neode-ui/aiui" # npm run build can silently no-op (vue-tsc EACCES burned us before) — a stale # dist would ship with a perfectly valid sha256. Require the freshly built