diff --git a/artifacts/sandbox-ai/src/App.tsx b/artifacts/sandbox-ai/src/App.tsx
index 3feaa26..dd2dc8c 100644
--- a/artifacts/sandbox-ai/src/App.tsx
+++ b/artifacts/sandbox-ai/src/App.tsx
@@ -28,6 +28,34 @@ const queryClient = new QueryClient();
const clerkPubKey = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY;
const clerkProxyUrl = import.meta.env.VITE_CLERK_PROXY_URL;
const basePath = import.meta.env.BASE_URL.replace(/\/$/, "");
+const requestedAuthMode = (import.meta.env.VITE_AUTH_MODE ?? "clerk").toLowerCase();
+const authMode = requestedAuthMode === "public" ? "public" : "clerk";
+const isClerkConfigured = Boolean(clerkPubKey);
+const isAuthEnabled = authMode === "clerk" && isClerkConfigured;
+
+const envChecklist = [
+ {
+ key: "VITE_AUTH_MODE",
+ value: import.meta.env.VITE_AUTH_MODE,
+ required: false,
+ status: "info" as const,
+ hint: "Optional. Use 'clerk' (default) or 'public'.",
+ },
+ {
+ key: "VITE_CLERK_PUBLISHABLE_KEY",
+ value: clerkPubKey,
+ required: authMode === "clerk",
+ status: isClerkConfigured ? ("ok" as const) : ("missing" as const),
+ hint: "Required when VITE_AUTH_MODE=clerk.",
+ },
+ {
+ key: "VITE_CLERK_PROXY_URL",
+ value: clerkProxyUrl,
+ required: false,
+ status: "info" as const,
+ hint: "Optional proxy URL for Clerk.",
+ },
+];
function stripBase(path: string): string {
return basePath && path.startsWith(basePath)
@@ -198,6 +226,33 @@ function ClerkAuthTokenSetter() {
return null;
}
+
+function HealthConfigPage() {
+ return (
+
+
Health Config
+
+ Runtime auth mode: {authMode}. Auth enabled: {String(isAuthEnabled)}.
+
+
+ {envChecklist.map((item) => (
+
+
+ {item.key}
+
+ {item.status === "ok" ? "✅ configured" : item.status === "missing" ? "❌ missing" : "ℹ️ optional"}
+
+
+
required: {String(item.required)}
+
value: {item.value ? "set" : "empty"}
+
{item.hint}
+
+ ))}
+
+
+ );
+}
+
function Router() {
return (
@@ -207,6 +262,7 @@ function Router() {
+
@@ -258,14 +314,54 @@ function ClerkProviderWithRoutes() {
);
}
+
+function PublicOnlyRouter() {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+function PublicAppWithoutAuth() {
+ return (
+
+
+
+ Auth is running in public mode. Open /health-config to inspect environment readiness.
+
+
+
+
+
+ );
+}
function App() {
const [showSplash, setShowSplash] = useState(true);
- if (!clerkPubKey) {
+ if (!isAuthEnabled) {
return (
-
- Missing VITE_CLERK_PUBLISHABLE_KEY — please check environment variables.
-
+
+
+
);
}
diff --git a/docs_self_healing_process.md b/docs_self_healing_process.md
new file mode 100644
index 0000000..0403d9f
--- /dev/null
+++ b/docs_self_healing_process.md
@@ -0,0 +1,27 @@
+# Self-healing reminder workflow (OpenClaw/Eios style)
+
+## Goal
+Automatically remind maintainers when deployment-critical configuration or code artifacts are missing.
+
+## 1) Detect
+- On every deploy, open `/health-config` and validate required env keys.
+- On CI, run `pnpm --filter @workspace/sandbox-ai run build` and fail on errors.
+
+## 2) Classify
+- **Config missing** (e.g. `VITE_CLERK_PUBLISHABLE_KEY` when `VITE_AUTH_MODE=clerk`).
+- **Artifact missing** (route/page/module referenced but not found).
+- **Type/build breakage** (TypeScript/build errors).
+
+## 3) Notify owner
+- Config missing -> notify DevOps/release owner.
+- Artifact missing -> notify feature owner/repo maintainer.
+- Build/type breakage -> notify author of latest PR and reviewer.
+
+## 4) Auto-remediation checklist
+- If auth env missing in non-production: set `VITE_AUTH_MODE=public` as temporary fallback.
+- If auth env missing in production: block release and require secret injection.
+- If artifact missing: create placeholder file + TODO with owner and deadline.
+
+## 5) Prevent regressions
+- Add a PR checklist item: “Did you verify `/health-config` and auth mode behavior?”
+- Keep a short runbook for required variables per environment.