feat: update .gitignore, remove unused API interfaces, and add local dev scripts for bootstrap and seeding connections

This commit is contained in:
2026-07-13 23:13:16 +08:00
parent b1ddf32238
commit 3ae0cc3e60
8 changed files with 166 additions and 204 deletions
+76
View File
@@ -0,0 +1,76 @@
/**
* Local dev bootstrap for an Alpha Silo on Windows / non-systemd hosts.
*
* The production bootstrap-silo CLI is Linux-only (requires root uid 0,
* systemctl, root-owned files). This script calls the same
* `bootstrapAlphaSilo` invariants directly, sourcing credentials from the
* local `.env` and the dev keyring. Idempotent: re-running is a no-op once
* the Silo Organization exists.
*
* Usage: npx tsx scripts/dev-bootstrap-silo.ts
*/
import "dotenv/config";
import { PrismaClient } from "@prisma/client";
import { bootstrapAlphaSilo } from "../src/deployment/bootstrap-silo.js";
import { loadLocalSecretKeyring, LocalSecretEnvelope } from "../src/security/secretEnvelope.js";
function requiredEnv(name: string): string {
const v = process.env[name]?.trim();
if (v === undefined || v === "") throw new Error(`missing required env: ${name}`);
return v;
}
async function main(): Promise<void> {
const databaseUrl = requiredEnv("DATABASE_URL");
const keyring = await loadLocalSecretKeyring();
const secrets = new LocalSecretEnvelope(keyring);
const prisma = new PrismaClient({ datasources: { db: { url: databaseUrl } }, log: [] });
const organizationId = requiredEnv("HUB_SILO_ORGANIZATION_ID");
const feishuAppId = requiredEnv("FEISHU_APP_ID");
const feishuAppSecret = requiredEnv("FEISHU_APP_SECRET");
const feishuBotOpenId = requiredEnv("FEISHU_BOT_OPEN_ID");
const providerAuthToken = requiredEnv("ANTHROPIC_AUTH_TOKEN");
const providerBaseUrl = process.env["ANTHROPIC_BASE_URL"]?.trim() || "https://openrouter.ai/api";
const anthropicApiKey = process.env["ANTHROPIC_API_KEY"]?.trim() || "";
try {
const result = await bootstrapAlphaSilo(
prisma,
secrets,
{
organization: {
id: organizationId,
slug: "local-dev",
name: "Local Dev Silo",
},
owner: {
openId: feishuBotOpenId,
displayName: "Local Dev Owner",
},
feishu: {
appId: feishuAppId,
appSecret: feishuAppSecret,
botOpenId: feishuBotOpenId,
},
provider: {
providerId: "openrouter",
baseUrl: providerBaseUrl,
authToken: providerAuthToken,
...(anthropicApiKey !== "" ? { anthropicApiKey } : {}),
},
},
// Skip live network probes in local dev — Feishu/OpenRouter reachability
// is not required to seed the encrypted envelope rows.
{ feishu: async () => {}, provider: async () => {} },
);
console.log("bootstrap result:", JSON.stringify(result, null, 2));
} finally {
await prisma.$disconnect();
}
}
main().catch((error: unknown) => {
console.error("[dev-bootstrap-silo] failed:", error instanceof Error ? error.message : String(error));
process.exitCode = 1;
});
+84
View File
@@ -0,0 +1,84 @@
/**
* Local dev seed for an existing Organization that predates the ADR-0024
* secret-envelope plane (e.g. the legacy `org_default` from the tenant-root
* migration). Creates ACTIVE Feishu Application + Provider (BYOK openrouter)
* connections with encrypted envelopes, using the local dev keyring.
*
* Idempotent: re-running rotates a new secret version if the connection
* already exists.
*
* Usage: npx tsx scripts/dev-seed-connections.ts
*/
import "dotenv/config";
import { PrismaClient } from "@prisma/client";
import { FeishuApplicationConnectionService } from "../src/connections/feishuApplicationConnections.js";
import { ProviderConnectionService } from "../src/connections/providerConnections.js";
import { loadLocalSecretKeyring, LocalSecretEnvelope } from "../src/security/secretEnvelope.js";
function requiredEnv(name: string): string {
const v = process.env[name]?.trim();
if (v === undefined || v === "") throw new Error(`missing required env: ${name}`);
return v;
}
async function main(): Promise<void> {
const databaseUrl = requiredEnv("DATABASE_URL");
const organizationId = requiredEnv("HUB_SILO_ORGANIZATION_ID");
const keyring = await loadLocalSecretKeyring();
const secrets = new LocalSecretEnvelope(keyring);
const prisma = new PrismaClient({ datasources: { db: { url: databaseUrl } }, log: [] });
const feishuAppId = requiredEnv("FEISHU_APP_ID");
const feishuAppSecret = requiredEnv("FEISHU_APP_SECRET");
const feishuBotOpenId = requiredEnv("FEISHU_BOT_OPEN_ID");
const providerAuthToken = requiredEnv("ANTHROPIC_AUTH_TOKEN");
const providerBaseUrl = process.env["ANTHROPIC_BASE_URL"]?.trim() || "https://openrouter.ai/api";
const anthropicApiKey = process.env["ANTHROPIC_API_KEY"]?.trim() || "";
// Pick an existing active OWNER/ADMIN as the actor for the audit rows.
const actor = await prisma.organizationMembership.findFirst({
where: { organizationId, role: { in: ["OWNER", "ADMIN"] }, revokedAt: null },
select: { userId: true },
});
if (actor === null) throw new Error(`no active OWNER/ADMIN membership on ${organizationId}; seed a member first`);
const actorUserId = actor.userId;
console.log("actor:", actorUserId);
try {
const feishuService = new FeishuApplicationConnectionService(
prisma,
secrets,
async () => {}, // skip live Feishu probe in local dev
);
const feishuResult = await feishuService.rotateCustomerApplication({
organizationId,
actorUserId,
appId: feishuAppId,
appSecret: feishuAppSecret,
botOpenId: feishuBotOpenId,
});
console.log("feishu connection:", JSON.stringify(feishuResult, null, 2));
const providerService = new ProviderConnectionService(
prisma,
secrets,
async () => {}, // skip live OpenRouter probe in local dev
);
const providerResult = await providerService.rotateByok({
organizationId,
actorUserId,
providerId: "openrouter",
baseUrl: providerBaseUrl,
authToken: providerAuthToken,
...(anthropicApiKey !== "" ? { anthropicApiKey } : {}),
});
console.log("provider connection:", JSON.stringify(providerResult, null, 2));
} finally {
await prisma.$disconnect();
}
}
main().catch((error: unknown) => {
console.error("[dev-seed-connections] failed:", error instanceof Error ? error.message : String(error));
process.exitCode = 1;
});