From 496448aa2f31e0209787f2d0f8e9735e9b9a56d3 Mon Sep 17 00:00:00 2001 From: JSONbored <49853598+JSONbored@users.noreply.github.com> Date: Sun, 12 Jul 2026 23:54:48 -0700 Subject: [PATCH] feat(loopover): flip site-identity domain to loopover.ai Advances #4765. Flips PUBLIC_SITE_ORIGIN (+ CORS, OAuth returnTo fallback, UI-facing links/docs/sitemap, ORB broker/collector defaults, OpenAPI server URL) from gittensory.aethereal.dev / gittensory-api.aethereal.dev to loopover.ai / api.loopover.ai as the new default identity. PUBLIC_API_ORIGIN is intentionally left unchanged: flipping it would send a new redirect_uri during GitHub OAuth, which requires the GitHub App's registered callback URL to be updated first. That flip lands separately once the callback URL is confirmed. The old gittensory.aethereal.dev domain stays live (CORS allowlist, Worker route, and PUBLIC_SITE_ORIGIN_ALIASES) as a backward-compatible alias, not a hard cutover. --- .github/workflows/ci.yml | 4 +- .github/workflows/release-selfhost.yml | 2 +- .github/workflows/ui-deploy.yml | 2 +- .github/workflows/ui-preview-deploy.yml | 2 +- .github/workflows/ui-preview.yml | 2 +- apps/gittensory-ui/public/openapi.json | 2 +- apps/gittensory-ui/public/robots.txt | 2 +- apps/gittensory-ui/public/sitemap.xml | 70 +++++++++---------- .../src/components/site/site-footer.tsx | 4 +- apps/gittensory-ui/src/lib/analytics-proxy.ts | 2 +- apps/gittensory-ui/src/lib/api/origin.ts | 2 +- apps/gittensory-ui/src/routes/__root.tsx | 4 +- apps/gittensory-ui/src/routes/agents.tsx | 2 +- .../src/routes/docs.mcp-clients.tsx | 2 +- .../routes/docs.self-hosting-github-app.tsx | 2 +- .../src/routes/docs.troubleshooting.tsx | 4 +- apps/gittensory-ui/src/routes/index.tsx | 2 +- apps/gittensory-ui/wrangler.jsonc | 2 +- scripts/smoke-production.mjs | 6 +- scripts/smoke-ui-browser.mjs | 2 +- scripts/write-ui-openapi.ts | 2 +- src/api/routes.ts | 3 +- src/auth/github-oauth.ts | 4 +- src/env.d.ts | 2 +- src/github/footer.ts | 2 +- src/github/repo-doc-pr.ts | 2 +- src/orb/broker-client.ts | 2 +- src/review/repo-doc-render.ts | 2 +- src/review/visual/capture.ts | 2 +- src/selfhost/orb-collector.ts | 2 +- src/signals/engine.ts | 2 +- test/helpers/d1.ts | 2 +- test/integration/orb-oauth.test.ts | 4 +- test/integration/routes-errors.test.ts | 4 +- test/unit/auth.test.ts | 8 +-- test/unit/github-app.test.ts | 2 +- test/unit/github-commands.test.ts | 4 +- test/unit/orb-broker-client.test.ts | 6 +- test/unit/queue-4.test.ts | 2 +- worker-configuration.d.ts | 6 +- wrangler.jsonc | 10 +-- 41 files changed, 98 insertions(+), 95 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1357315227..86fc7d6722 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -169,7 +169,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 45 env: - VITE_GITTENSORY_API_ORIGIN: https://gittensory-api.aethereal.dev + VITE_GITTENSORY_API_ORIGIN: https://api.loopover.ai steps: - name: Checkout uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 @@ -422,7 +422,7 @@ jobs: matrix: shard: [1, 2, 3, 4, 5, 6] env: - VITE_GITTENSORY_API_ORIGIN: https://gittensory-api.aethereal.dev + VITE_GITTENSORY_API_ORIGIN: https://api.loopover.ai steps: - name: Checkout uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 diff --git a/.github/workflows/release-selfhost.yml b/.github/workflows/release-selfhost.yml index 05e5988de7..238bb378c9 100644 --- a/.github/workflows/release-selfhost.yml +++ b/.github/workflows/release-selfhost.yml @@ -351,7 +351,7 @@ jobs: docker pull ghcr.io/${REPOSITORY_OWNER_LOWER}/loopover-selfhost:${RELEASE_TAG} \`\`\` - Multi-arch (linux/amd64 + linux/arm64). See https://gittensory.aethereal.dev/docs/maintainer-self-hosting for setup. + Multi-arch (linux/amd64 + linux/arm64). See https://loopover.ai/docs/maintainer-self-hosting for setup. Includes the Claude Code / Codex subscription CLIs by default; credentials stay runtime-only. Sentry release id baked into the image: \`${RELEASE_ID}\`. diff --git a/.github/workflows/ui-deploy.yml b/.github/workflows/ui-deploy.yml index 0d0edfa776..a8ca4fbf30 100644 --- a/.github/workflows/ui-deploy.yml +++ b/.github/workflows/ui-deploy.yml @@ -36,5 +36,5 @@ jobs: # regen (mirrors the same fix in .github/workflows/ci.yml's "UI build" step). - name: Validate frontend env: - VITE_GITTENSORY_API_ORIGIN: https://gittensory-api.aethereal.dev + VITE_GITTENSORY_API_ORIGIN: https://api.loopover.ai run: npm run ui:openapi:check && npm run ui:lint && npm run ui:typecheck && npm run extension:lint && npm run miner-extension:lint && npm run extension:typecheck && npm run miner-extension:typecheck && npm run extension:build && npm run miner-extension:build && npm --workspace @jsonbored/gittensory-ui run build diff --git a/.github/workflows/ui-preview-deploy.yml b/.github/workflows/ui-preview-deploy.yml index d8740ec169..14ce18318e 100644 --- a/.github/workflows/ui-preview-deploy.yml +++ b/.github/workflows/ui-preview-deploy.yml @@ -143,7 +143,7 @@ jobs: } }, "vars": { - "VITE_GITTENSORY_API_ORIGIN": "https://gittensory-api.aethereal.dev" + "VITE_GITTENSORY_API_ORIGIN": "https://api.loopover.ai" }, "main": "index.mjs", "assets": { diff --git a/.github/workflows/ui-preview.yml b/.github/workflows/ui-preview.yml index bfdb8010d0..f132bd51ce 100644 --- a/.github/workflows/ui-preview.yml +++ b/.github/workflows/ui-preview.yml @@ -47,7 +47,7 @@ jobs: - name: Build UI env: - VITE_GITTENSORY_API_ORIGIN: https://gittensory-api.aethereal.dev + VITE_GITTENSORY_API_ORIGIN: https://api.loopover.ai # Preview-only: enables the synthetic demo session (useSession().signInPreview) so reviewbot can # screenshot the authenticated /app/* dashboard via ?preview=1 instead of the sign-in wall. The # production build (ui-deploy.yml) does NOT set this, so the escape hatch is dead-code-eliminated diff --git a/apps/gittensory-ui/public/openapi.json b/apps/gittensory-ui/public/openapi.json index 3460e0f059..98ae47ca7c 100644 --- a/apps/gittensory-ui/public/openapi.json +++ b/apps/gittensory-ui/public/openapi.json @@ -17075,7 +17075,7 @@ }, "servers": [ { - "url": "https://gittensory-api.aethereal.dev", + "url": "https://api.loopover.ai", "description": "Production" } ] diff --git a/apps/gittensory-ui/public/robots.txt b/apps/gittensory-ui/public/robots.txt index 06f6932e2b..954e61fd1d 100644 --- a/apps/gittensory-ui/public/robots.txt +++ b/apps/gittensory-ui/public/robots.txt @@ -1,4 +1,4 @@ User-agent: * Allow: / -Sitemap: https://gittensory.aethereal.dev/sitemap.xml +Sitemap: https://loopover.ai/sitemap.xml diff --git a/apps/gittensory-ui/public/sitemap.xml b/apps/gittensory-ui/public/sitemap.xml index 35e6313b34..da9be0522c 100644 --- a/apps/gittensory-ui/public/sitemap.xml +++ b/apps/gittensory-ui/public/sitemap.xml @@ -1,38 +1,38 @@ - https://gittensory.aethereal.dev/ - https://gittensory.aethereal.dev/miners - https://gittensory.aethereal.dev/maintainers - https://gittensory.aethereal.dev/agents - https://gittensory.aethereal.dev/extension - https://gittensory.aethereal.dev/roadmap - https://gittensory.aethereal.dev/docs - https://gittensory.aethereal.dev/docs/beta-onboarding - https://gittensory.aethereal.dev/docs/quickstart - https://gittensory.aethereal.dev/docs/mcp-clients - https://gittensory.aethereal.dev/docs/miner-workflow - https://gittensory.aethereal.dev/docs/maintainer-workflow - https://gittensory.aethereal.dev/docs/github-app - https://gittensory.aethereal.dev/docs/maintainer-install-trust - https://gittensory.aethereal.dev/docs/maintainer-self-hosting - https://gittensory.aethereal.dev/docs/self-hosting-quickstart - https://gittensory.aethereal.dev/docs/self-hosting-configuration - https://gittensory.aethereal.dev/docs/self-hosting-github-app - https://gittensory.aethereal.dev/docs/self-hosting-ai-providers - https://gittensory.aethereal.dev/docs/self-hosting-rees - https://gittensory.aethereal.dev/docs/self-hosting-rees-analyzers - https://gittensory.aethereal.dev/docs/self-hosting-rag - https://gittensory.aethereal.dev/docs/self-hosting-operations - https://gittensory.aethereal.dev/docs/self-hosting-backup-scaling - https://gittensory.aethereal.dev/docs/self-hosting-releases - https://gittensory.aethereal.dev/docs/self-hosting-security - https://gittensory.aethereal.dev/docs/self-hosting-troubleshooting - https://gittensory.aethereal.dev/docs/branch-analysis - https://gittensory.aethereal.dev/docs/scoreability - https://gittensory.aethereal.dev/docs/upstream-drift - https://gittensory.aethereal.dev/docs/privacy-security - https://gittensory.aethereal.dev/docs/troubleshooting - https://gittensory.aethereal.dev/docs/ai-summaries - https://gittensory.aethereal.dev/api - https://gittensory.aethereal.dev/changelog + https://loopover.ai/ + https://loopover.ai/miners + https://loopover.ai/maintainers + https://loopover.ai/agents + https://loopover.ai/extension + https://loopover.ai/roadmap + https://loopover.ai/docs + https://loopover.ai/docs/beta-onboarding + https://loopover.ai/docs/quickstart + https://loopover.ai/docs/mcp-clients + https://loopover.ai/docs/miner-workflow + https://loopover.ai/docs/maintainer-workflow + https://loopover.ai/docs/github-app + https://loopover.ai/docs/maintainer-install-trust + https://loopover.ai/docs/maintainer-self-hosting + https://loopover.ai/docs/self-hosting-quickstart + https://loopover.ai/docs/self-hosting-configuration + https://loopover.ai/docs/self-hosting-github-app + https://loopover.ai/docs/self-hosting-ai-providers + https://loopover.ai/docs/self-hosting-rees + https://loopover.ai/docs/self-hosting-rees-analyzers + https://loopover.ai/docs/self-hosting-rag + https://loopover.ai/docs/self-hosting-operations + https://loopover.ai/docs/self-hosting-backup-scaling + https://loopover.ai/docs/self-hosting-releases + https://loopover.ai/docs/self-hosting-security + https://loopover.ai/docs/self-hosting-troubleshooting + https://loopover.ai/docs/branch-analysis + https://loopover.ai/docs/scoreability + https://loopover.ai/docs/upstream-drift + https://loopover.ai/docs/privacy-security + https://loopover.ai/docs/troubleshooting + https://loopover.ai/docs/ai-summaries + https://loopover.ai/api + https://loopover.ai/changelog diff --git a/apps/gittensory-ui/src/components/site/site-footer.tsx b/apps/gittensory-ui/src/components/site/site-footer.tsx index 5a81be8731..fc5e244074 100644 --- a/apps/gittensory-ui/src/components/site/site-footer.tsx +++ b/apps/gittensory-ui/src/components/site/site-footer.tsx @@ -96,9 +96,9 @@ export function SiteFooter() {
- gittensory.aethereal.dev + loopover.ai · - api: gittensory-api.aethereal.dev + api: api.loopover.ai
https://tasty.aethereal.dev/api/send // // Do not proxy the remote Umami script through this origin. Serving mutable diff --git a/apps/gittensory-ui/src/lib/api/origin.ts b/apps/gittensory-ui/src/lib/api/origin.ts index 888df97890..876f1f8a15 100644 --- a/apps/gittensory-ui/src/lib/api/origin.ts +++ b/apps/gittensory-ui/src/lib/api/origin.ts @@ -1,4 +1,4 @@ -const DEFAULT_API_ORIGIN = "https://gittensory-api.aethereal.dev"; +const DEFAULT_API_ORIGIN = "https://api.loopover.ai"; export function getApiOrigin(): string { const configured = import.meta.env.VITE_GITTENSORY_API_ORIGIN?.trim(); diff --git a/apps/gittensory-ui/src/routes/__root.tsx b/apps/gittensory-ui/src/routes/__root.tsx index cb5dc1b0e7..c7a92681ea 100644 --- a/apps/gittensory-ui/src/routes/__root.tsx +++ b/apps/gittensory-ui/src/routes/__root.tsx @@ -154,8 +154,8 @@ export const Route = createRootRouteWithContext<{ queryClient: QueryClient }>()( children: JSON.stringify({ "@context": "https://schema.org", "@type": "Organization", - name: "Gittensory", - url: "https://gittensory.aethereal.dev", + name: "LoopOver", + url: "https://loopover.ai", description: "Deterministic base-agent layer for Gittensor OSS contribution mining.", }), }, diff --git a/apps/gittensory-ui/src/routes/agents.tsx b/apps/gittensory-ui/src/routes/agents.tsx index 69fa209bd6..eb08a91152 100644 --- a/apps/gittensory-ui/src/routes/agents.tsx +++ b/apps/gittensory-ui/src/routes/agents.tsx @@ -72,7 +72,7 @@ function AgentsPage() {
- +
diff --git a/apps/gittensory-ui/src/routes/docs.mcp-clients.tsx b/apps/gittensory-ui/src/routes/docs.mcp-clients.tsx index d68c26fe9c..b1f4513217 100644 --- a/apps/gittensory-ui/src/routes/docs.mcp-clients.tsx +++ b/apps/gittensory-ui/src/routes/docs.mcp-clients.tsx @@ -112,7 +112,7 @@ args = ["--stdio"]`} The Worker also exposes a remote MCP endpoint. Use this when your agent runs in the cloud or you don't want a local Node process.

- + Local --stdio is the default recommendation. It keeps auth + analysis on your diff --git a/apps/gittensory-ui/src/routes/docs.self-hosting-github-app.tsx b/apps/gittensory-ui/src/routes/docs.self-hosting-github-app.tsx index 4e64755096..020bc94703 100644 --- a/apps/gittensory-ui/src/routes/docs.self-hosting-github-app.tsx +++ b/apps/gittensory-ui/src/routes/docs.self-hosting-github-app.tsx @@ -217,7 +217,7 @@ GITHUB_WEBHOOK_SECRET=`} -ORB_BROKER_URL=https://gittensory-api.aethereal.dev +ORB_BROKER_URL=https://api.loopover.ai ORB_RELAY_MODE=pull # or omit for push (the default) -- see "Choosing a relay mode" below`} />

diff --git a/apps/gittensory-ui/src/routes/docs.troubleshooting.tsx b/apps/gittensory-ui/src/routes/docs.troubleshooting.tsx index 945602fcc3..7ba48e7411 100644 --- a/apps/gittensory-ui/src/routes/docs.troubleshooting.tsx +++ b/apps/gittensory-ui/src/routes/docs.troubleshooting.tsx @@ -39,7 +39,7 @@ gittensory-mcp status gittensory-mcp whoami`} />

Or hit the public API endpoint directly to confirm reachability:

- +

Self-host Docker observability

@@ -111,7 +111,7 @@ OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318`}

/health couldn't be reached at all. This usually means a network problem between you and the API edge. Try the Recheck button in the banner, or run{" "} - curl https://gittensory-api.aethereal.dev/health from your machine to confirm. + curl https://api.loopover.ai/health from your machine to confirm.

API timing out

diff --git a/apps/gittensory-ui/src/routes/index.tsx b/apps/gittensory-ui/src/routes/index.tsx index 5f5f5c5e2b..a6d1d25157 100644 --- a/apps/gittensory-ui/src/routes/index.tsx +++ b/apps/gittensory-ui/src/routes/index.tsx @@ -506,7 +506,7 @@ args = ["-y", "@jsonbored/gittensory-mcp@latest", "--stdio"]`, audience: "Agents", filename: "endpoint", lang: "http", - snippet: `https://gittensory-api.aethereal.dev/mcp`, + snippet: `https://api.loopover.ai/mcp`, }, ]; diff --git a/apps/gittensory-ui/wrangler.jsonc b/apps/gittensory-ui/wrangler.jsonc index 68a9b13fd2..f0d6589435 100644 --- a/apps/gittensory-ui/wrangler.jsonc +++ b/apps/gittensory-ui/wrangler.jsonc @@ -20,7 +20,7 @@ }, }, "vars": { - "VITE_GITTENSORY_API_ORIGIN": "https://gittensory-api.aethereal.dev", + "VITE_GITTENSORY_API_ORIGIN": "https://api.loopover.ai", }, "routes": [ { diff --git a/scripts/smoke-production.mjs b/scripts/smoke-production.mjs index 0d4a11bd0d..5b527083e3 100644 --- a/scripts/smoke-production.mjs +++ b/scripts/smoke-production.mjs @@ -1,5 +1,5 @@ -const siteOrigin = normalizeOrigin(process.env.GITTENSORY_SITE_ORIGIN ?? "https://gittensory.aethereal.dev"); -const apiOrigin = normalizeOrigin(process.env.GITTENSORY_API_ORIGIN ?? "https://gittensory-api.aethereal.dev"); +const siteOrigin = normalizeOrigin(process.env.GITTENSORY_SITE_ORIGIN ?? "https://loopover.ai"); +const apiOrigin = normalizeOrigin(process.env.GITTENSORY_API_ORIGIN ?? "https://api.loopover.ai"); const siteRoutes = [ "/", @@ -27,7 +27,7 @@ async function main() { for (const route of siteRoutes) checks.push(checkStatus(`${siteOrigin}${route}`, 200, `UI ${route}`)); checks.push(checkStatus(`${siteOrigin}/openapi.json`, 200, "UI OpenAPI artifact", { contentType: /application\/json/i })); checks.push(checkStatus(`${siteOrigin}/downloads/loopover-extension.zip`, 200, "extension zip", { contentType: /application\/zip/i })); - checks.push(checkText(`${siteOrigin}/robots.txt`, "Sitemap: https://gittensory.aethereal.dev/sitemap.xml", "robots sitemap directive")); + checks.push(checkText(`${siteOrigin}/robots.txt`, "Sitemap: https://loopover.ai/sitemap.xml", "robots sitemap directive")); checks.push(checkStatus(`${siteOrigin}/sitemap.xml`, 200, "sitemap", { contentType: /application\/xml/i })); checks.push(checkStatus(`${siteOrigin}/CNAME`, 404, "retired GitHub Pages CNAME")); diff --git a/scripts/smoke-ui-browser.mjs b/scripts/smoke-ui-browser.mjs index 43258ed887..ddc8813b67 100644 --- a/scripts/smoke-ui-browser.mjs +++ b/scripts/smoke-ui-browser.mjs @@ -1,4 +1,4 @@ -const siteOrigin = new URL(process.env.GITTENSORY_SITE_ORIGIN ?? "https://gittensory.aethereal.dev").origin; +const siteOrigin = new URL(process.env.GITTENSORY_SITE_ORIGIN ?? "https://loopover.ai").origin; const routes = ["/", "/app", "/app/workbench", "/app/repos", "/app/runs", "/app/analytics", "/app/operator", "/app/commands", "/app/digest", "/api", "/roadmap", "/changelog", "/extension", "/docs"]; const playwright = await import("playwright").catch(() => null); diff --git a/scripts/write-ui-openapi.ts b/scripts/write-ui-openapi.ts index 0d73a3d411..93410e939a 100644 --- a/scripts/write-ui-openapi.ts +++ b/scripts/write-ui-openapi.ts @@ -9,7 +9,7 @@ const target = resolve(root, "apps/gittensory-ui/public/openapi.json"); const checkOnly = process.argv.includes("--check"); const spec = buildOpenApiSpec(); -spec.servers = [{ url: "https://gittensory-api.aethereal.dev", description: "Production" }]; +spec.servers = [{ url: "https://api.loopover.ai", description: "Production" }]; const current = await readFile(target, "utf8").catch(() => ""); const currentSpec = parseCurrentSpec(current); diff --git a/src/api/routes.ts b/src/api/routes.ts index 8f7f3eec2f..a8ef612eef 100644 --- a/src/api/routes.ts +++ b/src/api/routes.ts @@ -4211,7 +4211,7 @@ const APP_COMMANDS = [ ] as const; function authRedirectWithError(env: Env, reason: string): string { - const siteOrigin = env.PUBLIC_SITE_ORIGIN ?? "https://gittensory.aethereal.dev"; + const siteOrigin = env.PUBLIC_SITE_ORIGIN ?? "https://loopover.ai"; const url = new URL("/app", siteOrigin); url.searchParams.set("auth", "error"); url.searchParams.set("reason", reason); @@ -5700,6 +5700,7 @@ function requiresApiToken(path: string): boolean { } const DEFAULT_CORS_ORIGINS = [ + "https://loopover.ai", "https://gittensory.aethereal.dev", "http://localhost:3000", "http://localhost:4173", diff --git a/src/auth/github-oauth.ts b/src/auth/github-oauth.ts index 74bab5cf22..5cf8448ad0 100644 --- a/src/auth/github-oauth.ts +++ b/src/auth/github-oauth.ts @@ -236,12 +236,12 @@ function githubOAuthCallbackUrl(env: Env, requestUrl: string): string { } function normalizeReturnTo(env: Env, value: string | undefined): string { - const siteOrigin = env.PUBLIC_SITE_ORIGIN ?? "https://gittensory.aethereal.dev"; + const siteOrigin = env.PUBLIC_SITE_ORIGIN ?? "https://loopover.ai"; const fallback = `${siteOrigin.replace(/\/$/, "")}/app`; if (!value) return fallback; try { const url = new URL(value, siteOrigin); - // siteOrigin already IS "https://gittensory.aethereal.dev" when PUBLIC_SITE_ORIGIN is unset (the fallback + // siteOrigin already IS "https://loopover.ai" when PUBLIC_SITE_ORIGIN is unset (the fallback // two lines up), so a separate hardcoded entry here was dead weight once a self-hoster sets their own // PUBLIC_SITE_ORIGIN -- it kept accepting the cloud origin as a valid redirect target even for a self-host // instance that never uses it (#4615). Rely solely on siteOrigin. diff --git a/src/env.d.ts b/src/env.d.ts index 91afc01ace..d6509cb10f 100644 --- a/src/env.d.ts +++ b/src/env.d.ts @@ -178,7 +178,7 @@ declare global { * engine sources GitHub installation tokens from the central Orb (POST /v1/orb/token) instead of a local App * key. Cloud never sets it ⇒ inert there. See src/orb/broker-client. (A secret — never commit a real value.) */ ORB_ENROLLMENT_SECRET?: string; - /** Override the Orb broker base URL the self-host client calls (default https://gittensory-api.aethereal.dev); + /** Override the Orb broker base URL the self-host client calls (default https://api.loopover.ai); * point at a private gittensory deployment if you self-host the broker too. */ ORB_BROKER_URL?: string; /** The retired review App's own credentials. Optional: that App has been fully deleted — cloud no longer diff --git a/src/github/footer.ts b/src/github/footer.ts index 1833a71f30..77c1903efe 100644 --- a/src/github/footer.ts +++ b/src/github/footer.ts @@ -11,7 +11,7 @@ /** The LoopOver product site (marketing on-ramp / attribution target) -- the DEFAULT only. A * self-hoster with `PUBLIC_SITE_ORIGIN` set gets their own domain instead, both here and in * `gittensoryFooter` below (#4613). */ -export const GITTENSORY_SITE_URL = "https://gittensory.aethereal.dev"; +export const GITTENSORY_SITE_URL = "https://loopover.ai"; /** Minimal env slice `gittensoryFooter` needs, narrowed from the full `Env` the same way this file's * `maintainerControlPanelUrl` already narrows its own `env` param inline -- so every file that renders diff --git a/src/github/repo-doc-pr.ts b/src/github/repo-doc-pr.ts index b36e2dbb9f..2edc318b19 100644 --- a/src/github/repo-doc-pr.ts +++ b/src/github/repo-doc-pr.ts @@ -150,7 +150,7 @@ export async function openRepoDocPullRequest(env: Env, repoFullName: string, mod const profile = await extractRepoProfile(env, repoFullName); if (!profile.present) return { opened: false, reason: profile.reason }; // #4613: a self-hoster's own domain (env.PUBLIC_SITE_ORIGIN) reaches the generated AGENTS.md's - // attribution link instead of gittensory.aethereal.dev -- same fallback `maintainerControlPanelUrl`/ + // attribution link instead of loopover.ai -- same fallback `maintainerControlPanelUrl`/ // `gittensoryFooter` already use. const generatedSection = renderRepoDocContent(profile, env.PUBLIC_SITE_ORIGIN ?? GITTENSORY_SITE_URL); if (!generatedSection) return { opened: false, reason: "no content rendered from profile" }; diff --git a/src/orb/broker-client.ts b/src/orb/broker-client.ts index 09f4d87b9b..caa0705b06 100644 --- a/src/orb/broker-client.ts +++ b/src/orb/broker-client.ts @@ -10,7 +10,7 @@ import { incr } from "../selfhost/metrics"; /** The Orb's hosted broker base; override (ORB_BROKER_URL) only to point at a private gittensory deployment. */ -const DEFAULT_BROKER_URL = "https://gittensory-api.aethereal.dev"; +const DEFAULT_BROKER_URL = "https://api.loopover.ai"; // The broker's cold token mint can take many seconds when GitHub is throttling the App; allow headroom so the one // uncached mint completes and populates the broker-side cache (steady-state cache hits return in well under a second). const BROKER_TIMEOUT_MS = 25_000; diff --git a/src/review/repo-doc-render.ts b/src/review/repo-doc-render.ts index b7891b929b..c0b0e1d0b6 100644 --- a/src/review/repo-doc-render.ts +++ b/src/review/repo-doc-render.ts @@ -66,7 +66,7 @@ function renderCiWorkflowFiles(ciWorkflowFiles: string[]): string { * is therefore never touched. * * `siteUrl` is resolved by the caller from `env.PUBLIC_SITE_ORIGIN ?? GITTENSORY_SITE_URL` (#4613), so a - * self-hoster's own domain reaches the attribution link instead of `gittensory.aethereal.dev`. Threading it as a + * self-hoster's own domain reaches the attribution link instead of `loopover.ai`. Threading it as a * plain string argument (rather than an `env` slice) keeps this function's purity/determinism contract intact -- * the SAME `(profile, siteUrl)` pair always renders the SAME output, which is all the diff-aware refresh in * `generated-doc-refresh.ts` needs for its byte-for-byte comparison. diff --git a/src/review/visual/capture.ts b/src/review/visual/capture.ts index fb8ae6c625..c54fe71732 100644 --- a/src/review/visual/capture.ts +++ b/src/review/visual/capture.ts @@ -488,7 +488,7 @@ export async function buildCapture(env: Env, token: string, target: CaptureTarge const repo = parseRepo(target.repoFullName); const apiVersion = "2022-11-28"; // before = production. review.visual.production_url (#3611 follow-up) ALWAYS wins when set -- PUBLIC_SITE_ORIGIN - // is a single GLOBAL env var (e.g. https://gittensory.aethereal.dev) with no per-repo awareness, correct for at + // is a single GLOBAL env var (e.g. https://loopover.ai) with no per-repo awareness, correct for at // most one repo on a multi-repo self-host instance; every other repo needs its own override here. const prodBase = visualConfig?.productionUrl ? visualConfig.productionUrl : (env.PUBLIC_SITE_ORIGIN ?? ""); diff --git a/src/selfhost/orb-collector.ts b/src/selfhost/orb-collector.ts index c425ec6792..7b78885fa4 100644 --- a/src/selfhost/orb-collector.ts +++ b/src/selfhost/orb-collector.ts @@ -169,7 +169,7 @@ export async function exportOrbBatch(db: D1Database, batchSize = 200, fetchFn: t // instance's DEDICATED anonymization secret (a 256-bit random key generated once and persisted in // system_flags — see getOrCreateAnonSecret), single-purpose and never the App key, so the collector // (which never holds it) can never de-anonymize them. - const collectorUrl = process.env.ORB_COLLECTOR_URL ?? "https://gittensory-api.aethereal.dev/v1/orb/ingest"; + const collectorUrl = process.env.ORB_COLLECTOR_URL ?? "https://api.loopover.ai/v1/orb/ingest"; const secret = await getOrCreateAnonSecret(db); const anonymize = (process.env.ORB_ANONYMIZE ?? "true").toLowerCase() !== "false"; const instance = instanceId(secret); diff --git a/src/signals/engine.ts b/src/signals/engine.ts index 1daa134eb9..2d10d26ba8 100644 --- a/src/signals/engine.ts +++ b/src/signals/engine.ts @@ -4156,7 +4156,7 @@ type PublicSafeCollapsibleArgs = { e2eTestGenAvailable?: boolean | undefined; /** #5078: resolved by the caller from `env.PUBLIC_SITE_ORIGIN`, same as `buildPublicPrIntelligenceComment`'s * own `env` param -- lets the "[BETA] Chat with Gittensory" collapsible link to a self-hoster's own - * command-reference doc page instead of always the canonical gittensory.aethereal.dev. */ + * command-reference doc page instead of always the canonical loopover.ai. */ env: GittensoryFooterEnv; }; diff --git a/test/helpers/d1.ts b/test/helpers/d1.ts index d7d794aab5..49facb83b8 100644 --- a/test/helpers/d1.ts +++ b/test/helpers/d1.ts @@ -89,7 +89,7 @@ export function createTestEnv(overrides: Partial = {}): Env { GITTENSORY_AUTO_FILE_DRIFT_ISSUES: "false", GITTENSORY_DRIFT_ISSUE_REPO: "JSONbored/gittensory", PUBLIC_API_ORIGIN: "https://gittensory-api.aethereal.dev", - PUBLIC_SITE_ORIGIN: "https://gittensory.aethereal.dev", + PUBLIC_SITE_ORIGIN: "https://loopover.ai", INTERNAL_JOB_TOKEN: "dev-internal-token", GITTENSORY_API_TOKEN: "test-api-token", GITTENSORY_MCP_TOKEN: "test-mcp-token", diff --git a/test/integration/orb-oauth.test.ts b/test/integration/orb-oauth.test.ts index 8600f09c47..9a185f5d92 100644 --- a/test/integration/orb-oauth.test.ts +++ b/test/integration/orb-oauth.test.ts @@ -14,7 +14,7 @@ describe("GET /v1/orb/oauth/callback (post-install landing)", () => { expect(res.status).toBe(200); const html = await res.text(); expect(html).toContain("Gittensory Orb connected"); - expect(html).toContain("gittensory.aethereal.dev"); + expect(html).toContain("loopover.ai"); }); it("returns the updated page on a repo-selection update", async () => { @@ -50,7 +50,7 @@ describe("GET /v1/orb/oauth/callback (post-install landing)", () => { const env = createTestEnv(); delete (env as Partial).PUBLIC_SITE_ORIGIN; const res = await app.request("/v1/orb/oauth/callback", {}, env); - expect(await res.text()).toContain('href="https://gittensory.aethereal.dev"'); + expect(await res.text()).toContain('href="https://loopover.ai"'); }); }); diff --git a/test/integration/routes-errors.test.ts b/test/integration/routes-errors.test.ts index 0432ee896a..0f8c412319 100644 --- a/test/integration/routes-errors.test.ts +++ b/test/integration/routes-errors.test.ts @@ -57,7 +57,7 @@ describe("api route guards and error branches", () => { ADMIN_GITHUB_LOGINS: "jsonbored", }); - const started = await app.request("/v1/auth/github/start?returnTo=https%3A%2F%2Fgittensory.aethereal.dev%2Fapp", {}, env); + const started = await app.request("/v1/auth/github/start?returnTo=https%3A%2F%2Floopover.ai%2Fapp", {}, env); expect(started.status).toBe(302); const startCookie = started.headers.get("set-cookie") ?? ""; const location = new URL(started.headers.get("location") ?? ""); @@ -74,7 +74,7 @@ describe("api route guards and error branches", () => { const callback = await app.request(`/v1/auth/github/callback?code=code&state=${encodeURIComponent(state)}`, { headers: { cookie: firstCookiePair(startCookie) } }, env); expect(callback.status).toBe(302); - expect(callback.headers.get("location")).toBe("https://gittensory.aethereal.dev/app"); + expect(callback.headers.get("location")).toBe("https://loopover.ai/app"); const callbackCookie = callback.headers.get("set-cookie") ?? ""; expect(callbackCookie).toContain("gittensory_session="); expect(callbackCookie).toContain("HttpOnly"); diff --git a/test/unit/auth.test.ts b/test/unit/auth.test.ts index c31c15b7c9..abe6e40705 100644 --- a/test/unit/auth.test.ts +++ b/test/unit/auth.test.ts @@ -632,9 +632,9 @@ describe("private-beta auth and rate limiting", () => { const started = await startGitHubWebOAuth( env, "https://gittensory-api.aethereal.dev/v1/auth/github/start", - "https://gittensory.aethereal.dev/app/workbench", + "https://loopover.ai/app/workbench", ); - expect(started.returnTo).toBe("https://gittensory.aethereal.dev/app/workbench"); + expect(started.returnTo).toBe("https://loopover.ai/app/workbench"); expect(started.authorizationUrl).toContain("https://github.com/login/oauth/authorize"); expect(started.authorizationUrl).toContain("client_id=client-id"); expect(started.authorizationUrl).toContain("redirect_uri=https%3A%2F%2Fgittensory-api.aethereal.dev%2Fv1%2Fauth%2Fgithub%2Fcallback"); @@ -655,7 +655,7 @@ describe("private-beta auth and rate limiting", () => { state: started.state, cookieState: started.state, }), - ).resolves.toMatchObject({ login: "jsonbored", scopes: ["read:user"], returnTo: "https://gittensory.aethereal.dev/app/workbench" }); + ).resolves.toMatchObject({ login: "jsonbored", scopes: ["read:user"], returnTo: "https://loopover.ai/app/workbench" }); await expect( completeGitHubWebOAuth(env, "https://gittensory-api.aethereal.dev/v1/auth/github/callback", { @@ -689,7 +689,7 @@ describe("private-beta auth and rate limiting", () => { delete (env as Partial).PUBLIC_SITE_ORIGIN; const invalidReturnTo = await startGitHubWebOAuth(env, "https://preview.example.workers.dev/v1/auth/github/start", "https://evil.example/app"); - expect(invalidReturnTo.returnTo).toBe("https://gittensory.aethereal.dev/app"); + expect(invalidReturnTo.returnTo).toBe("https://loopover.ai/app"); expect(invalidReturnTo.authorizationUrl).toContain("redirect_uri=https%3A%2F%2Fpreview.example.workers.dev%2Fv1%2Fauth%2Fgithub%2Fcallback"); const localhostReturnTo = await startGitHubWebOAuth(env, "https://preview.example.workers.dev/v1/auth/github/start", "http://localhost:5173/app"); diff --git a/test/unit/github-app.test.ts b/test/unit/github-app.test.ts index 70e2fca371..466ce6c45a 100644 --- a/test/unit/github-app.test.ts +++ b/test/unit/github-app.test.ts @@ -1362,7 +1362,7 @@ describe("GitHub check runs", () => { expect(capturedBody.output?.text).toContain("blocks every author"); // The "Details" link points at the repo's Gittensory maintainer panel, not GitHub's generic check page. (#audit-details-url) expect(capturedBody.details_url).toBe( - "https://gittensory.aethereal.dev/app?view=maintainer&repo=JSONbored%2Fgittensory", + "https://loopover.ai/app?view=maintainer&repo=JSONbored%2Fgittensory", ); }); diff --git a/test/unit/github-commands.test.ts b/test/unit/github-commands.test.ts index de7cae171d..5b4e483a35 100644 --- a/test/unit/github-commands.test.ts +++ b/test/unit/github-commands.test.ts @@ -229,7 +229,7 @@ describe("GitHub mention commands", () => { it("helpSections links to the public command reference doc (#2171)", () => { const body = githubCommandsInternals.helpSections({}).join("\n"); - expect(body).toContain("https://gittensory.aethereal.dev/docs/gittensory-commands"); + expect(body).toContain("https://loopover.ai/docs/gittensory-commands"); expect(body).toContain("Full command reference"); }); @@ -241,7 +241,7 @@ describe("GitHub mention commands", () => { it("commandReferenceUrl falls back to the default site when PUBLIC_SITE_ORIGIN is malformed", () => { expect(githubCommandsInternals.commandReferenceUrl({ PUBLIC_SITE_ORIGIN: "not a url" })).toBe( - "https://gittensory.aethereal.dev/docs/gittensory-commands", + "https://loopover.ai/docs/gittensory-commands", ); }); diff --git a/test/unit/orb-broker-client.test.ts b/test/unit/orb-broker-client.test.ts index 2f4cda2945..36d8104c57 100644 --- a/test/unit/orb-broker-client.test.ts +++ b/test/unit/orb-broker-client.test.ts @@ -33,7 +33,7 @@ describe("fetchBrokeredInstallationToken", () => { const { fetchImpl, calls } = captureFetch(Response.json({ token: "ghs_x", installationId: 42, expiresAt: "2026-06-25T09:00:00Z", permissions: { contents: "write" } })); const out = await fetchBrokeredInstallationToken({ ORB_ENROLLMENT_SECRET: "orbsec_x" }, fetchImpl); expect(out).toEqual({ token: "ghs_x", installationId: 42, expiresAtMs: Date.parse("2026-06-25T09:00:00Z"), permissions: { contents: "write" } }); - expect(calls[0]?.url).toBe("https://gittensory-api.aethereal.dev/v1/orb/token"); + expect(calls[0]?.url).toBe("https://api.loopover.ai/v1/orb/token"); expect((calls[0]?.init?.headers as Record).authorization).toBe("Bearer orbsec_x"); expect(calls[0]?.init?.method).toBe("POST"); expect(calls[0]?.init?.body).toBeUndefined(); @@ -131,7 +131,7 @@ describe("registerOrbRelayTarget", () => { it("uses the default broker base when ORB_BROKER_URL is unset", async () => { const { fetchImpl, calls } = captureFetch(new Response("ok")); await registerOrbRelayTarget({ ORB_ENROLLMENT_SECRET: "s", PUBLIC_API_ORIGIN: "https://me.example" }, fetchImpl); - expect(calls[0]?.url).toBe("https://gittensory-api.aethereal.dev/v1/orb/relay/register"); + expect(calls[0]?.url).toBe("https://api.loopover.ai/v1/orb/relay/register"); }); it("fails closed without registering when the broker URL is unsafe", async () => { @@ -380,7 +380,7 @@ describe("drainOrbRelay (pull-mode drain)", () => { { deliveryId: "d1", eventName: "pull_request", rawBody: "{\"a\":1}" }, { deliveryId: "d2", eventName: "check_suite", rawBody: "{}" }, ]); - expect(calls[0]?.url).toBe("https://gittensory-api.aethereal.dev/v1/orb/relay/pull"); + expect(calls[0]?.url).toBe("https://api.loopover.ai/v1/orb/relay/pull"); expect((calls[0]?.init?.headers as Record).authorization).toBe("Bearer s"); expect(JSON.parse(String(calls[0]?.init?.body))).toEqual({ ack: ["prev-1"] }); expect(counterValue("loopover_orb_relay_malformed_events_total")).toBe(1); diff --git a/test/unit/queue-4.test.ts b/test/unit/queue-4.test.ts index 37fb0f4a8b..75dda8baf7 100644 --- a/test/unit/queue-4.test.ts +++ b/test/unit/queue-4.test.ts @@ -6810,7 +6810,7 @@ describe("queue processors", () => { expect(body.body).toContain("**Gittensory maintainer queue summary**"); expect(body.body).toContain("Open PRs: 4"); expect(body.body).toContain("confirmed-miner PRs: 1"); - expect(body.body).toContain("Authenticated control panel: https://gittensory.aethereal.dev/app?view=maintainer&repo=JSONbored%2Fgittensory"); + expect(body.body).toContain("Authenticated control panel: https://loopover.ai/app?view=maintainer&repo=JSONbored%2Fgittensory"); expect(body.body).not.toMatch(/wallet|hotkey|raw trust score|payout|reward estimate|farming|private reviewability|public score estimate/i); return Response.json({ id: 1001 }, { status: 201 }); } diff --git a/worker-configuration.d.ts b/worker-configuration.d.ts index e1947b1df9..f02444525f 100644 --- a/worker-configuration.d.ts +++ b/worker-configuration.d.ts @@ -1,5 +1,5 @@ /* eslint-disable */ -// Generated by Wrangler by running `wrangler types` (hash: edef2ca99ed4103c1ab8cdf89078e160) +// Generated by Wrangler by running `wrangler types` (hash: eaba2a08cc6397ed08020b695340552a) // Runtime types generated with workerd@1.20260701.1 2026-05-28 nodejs_compat interface __BaseEnv_Env { REVIEW_AUDIT: R2Bucket; @@ -15,8 +15,8 @@ interface __BaseEnv_Env { GITTENSORY_AUTO_FILE_DRIFT_ISSUES: "false"; GITTENSORY_DRIFT_ISSUE_REPO: "JSONbored/gittensory"; PUBLIC_API_ORIGIN: "https://gittensory-api.aethereal.dev"; - PUBLIC_SITE_ORIGIN: "https://gittensory.aethereal.dev"; - PUBLIC_SITE_ORIGIN_ALIASES: "https://loopover.ai"; + PUBLIC_SITE_ORIGIN: "https://loopover.ai"; + PUBLIC_SITE_ORIGIN_ALIASES: "https://gittensory.aethereal.dev"; ADMIN_GITHUB_LOGINS: "JSONbored"; GITTENSORY_REVIEW_UNIFIED_COMMENT: "false"; GITTENSORY_REVIEW_INLINE_COMMENTS: "false"; diff --git a/wrangler.jsonc b/wrangler.jsonc index 7ff42c02ee..4ca8b437cc 100644 --- a/wrangler.jsonc +++ b/wrangler.jsonc @@ -39,10 +39,12 @@ "GITTENSORY_AUTO_FILE_DRIFT_ISSUES": "false", "GITTENSORY_DRIFT_ISSUE_REPO": "JSONbored/gittensory", "PUBLIC_API_ORIGIN": "https://gittensory-api.aethereal.dev", - "PUBLIC_SITE_ORIGIN": "https://gittensory.aethereal.dev", - // LoopOver rebrand (issue #4762, Step 1): loopover.ai runs live side-by-side with the existing domain, not - // as a replacement -- keeps the post-OAuth-login redirect working when a user signs in from loopover.ai. - "PUBLIC_SITE_ORIGIN_ALIASES": "https://loopover.ai", + // LoopOver rebrand (issue #4765, domain flip): loopover.ai is now the canonical site origin. The old + // gittensory.aethereal.dev domain stays live (still resolves, still valid as a post-OAuth-login redirect + // target via PUBLIC_SITE_ORIGIN_ALIASES below) -- no redirect rule, no sunset date, both domains keep + // working side by side; only which one this instance treats as canonical has flipped. + "PUBLIC_SITE_ORIGIN": "https://loopover.ai", + "PUBLIC_SITE_ORIGIN_ALIASES": "https://gittensory.aethereal.dev", "ADMIN_GITHUB_LOGINS": "JSONbored", // Hosted reviews are retired. Cloudflare now serves the public API + Orb broker only; review execution runs // in the self-host container, where Redis-backed transient state is mandatory. The Cloudflare API worker no