Explorar el Código

feat: add workspace

Thomas Zhang hace 3 meses
padre
commit
dd6383da0d

+ 4 - 0
src/app.d.ts

@@ -1,4 +1,6 @@
 // See https://svelte.dev/docs/kit/types#app.d.ts
+import type { Workspace } from '$lib/types/workspace';
+
 // for information about these interfaces
 declare global {
 	namespace App {
@@ -10,6 +12,8 @@ declare global {
 		}
 		interface Locals {
 			requestId: string;
+			workspaceId: string | null;
+			workspace: Workspace | undefined;
 		}
 		// interface PageData {}
 		// interface PageState {}

+ 22 - 0
src/hooks.server.ts

@@ -2,14 +2,20 @@ import crypto from 'node:crypto';
 
 import type { Handle, HandleServerError } from '@sveltejs/kit';
 
+import { resolve } from '$app/paths';
+
 import {
 	isAppError,
 	logger as rootLogger,
+	NotFoundError,
 	runWithContext,
 	server,
 	serverLogger as log,
+	ValidationError,
 } from '$lib/server';
 
+const WORKSPACE_RESOURCES = resolve('/api/workspaces');
+
 const ready = server.init();
 
 const shutdown = async (signal: string) => {
@@ -29,6 +35,22 @@ const handle: Handle = async ({ event, resolve: resolveRequest }) => {
 	event.locals.requestId = requestId;
 
 	return runWithContext({ requestId }, async () => {
+		const { pathname } = event.url;
+		if (pathname.startsWith(WORKSPACE_RESOURCES) && pathname !== WORKSPACE_RESOURCES) {
+			const workspaceId = event.params.workspaceId;
+			if (workspaceId === undefined) {
+				throw new ValidationError('Workspace ID is required');
+			}
+			const workspace = server.ws.list().find((ws) => ws.id === workspaceId);
+			if (!workspace) {
+				throw new NotFoundError('Workspace not found');
+			}
+			event.locals.workspaceId = workspaceId;
+			event.locals.workspace = workspace;
+		} else {
+			event.locals.workspaceId = event.cookies.get('workspaceId') || null;
+		}
+
 		return resolveRequest(event);
 	});
 };

+ 16 - 0
src/lib/server/server.ts

@@ -1,18 +1,34 @@
 import { serverLogger as log } from '$lib/server/logger';
 
+import { WorkspaceManager } from './workspace';
+
 class Server {
 	// Guards against double-init in HMR / test environments.
 	#initialized = false;
 
+	#ws!: WorkspaceManager;
+
 	async init(): Promise<void> {
 		if (this.#initialized) return;
 		this.#initialized = true;
 		log.info('Server initializing');
 
+		await this.#createWorkspaceManager();
+
 		log.info('Server ready');
 	}
 
 	async shutdown(): Promise<void> {}
+
+	async #createWorkspaceManager(): Promise<void> {
+		const ws = new WorkspaceManager();
+		await ws.init();
+		this.#ws = ws;
+	}
+
+	get ws(): WorkspaceManager {
+		return this.#ws;
+	}
 }
 
 // Singleton shared across hooks and route handlers.

+ 37 - 0
src/lib/server/workspace.ts

@@ -0,0 +1,37 @@
+import type { Workspace } from '$lib/types/workspace';
+
+import { env } from '$env/dynamic/private';
+
+class WorkspaceManager {
+	#workspaces: Workspace[] = [];
+
+	async init(): Promise<void> {
+		this.#workspaces = await this.#loadWorkspaces();
+	}
+
+	async #loadWorkspaces(): Promise<Workspace[]> {
+		return [
+			{
+				id: 'default',
+				displayName: 'Default Workspace',
+				persistence: {
+					type: 'local',
+					directory: env.WS_LOCAL_GIT_DIR || '.',
+					authorName: env.WS_LOCAL_GIT_AUTHOR_NAME || 'LocoStack',
+					authorEmail: env.WS_LOCAL_GIT_AUTHOR_EMAIL || 'local@locostack.com',
+					branch: undefined,
+				},
+				deployment: {
+					type: 'k8s',
+					namespace: 'locostack',
+				},
+			},
+		];
+	}
+
+	list(): Workspace[] {
+		return this.#workspaces;
+	}
+}
+
+export { WorkspaceManager };

+ 43 - 0
src/lib/types/workspace.ts

@@ -0,0 +1,43 @@
+type Workspace = {
+	id: string;
+	displayName: string;
+	persistence: WorkspacePersistence;
+	deployment: WorkspaceDeployment;
+};
+
+type WorkspacePersistence = (
+	| {
+			type: 'git';
+			repoUrl: string;
+			branch: string;
+	  }
+	| {
+			type: 'local';
+			directory: string;
+			authorEmail: string;
+			authorName: string;
+			branch: undefined;
+	  }
+) & {
+	modelsDirectory?: string;
+	modelClassesDirectory?: string;
+	toolsDirectory?: string;
+	kbsDirectory?: string;
+	kbClassesDirectory?: string;
+	agentsDirectory?: string;
+	agentClassesDirectory?: string;
+};
+
+type WorkspaceDeployment =
+	| {
+			type: 'k8s';
+			namespace: string;
+			apiUrl?: string;
+			token?: string;
+			skipTlsVerify?: boolean;
+	  }
+	| {
+			type: 'local';
+	  };
+
+export type { Workspace, WorkspaceDeployment,WorkspacePersistence };

+ 0 - 0
src/routes/api/workspaces/+server.ts