import { Config, ConfigProvider, Context, Effect, Layer, Option } from "effect" import { ConfigService } from "@/effect/config-service" const bool = (name: string) => Config.boolean(name).pipe(Config.withDefault(false)) const positiveInteger = (name: string) => Config.number(name).pipe( Config.map((value) => (Number.isInteger(value) && value > 0 ? value : undefined)), Config.orElse(() => Config.succeed(undefined)), ) const experimental = bool("KIRINCODE_EXPERIMENTAL") const enabledByExperimental = (name: string) => Config.all({ experimental, enabled: Config.boolean(name).pipe(Config.option) }).pipe( Config.map((flags) => Option.getOrElse(flags.enabled, () => flags.experimental)), ) export class Service extends ConfigService.Service()("@kirincode/RuntimeFlags", { autoShare: bool("KIRINCODE_AUTO_SHARE"), pure: bool("KIRINCODE_PURE"), disableDefaultPlugins: bool("KIRINCODE_DISABLE_DEFAULT_PLUGINS"), disableEmbeddedWebUi: bool("KIRINCODE_DISABLE_EMBEDDED_WEB_UI"), disableExternalSkills: bool("KIRINCODE_DISABLE_EXTERNAL_SKILLS"), disableLspDownload: bool("KIRINCODE_DISABLE_LSP_DOWNLOAD"), disableClaudeCodePrompt: Config.all({ broad: bool("KIRINCODE_DISABLE_CLAUDE_CODE"), direct: bool("KIRINCODE_DISABLE_CLAUDE_CODE_PROMPT"), }).pipe(Config.map((flags) => flags.broad || flags.direct)), disableClaudeCodeSkills: Config.all({ broad: bool("KIRINCODE_DISABLE_CLAUDE_CODE"), direct: bool("KIRINCODE_DISABLE_CLAUDE_CODE_SKILLS"), }).pipe(Config.map((flags) => flags.broad || flags.direct)), enableExa: Config.all({ experimental, enabled: bool("KIRINCODE_ENABLE_EXA"), legacy: bool("KIRINCODE_EXPERIMENTAL_EXA"), }).pipe(Config.map((flags) => flags.experimental || flags.enabled || flags.legacy)), enableParallel: Config.all({ enabled: bool("KIRINCODE_ENABLE_PARALLEL"), legacy: bool("KIRINCODE_EXPERIMENTAL_PARALLEL"), }).pipe(Config.map((flags) => flags.enabled || flags.legacy)), enableExperimentalModels: bool("KIRINCODE_ENABLE_EXPERIMENTAL_MODELS"), enableQuestionTool: bool("KIRINCODE_ENABLE_QUESTION_TOOL"), experimentalReferences: enabledByExperimental("KIRINCODE_EXPERIMENTAL_REFERENCES"), experimentalBackgroundSubagents: enabledByExperimental("KIRINCODE_EXPERIMENTAL_BACKGROUND_SUBAGENTS"), experimentalLspTy: bool("KIRINCODE_EXPERIMENTAL_LSP_TY"), experimentalLspTool: enabledByExperimental("KIRINCODE_EXPERIMENTAL_LSP_TOOL"), experimentalOxfmt: enabledByExperimental("KIRINCODE_EXPERIMENTAL_OXFMT"), experimentalPlanMode: enabledByExperimental("KIRINCODE_EXPERIMENTAL_PLAN_MODE"), experimentalCodeMode: enabledByExperimental("KIRINCODE_EXPERIMENTAL_CODE_MODE"), experimentalEventSystem: enabledByExperimental("KIRINCODE_EXPERIMENTAL_EVENT_SYSTEM"), experimentalWorkspaces: enabledByExperimental("KIRINCODE_EXPERIMENTAL_WORKSPACES"), experimentalIconDiscovery: enabledByExperimental("KIRINCODE_EXPERIMENTAL_ICON_DISCOVERY"), outputTokenMax: positiveInteger("KIRINCODE_EXPERIMENTAL_OUTPUT_TOKEN_MAX"), bashDefaultTimeoutMs: positiveInteger("KIRINCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS"), experimentalNativeLlm: bool("KIRINCODE_EXPERIMENTAL_NATIVE_LLM"), experimentalWebSockets: bool("KIRINCODE_EXPERIMENTAL_WEBSOCKETS"), client: Config.string("KIRINCODE_CLIENT").pipe(Config.withDefault("cli")), }) {} export type Info = Context.Service.Shape const emptyConfigLayer = Service.layer.pipe( Layer.provide(ConfigProvider.layer(ConfigProvider.fromUnknown({}))), Layer.orDie, ) export const layer = (overrides: Partial = {}) => Layer.effect( Service, Effect.gen(function* () { const flags = yield* Service return Service.of({ ...flags, ...overrides }) }), ).pipe(Layer.provide(emptyConfigLayer)) export const node = LayerNode.make({ service: Service, layer: Service.layer.pipe(Layer.orDie), deps: [] }) export * as RuntimeFlags from "./runtime-flags" import { LayerNode } from "@kirincode-ai/core/effect/layer-node"