stack/apps/dev-launchpad/public/index.html
BilalG1 c14a9dd3d0
feat(hexclave): PR 5 — internal symbol/path/package renames + brand strings (#1547)
## Stack Auth → Hexclave rename — PR 5 (internal symbols, paths,
packages, brand strings)

PR 5 finishes the **internal / non-wire** half of the Stack→Hexclave
rename. It only touches things where nothing outside the repo depends on
the exact name: internal symbols, file/dir names, the
`@stackframe/template` package, and residual brand strings. Plan +
progress are in `HEXCLAVE-RENAME-PR5-PLAN.md`.

Every step was verified green (`pnpm typecheck` + `pnpm lint`, 28/28)
and committed as its own checkpoint, then a fan-out of review agents
audited all commits and the findings were fixed.

### What changed
- **Internal symbols** (`@hexclave/shared`, `packages/template`, apps):
`stack*`/`Stack*` → `hexclave*`/`Hexclave*` — incl.
`stackGlobalsSymbol`, the `_Stack*AppImpl` classes,
`stackAppInternalsSymbol`, `StackContext`, `getStackStripe`, etc. The
`stack*App` local-variable convention
(`stackServerApp`/`stackClientApp`/…) was renamed across 175
source/example/doc files.
- **File renames**: `hexclave-handler/provider/context.tsx`,
`backend/hexclave.tsx`, `internal-tool/hexclave.ts`,
`hexclave-app-internals.ts`.
- **Directory renames**: `lib/hexclave-app`, `hexclave-companion`,
`[...hexclave]` route segment, `skills/hexclave`,
`dashboard/src/hexclave`, and the package dirs
**`packages/{next,shared,ui,sc,cli}`** (dropping the `stack-` prefix to
match the `@hexclave/*` npm names).
- **Packages**: `@stackframe/template` → `@hexclave/template`; **deleted
`packages/init-stack`** (onboarding lives in `@hexclave/cli init`; the
published npm package is untouched).
- **Brand strings**: reworded `Stack Auth`/`Stack dashboard` prose in
code + docs-mintlify, renamed `hexclave-app.mdx`/`use-hexclave-app.mdx`
with redirects, regenerated OpenAPI, updated coupled e2e assertions;
`doctor`/`init` now prefer `hexclave.config.ts`.

### Intentionally kept (verified, not oversights)
Wire/compat identifiers (`x-stack-*` headers, `stack-*` cookies,
`STACK_*` env names, `*.stack-auth.com`, `stackauth_`, `ask_stack_auth`,
query params), public `Stack*` SDK aliases, crypto/JWT/vault
domain-separation tags, `*-brand-sentinel`s, the
`Symbol.for("StackAuth--…")` string, `_stack_sync_metadata`, Postgres
`stackframe` / docker image names, the `stack-auth-logo*.svg` (used by
the rebrand modal), and `migration.mdx` / "formerly known as Stack Auth"
notes. False positives (Phosphor `StackIcon`/`StackSimple`, `TanStack`,
`OrbStack`, `stackable`/`Stacked` charts) left alone.

### Review pass
Six review agents audited all commits. Found + fixed one real bug — a
build script (`bundle-type-definitions.ts`) hardcoded the old
`lib/stack-app` glob path (not an import, so typecheck/lint were blind),
silently emptying the dashboard AI type bundle — plus stale comments, a
dead CI env var, and stale `.gitignore`/`.dockerignore` entries.
Cross-cutting audit confirmed **zero wire-compat identifiers were
accidentally renamed**.

### ⚠️ Verification note
`typecheck` + `lint` are fully green locally. The **e2e suite was not
run** (needs a live backend+DB), so the brand-string assertion +
OpenAPI-regen changes are verified by grep/codegen only — please let CI
exercise e2e to confirm.

### Base-branch note
This branch was forked from the local-only `cl/friendly-lewin-72293f`
(not on origin, no separate PR), so this PR against `dev` also carries
that branch's ~11 preceding Hexclave-rename commits (config-file rename,
env-var dual-read, AI setup-prompt rebrand). If those should land
separately, re-parent before merge.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Finishes the internal Stack Auth → Hexclave rename and cleans up
remaining stragglers, including dev-tool and prompt copy. All changes
are internal-only; public/wire APIs remain unchanged. Re-merged `dev`
and resolved the payments create-purchase-url conflict.

- **Refactors**
- Internal symbols: stack*/Stack* → hexclave*/Hexclave* (e.g.,
`getHexclaveServerApp` via `@/hexclave`, `getHexclaveStripe`,
`hexclaveAppInternalsSymbol`, `hexclaveSchemaInfo`, Prisma
`__hexclave_*`, `data-hexclave-handler-page`, Stripe mock
`hexclavePortPrefix`).
- Files/dirs: moved to `lib/hexclave-app`; handler route
`[...hexclave]`; backend entry `src/hexclave.tsx`; dashboard internals
`hexclave-app-internals`; companion `hexclave-companion`; dropped
`stack-` prefix across package dirs
(`packages/{shared,ui,sc,cli,next}`); workflows/emulator paths now
`packages/cli`; Quetzal codegen env at `packages/next/.env.local`.
- Packages/docs: `@stackframe/template` → `@hexclave/template`; removed
`packages/init-stack`; regenerated OpenAPI and updated docs
slugs/redirects for hexclave-app/use-hexclave-app.
- Brand strings/prompts: reworded remaining “Stack” dashboard strings to
Hexclave; updated dev-tool copy and prompts; `doctor/init` now prefer
`hexclave.config.ts`. Kept all wire-compat identifiers and public
aliases (`x-stack-*`, `stack-*` cookies, `STACK_*` env,
`*.stack-auth.com`, `Stack*` SDK names).
- Rebased/merged onto latest `dev`: retained `@hexclave/template`, kept
`src` in published files, refreshed setup-prompt imports and docs JSON,
adopted 1.0.5 version bumps, and re-merged `dev` again (resolved
`create-purchase-url` with `getHexclaveStripe`).

- **Bug Fixes**
- Restored dashboard AI type bundle by pointing the glob to
`packages/template/src/lib/hexclave-app`.
- Addressed rename leftovers: updated lingering `@/stack` imports and
CSS selector, fixed schema/meta and port-prefix expansions, and aligned
emulator commands to `packages/cli`.
- CI/build: removed a dead env var and stale ignore entries; fixed
Docker by renaming `STACK_SKIP_TEMPLATE_GENERATION` →
`HEXCLAVE_SKIP_TEMPLATE_GENERATION`.

<sup>Written for commit 3c1af3bff3.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/hexclave/hexclave/pull/1547?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
2026-06-03 18:57:09 -07:00

459 lines
15 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<title>Hexclave Dev Launchpad</title>
<link rel="icon" href="./favicon.svg" type="image/svg+xml" />
<script src="./env-config.js"></script>
<style>
body {
font-family: Arial, sans-serif;
background-color: #e0f0e0;
padding-left: 16px;
padding-right: 16px;
}
.apps-container {
display: flex;
flex-direction: row;
flex-wrap: wrap;
gap: 16px;
}
.apps-container > a {
border: 1px solid #8888;
background-color: #fff;
padding: 0px 4px 8px 4px;
width: 120px;
text-decoration: none;
display: flex;
flex-direction: column;
align-items: center;
gap: 12px;
position: relative;
}
.apps-container > a.important {
background-color: #fee;
}
.apps-container > a.unimportant {
opacity: 0.2;
}
.apps-container > a.unimportant:hover {
opacity: 0.5;
}
.apps-container > a:hover {
border-color: #888;
transition: opacity 0.1s ease-in-out;
}
.apps-container > a > div > img {
height: 68px;
}
.apps-container > a > .description {
text-align: center;
font-size: 12px;
color: #888;
}
.apps-container > a > .port {
padding-right: 0.5px;
padding-top: 1px;
align-self: flex-end;
font-size: 12px;
color: #888;
}
.apps-container > a > .hover-description {
display: none;
position: absolute;
top: 100%;
left: -1px;
pointer-events: none;
z-index: 1000;
white-space: pre;
background-color: #ffc;
border: 1px solid #888;
padding: 2px;
color: #0008;
font-size: 12px;
}
.apps-container > a:hover > .hover-description {
display: block;
}
</style>
</head>
<body>
<h1>Hexclave Dev Launchpad</h1>
<div class="apps-container"></div>
<hr />
<div class="apps-container"></div>
<hr />
<div class="apps-container"></div>
<h2 style="margin-top: 64px;">Background services</h2>
<ul class="background-services"></ul>
<noscript>
This page requires JavaScript.
</noscript>
<script>
const derivePrefixFromLocation = () => {
const port = window.location.port;
if (!port || port.length < 2) return "81";
return port.slice(0, -2);
};
const hexclavePortPrefix = window.NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX || derivePrefixFromLocation();
window.NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX = hexclavePortPrefix;
const withPrefix = (suffix) => `${hexclavePortPrefix}${suffix}`;
// Depending on the port prefix, set the color to light grey (port 91), light purple (port 92), papyrus yellow (port 93), or default otherwise
const color = {
"91": "#f8f8f8",
"92": "#fff8e0",
"93": "#e0e0ff",
}[hexclavePortPrefix] || undefined;
document.body.style.backgroundColor = color;
const backgroundServices = [
{ suffix: "28", label: "PostgreSQL" },
{ suffix: "34", label: "PostgreSQL Replica (with replication lag)" },
{ suffix: "29", label: "Inbucket SMTP" },
{ suffix: "30", label: "Inbucket POP3" },
{ suffix: "31", label: "OTel collector" },
{ suffix: "21", label: "S3 mock" },
{ suffix: "22", label: "Freestyle mock" },
{ suffix: "23", label: "Stripe mock" },
{ suffix: "24", label: "LocalStack Gateway (AWS mock)" },
{ suffix: "25", label: "QStash mock" },
{ suffix: "37", label: "ClickHouse native interface" },
{ suffix: "39", label: "SpacetimeDB (MCP call log)" },
{ range: ["50", "99"], label: "Reserved for LocalStack (external services)" },
];
const backgroundList = document.querySelector(".background-services");
backgroundList.innerHTML = backgroundServices.map((service) => {
const portText = service.range
? `${withPrefix(service.range[0])}-${withPrefix(service.range[1])}`
: withPrefix(service.suffix);
return `<li>${portText}: ${service.label}</li>`;
}).join("");
const apps = [
{
name: "Dashboard",
portSuffix: "01",
description: [
"Src: ./apps/dashboard",
"Prod: https://app.hexclave.com",
],
img: "https://www.svgrepo.com/show/507260/dashboard.svg",
importance: 2,
},
{
name: "Backend",
portSuffix: "02",
description: [
"Src: ./apps/backend",
"Prod: https://api.hexclave.com",
],
img: "https://www.svgrepo.com/show/340122/datastore.svg",
importance: 2,
},
{
name: "MCP",
portSuffix: "44",
description: [
"Src: ./apps/mcp",
"Prod: https://mcp.hexclave.com/mcp",
],
importance: 2,
},
{
name: "Skills",
portSuffix: "45",
description: [
"Src: ./apps/skills",
"Prod: https://skill.hexclave.com",
],
importance: 2,
},
{
name: "Demo app",
portSuffix: "03",
description: [
"Src: ./examples/demo",
"Prod: https://demo.hexclave.com",
],
importance: 2,
},
{
name: "Demo app — Local dev environment",
portSuffix: "42",
description: [
"Src: ./examples/demo",
"Prod: https://demo.hexclave.com",
],
importance: 2,
},
{
name: "TanStack Start demo",
portSuffix: "43",
description: [
"Src: ./examples/tanstack-start-demo",
"Alpha SDK integration demo",
],
img: "https://tanstack.com/favicon.ico",
importance: 2,
},
{
name: "Docs",
portSuffix: "26",
description: [
"Src: ./docs",
"Prod: https://docs.hexclave.com",
],
img: "https://www.svgrepo.com/show/448400/docs.svg",
importance: 2,
},
{
name: "Mintlify docs",
portSuffix: "04",
description: [
"Src: ./docs-mintlify",
],
img: "https://www.svgrepo.com/show/448400/docs.svg",
importance: 2,
},
{
name: "Hosted Components",
portSuffix: "09",
description: [
"Src: ./apps/hosted-components",
],
importance: 2,
},
{
name: "Inbucket",
portSuffix: "05",
img: "https://www.svgrepo.com/show/533176/at-sign.svg",
importance: 1,
description: [
"Email mock",
],
},
{
name: "Prisma Studio",
portSuffix: "06",
importance: 1,
img: "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcS95TdAw63YPAPcUpvRl4imIf-VJ1sGHnEvbw&s",
description: [
"Database interface",
],
},
{
name: "Jaeger UI (OTel)",
portSuffix: "07",
description: [
"Performance & tracing",
],
importance: 1,
img: "https://www.jaegertracing.io/img/jaeger-icon-reverse-color.svg",
},
{
name: "examples/docs-examples",
portSuffix: "08",
description: [
"Src: ./examples/docs-examples",
],
},
{
name: "examples/cjs-test",
portSuffix: "10",
description: [
"Src: ./examples/cjs-test",
],
},
{
name: "examples/e-commerce",
portSuffix: "11",
description: [
"Src: ./examples/e-commerce",
],
},
{
name: "examples/middleware",
portSuffix: "12",
description: [
"Src: ./examples/middleware",
],
},
{
name: "Svix server",
portSuffix: "13",
importance: 1,
img: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBpZD0iTGF5ZXJfMiIgZGF0YS1uYW1lPSJMYXllciAyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgdmlld0JveD0iODQuOSA4NC45IDM0NyAzNDciPgogIDxkZWZzPgogICAgPHN0eWxlPgogICAgICAuY2xzLTEgewogICAgICAgIGZpbGw6ICNmZmY7CiAgICAgIH0KCiAgICAgIC5jbHMtMSwgLmNscy0yIHsKICAgICAgICBzdHJva2Utd2lkdGg6IDBweDsKICAgICAgfQoKICAgICAgLmNscy0yIHsKICAgICAgICBmaWxsOiAjMmM3MGZmOwogICAgICB9CiAgICA8L3N0eWxlPgogIDwvZGVmcz4KICA8ZyBpZD0iTGF5ZXJfMS0yIiBkYXRhLW5hbWU9IkxheWVyIDEtMiI+CiAgICA8Y2lyY2xlIGNsYXNzPSJjbHMtMSIgY3g9IjI1OC40IiBjeT0iMjU4LjQiIHI9IjE3My41Ii8+CiAgICA8Zz4KICAgICAgPHBhdGggY2xhc3M9ImNscy0yIiBkPSJNMzYwLjgsMjMyLjljLTI4LjgtMS40LTU1LjctMTcuMi02OC4yLTQ1LTUuNS0xMi4zLTE3LjgtMjAuNC0zMS4zLTIwLjgtMjguNi0uOC00Ni43LDM1LjEtMjguNyw1Ny42LDYuMiw3LjgsMTUuNCwxMi4xLDI3LjUsMTIuOWgwYzIzLjQsMS43LDQzLjUsMTEuOCw1Ni44LDI4LjUsMjQuNCwzMC43LDIwLjksNzcuMS03LjQsMTA0LTM0LjEsMzIuNS05MS4xLDI1LjgtMTE3LjEtMTMuMi0yLjMtMy41LTQuMy03LjEtNi4xLTEwLjktNS41LTEyLjMtMTcuOC0yMC40LTMxLjMtMjAuOC0xMy45LS40LTI3LDQuOS0zNS4zLDEzLjgsMjcuMyw0Ni45LDc3LjcsNzguNywxMzUuOSw3OS43LDg4LjYsMS41LDE2MS43LTY5LDE2My4yLTE1Ny42LjMtMTQuOS0xLjYtMjkuNC01LjEtNDMuMi43LDIuOS0yMi4zLDEwLjktMjQuOCwxMS42LTkuMiwyLjctMTguNywzLjctMjgsMy4zaDBaIi8+CiAgICAgIDxwYXRoIGNsYXNzPSJjbHMtMiIgZD0iTTE1NiwyODMuNmMyOS40LjcsNTYuMSwxOC41LDY4LjIsNDUuMyw1LjUsMTIuMywxNy44LDIwLjQsMzEuMywyMC44LDkuNC4zLDE4LjMtMy4yLDI1LjItOS43LDEyLjgtMTIuMSwxNC41LTM0LjEsMy41LTQ4LTYuMi03LjgtMTUuNC0xMi4xLTI3LjUtMTIuOWgwYy0yMy40LTEuNy00My41LTExLjgtNTYuOC0yOC41LTI5LjYtMzcuMi0xNy05Mi41LDIzLjctMTE1LjQsMTEuOC02LjYsMjUuMi0xMC4yLDM4LjctOS44LDI5LjQuNyw1Ni4xLDE4LjUsNjguMiw0NS4zLDUuNSwxMi4zLDE3LjgsMjAuNCwzMS4zLDIwLjgsMTQsLjQsMjctNC45LDM1LjMtMTMuOC0yNy4zLTQ2LjktNzcuNy03OC43LTEzNS45LTc5LjgtODguNi0xLjUtMTYxLjYsNjkuMS0xNjMuMiwxNTcuNi0uMywxNC45LDEuNiwyOS40LDUuMiw0My4yLDE0LjktMTAuMSwzMy4zLTE1LjYsNTIuOS0xNS4yaDBaIi8+CiAgICA8L2c+CiAgPC9nPgo8L3N2Zz4=",
description: [
"Webhooks",
],
},
{
name: "OAuth mock server",
portSuffix: "14",
description: [
"Src: ./apps/mock-oauth-server",
],
},
{
name: "examples/supabase",
portSuffix: "15",
description: [
"Src: ./examples/supabase",
],
},
{
name: "PgHero",
portSuffix: "16",
description: [
"For database performance analysis",
],
importance: 1,
img: "https://pghero.dokkuapp.com/assets/pghero-88a0d052.png",
},
{
name: "PgHero (Replica)",
portSuffix: "35",
description: [
"For replica database performance analysis",
],
importance: 1,
img: "https://pghero.dokkuapp.com/assets/pghero-88a0d052.png",
},
{
name: "PgAdmin",
portSuffix: "17",
description: [
"For database administration",
],
importance: 1,
img: "https://www.w3schools.com/postgresql/screenshot_postgresql_pgadmin4_6.png",
},
{
name: "Supabase Studio",
portSuffix: "18",
path: "/project/default/editor",
description: [
"For database administration",
],
importance: 1,
img: "https://cdn.prod.website-files.com/655b60964be1a1b36c746790/655b60964be1a1b36c746d41_646dfce3b9c4849f6e401bff_supabase-logo-icon_1.png",
},
{
name: "Drizzle Gateway",
portSuffix: "33",
description: [
"Manage Drizzle configs",
],
importance: 1,
},
{
name: "WAL Info",
portSuffix: "38",
description: [
"Replication & WAL monitoring",
"Tracks primary/replica LSN positions",
"Decodes WAL to SQL statements",
],
importance: 1,
img: "https://www.svgrepo.com/show/374002/replication.svg",
},
{
name: "Internal Tool",
portSuffix: "41",
description: [
"Src: ./apps/internal-tool",
"MCP call review tool",
],
importance: 1,
},
{
name: "Bulldozer Studio",
portSuffix: "40",
description: [
"Bulldozer table graph and editor",
"Includes raw storage debug browser",
],
importance: 1,
img: "https://www.svgrepo.com/show/349299/database.svg",
},
{
name: "JS example",
portSuffix: "19",
description: [
"JavaScript example",
],
},
{
name: "React example",
portSuffix: "20",
description: [
"React example",
],
},
{
name: "ClickHouse HTTP",
portSuffix: "36",
description: [
"ClickHouse",
],
importance: 1,
img: "https://thumbs.bfldr.com/at/qkjfv3nvsv4rbwn94zmtb4t/v/1197417003?expiry=1764357242&fit=bounds&height=800&sig=NjEwNzA0OThjZmJiZDQzZmUwNjIyY2UxYzZiNGYxNmQ3NjJiYjc0OA%3D%3D&width=1100",
},
{
name: "Convex example",
portSuffix: "27",
importance: 0,
description: [
"Convex example",
],
},
{
name: "Lovable React 18 example",
portSuffix: "32",
importance: 0,
description: [
"Lovable React 18 example",
],
},
];
const appsContainers = document.querySelectorAll(".apps-container");
for (let i = 0; i < appsContainers.length; i++) {
const appContainer = appsContainers[i];
const importance = appsContainers.length - i - 1;
for (const app of apps) {
if ((app.importance ?? 0) === importance) {
// TODO escape HTML
appContainer.innerHTML += `
<a href="http://${app.portSuffix === "42" ? "127.0.0.1" : (`${hexclavePortPrefix}` === "81" ? "localhost" : `p${hexclavePortPrefix}.localhost`)}:${withPrefix(app.portSuffix)}${app.path ?? ""}" target="_blank" rel="noopener noreferrer" class="${app.importance === 2 ? "important" : app.importance === 1 ? "" : "unimportant"}">
<div class="port">:${withPrefix(app.portSuffix)}</div>
<div>
<img src=${app.img || `//localhost:${withPrefix(app.portSuffix)}/favicon.ico`} />
</div>
<span class="description">${app.name}</span>
${app.description ? `<div class="hover-description">${app.description.join("\n")}</div>` : ""}
</a>
`;
}
}
}
</script>
</body>
</html>