diff --git a/server/src/index.ts b/server/src/index.ts index 869961d1..caa6c39d 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -19,6 +19,7 @@ import { formatDatabaseBackupResult, runDatabaseBackup, authUsers, + agents, companies, companyMemberships, instanceUserRoles, @@ -28,7 +29,7 @@ import { createApp } from "./app.js"; import { loadConfig } from "./config.js"; import { logger } from "./middleware/logger.js"; import { setupLiveEventsWebSocketServer } from "./realtime/live-events-ws.js"; -import { heartbeatService, reconcilePersistedRuntimeServicesOnStartup, routineService } from "./services/index.js"; +import { agentService, heartbeatService, reconcilePersistedRuntimeServicesOnStartup, routineService } from "./services/index.js"; import { createStorageServiceFromConfig } from "./storage/index.js"; import { printStartupBanner } from "./startup-banner.js"; import { getBoardClaimWarningUrl, initializeBoardClaimChallenge } from "./board-claim.js"; @@ -243,6 +244,32 @@ export async function startServer(): Promise { } } + // [nexus] Backfill Generalist agent for existing workspaces that pre-date Phase 8 + async function ensureGeneralistAgents(db: any): Promise<{ backfilled: number }> { + const companyRows = await db.select({ id: companies.id }).from(companies); + let backfilled = 0; + for (const company of companyRows) { + const existing = await db + .select({ id: agents.id }) + .from(agents) + .where(and(eq(agents.companyId, company.id), eq(agents.role, "general"))) + .then((rows: Array<{ id: string }>) => rows[0] ?? null); + if (existing) continue; + const agentSvc = agentService(db); + await agentSvc.create(company.id, { + name: "Generalist", + role: "general", + adapterType: "claude_local", + adapterConfig: {}, + runtimeConfig: {}, + metadata: { pendingSkillGroups: ["Creative"], backfilled: true }, + }); + logger.info({ companyId: company.id }, "backfilled Generalist agent for existing workspace"); + backfilled++; + } + return { backfilled }; + } + let db; let embeddedPostgres: EmbeddedPostgresInstance | null = null; let embeddedPostgresStartedByThisProcess = false; @@ -459,6 +486,18 @@ export async function startServer(): Promise { if (config.deploymentMode === "local_trusted") { await ensureLocalTrustedBoardPrincipal(db as any); } + + // [nexus] Backfill Generalist agents for any workspace that pre-dates Phase 8 + void ensureGeneralistAgents(db as any) + .then((result) => { + if (result.backfilled > 0) { + logger.info({ backfilled: result.backfilled }, "backfilled Generalist agents for existing workspaces"); + } + }) + .catch((err) => { + logger.error({ err }, "failed to backfill Generalist agents"); + }); + if (config.deploymentMode === "authenticated") { const { createBetterAuthHandler,