Lines 9-49typescript
9import { SqliteStateLive } from "../state/sqlite.ts"
11export class ConfigLoadError extends Data.TaggedError("ConfigLoadError")<{
13 readonly reason: string
15 override get message(): string {
16 return `config ${this.path}: ${this.reason}`
20/** Config with an already-assembled model list: explicit ones + discovery finds. */
21export type LoadedConfig = EfmeshConfig & { readonly models: ReadonlyArray<AnyModel> }
23export const loadConfig = (
25): Effect.Effect<LoadedConfig, ConfigLoadError | DiscoveryError | DiscoveryConflictError> =>
26 Effect.gen(function* () {
27 const absolute = NodePath.resolve(process.cwd(), configPath)
28 const config = yield* Effect.tryPromise({
30 const module = (await import(absolute)) as { default?: EfmeshConfig }
31 if (
MediumDynamic Require
Package source references dynamic require/import behavior.
src/cli/config.tsView on unpkg · L29 32 module.default === undefined ||
33 (!Array.isArray(module.default.models) && module.default.discovery === undefined)
35 throw new Error("config must export a default with models and/or discovery")
39 catch: (cause) => new ConfigLoadError({ path: configPath, reason: String(cause) }),
41 const explicit = config.models ?? []
42 if (config.discovery === undefined) return { ...config, models: explicit }
43 // globs are relative to the config: the project is portable regardless of cwd
44 const discovered = yield* discoverModels(config.discovery, NodePath.dirname(absolute))
45 const seen = new Set(explicit)
46 const names = new Map(explicit.map((model) => [model.name.full, "config models"]))
47 const merged = [...explicit]
48 for (const model of discovered) {
49 if (seen.has(model)) continue