mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-10-03 02:24:33 +00:00
SandboxProviderKind is now a validated string newtype instead of a closed enum. The bundled kinds (local, docker, daytona) keep their constants and a BundledProvider enum for the code paths that still dispatch on them; any other well-formed sandbox-driver kind name is accepted and names a plugin executable. EnvironmentProvider is gone: environment settings carry SandboxProviderKind directly, and is_clone_based is replaced by a workspace policy where local runs in a designated directory and every other provider clones. Server sandbox policy is keyed by kind. [server.sandbox.providers.<kind>] accepts the bundled kinds with `enabled` and any plugin kind with its launch settings (path, sha256, dev, args, env, inherit_env); bundled kinds reject the plugin keys and a kind with no entry is disabled. The OpenAPI schema, generated Rust and TypeScript clients, web settings pages, and docs follow. The environments table drops its provider CHECK enumeration in favour of the kind name rules so a plugin environment can be stored. Bundled-only code paths (run start, preflight, reconnect, terminal, details) now fail with an explicit message for a plugin kind until the driver construction function lands in the next step. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
46 lines
2 KiB
TypeScript
46 lines
2 KiB
TypeScript
import type { Environment, ServerSandboxProviderSettings } from "@qltysh/fabro-api-client";
|
|
|
|
// The providers linked into the server. Any other provider kind names a
|
|
// sandbox-driver plugin the operator configured under
|
|
// `server.sandbox.providers.<kind>`.
|
|
export const LOCAL_PROVIDER = "local";
|
|
export const DOCKER_PROVIDER = "docker";
|
|
export const DAYTONA_PROVIDER = "daytona";
|
|
|
|
export const BUNDLED_PROVIDERS = [LOCAL_PROVIDER, DOCKER_PROVIDER, DAYTONA_PROVIDER] as const;
|
|
|
|
export type ProviderSettingsMap = { [kind: string]: ServerSandboxProviderSettings };
|
|
|
|
// `local` runs in the caller's directory and never clones. Every other
|
|
// provider owns an isolated workspace that Fabro clones into.
|
|
export function isCloneBasedProvider(provider: string): boolean {
|
|
return provider !== LOCAL_PROVIDER;
|
|
}
|
|
|
|
// Whether a server-managed environment can back Git-targeted work such as
|
|
// automations: only clone-based providers qualify.
|
|
export function isCloneBasedEnvironment(environment: Environment): boolean {
|
|
return isCloneBasedProvider(environment.provider);
|
|
}
|
|
|
|
// Providers a managed environment can be created with: every enabled
|
|
// clone-based provider. `local` is a reserved, in-memory environment, never a
|
|
// managed-environment provider, so it is never offered.
|
|
export function creatableProviders(providers: ProviderSettingsMap): string[] {
|
|
return Object.keys(providers)
|
|
.filter((kind) => isCloneBasedProvider(kind) && providers[kind]?.enabled)
|
|
.sort(compareProviderKinds);
|
|
}
|
|
|
|
// Bundled kinds first, in their canonical order, then plugins alphabetically.
|
|
export function compareProviderKinds(left: string, right: string): number {
|
|
const rank = (kind: string) => {
|
|
const index = (BUNDLED_PROVIDERS as readonly string[]).indexOf(kind);
|
|
return index === -1 ? BUNDLED_PROVIDERS.length : index;
|
|
};
|
|
return rank(left) - rank(right) || left.localeCompare(right);
|
|
}
|
|
|
|
export function providerLabel(provider: string): string {
|
|
return provider.charAt(0).toUpperCase() + provider.slice(1);
|
|
}
|