diff --git a/hub/admin-web/src/lib/components/Icon.svelte b/hub/admin-web/src/lib/components/Icon.svelte index f51370c..7f6ca06 100644 --- a/hub/admin-web/src/lib/components/Icon.svelte +++ b/hub/admin-web/src/lib/components/Icon.svelte @@ -11,11 +11,12 @@ | 'projects' | 'provider' | 'feishu' - | 'menu' - | 'logout' - | 'org' - | 'chevron' - | 'folder' + | 'menu' + | 'logout' + | 'org' + | 'chevron' + | 'arrow-left' + | 'folder' | 'file' | 'check'; class?: string; @@ -100,6 +101,14 @@ +{:else if name === 'arrow-left'} + + + {:else if name === 'folder'} - ← 返回项目列表 + + 返回项目列表 diff --git a/hub/admin-web/vite.config.ts b/hub/admin-web/vite.config.ts index 6134e79..90d4bb4 100644 --- a/hub/admin-web/vite.config.ts +++ b/hub/admin-web/vite.config.ts @@ -8,6 +8,10 @@ export default defineConfig({ proxy: { '/api': 'http://127.0.0.1:8788', '/auth': 'http://127.0.0.1:8788', + // Backend owns /admin/login (registered before the SPA fallback in + // src/admin/static.ts). Proxy it in dev so the SPA doesn't re-render + // its layout on that path and 401-redirect into a returnTo loop. + '/admin/login': 'http://127.0.0.1:8788', }, }, }); diff --git a/hub/scripts/dev-bootstrap.ts b/hub/scripts/dev-bootstrap.ts new file mode 100644 index 0000000..58a21d9 --- /dev/null +++ b/hub/scripts/dev-bootstrap.ts @@ -0,0 +1,52 @@ +import { config } from "dotenv"; +config(); + +import { PrismaClient } from "@prisma/client"; +import { bootstrapAlphaSilo } from "../src/deployment/bootstrap-silo.js"; +import { loadLocalSecretKeyring, LocalSecretEnvelope } from "../src/security/secretEnvelope.js"; + +async function main(): Promise { + const keyringFile = process.env["HUB_SECRET_KEYRING_FILE"]; + if (!keyringFile) throw new Error("HUB_SECRET_KEYRING_FILE is required"); + const secrets = new LocalSecretEnvelope(await loadLocalSecretKeyring()); + const prisma = new PrismaClient(); + try { + const result = await bootstrapAlphaSilo( + prisma, + secrets, + { + organization: { + id: "org_default", + slug: "default", + name: "Default Organization", + }, + owner: { + openId: process.env["FEISHU_BOT_OPEN_ID"] ?? "dev-owner", + displayName: "Dev Owner", + }, + feishu: { + appId: process.env["FEISHU_APP_ID"] ?? "dev-app", + appSecret: process.env["FEISHU_APP_SECRET"] ?? "dev-secret", + botOpenId: process.env["FEISHU_BOT_OPEN_ID"] ?? "dev-bot", + }, + provider: { + providerId: "openrouter", + baseUrl: process.env["ANTHROPIC_BASE_URL"] ?? "https://openrouter.ai/api", + authToken: process.env["ANTHROPIC_AUTH_TOKEN"] ?? "dev-token", + }, + }, + { + feishu: async () => undefined, + provider: async () => undefined, + }, + ); + console.log("bootstrap ok:", JSON.stringify(result, null, 2)); + } finally { + await prisma.$disconnect(); + } +} + +main().catch((error: unknown) => { + console.error("[dev-bootstrap] failed:", error instanceof Error ? error.message : String(error)); + process.exitCode = 1; +});