Compare commits

..

1 Commits

Author SHA1 Message Date
Kit Langton 55d4cd19e5 fix(opencode): warn on unknown config fields 2026-08-08 18:58:35 +00:00
5 changed files with 15 additions and 27 deletions
+1 -7
View File
@@ -228,13 +228,7 @@ const layer = Layer.effect(
}),
)
return JSON.parse(text) as Record<string, Provider>
}).pipe(
Effect.withSpan("ModelsDev.populate"),
Effect.catch((error) =>
Effect.logError("Failed to fetch models.dev", { error }).pipe(Effect.as({} as Record<string, Provider>)),
),
Effect.orDie,
)
}).pipe(Effect.withSpan("ModelsDev.populate"), Effect.orDie)
const [cachedGet, invalidate] = yield* Effect.cachedInvalidateWithTTL(populate, Duration.infinity)
-19
View File
@@ -176,25 +176,6 @@ describe("ModelsDev Service", () => {
}),
)
it.live("get() returns an empty catalog when the initial fetch fails", () =>
Effect.gen(function* () {
const state = yield* Ref.make({ ...initialState, status: 503 })
const context = yield* Layer.build(buildLayer(state))
const result = yield* Effect.acquireUseRelease(
Effect.sync(() => {
Flag.OPENCODE_DISABLE_MODELS_FETCH = false
}),
() => ModelsDev.Service.use((s) => s.get()).pipe(Effect.provide(context)),
() =>
Effect.sync(() => {
Flag.OPENCODE_DISABLE_MODELS_FETCH = true
}),
)
expect(result).toEqual({})
expect((yield* Ref.get(state)).calls.length).toBe(3)
}),
)
it.live("get() is single-flight under concurrent calls", () =>
Effect.gen(function* () {
yield* writeCache(fixture)
+6 -1
View File
@@ -224,7 +224,12 @@ const layer = Layer.effect(
),
)
const parsed = ConfigParse.jsonc(expanded, source)
const data = ConfigParse.schema(ConfigV1.Info, normalizeLoadedConfig(parsed), source)
const normalized = normalizeLoadedConfig(parsed)
const unrecognized = ConfigParse.unrecognizedKeys(ConfigV1.Info, normalized)
if (unrecognized.length) {
yield* Effect.logWarning("ignoring unrecognized config fields", { source, fields: unrecognized })
}
const data = ConfigParse.schema(ConfigV1.Info, normalized, source)
if (!("path" in options)) return data
yield* Effect.promise(() => resolveLoadedPlugins(data, options.path))
+7
View File
@@ -59,3 +59,10 @@ export function schema<S extends EffectSchema.Decoder<unknown, never>>(
{ cause: error },
)
}
export function unrecognizedKeys(schema: EffectSchema.Top, data: unknown) {
if (typeof data !== "object" || data === null || Array.isArray(data)) return []
if (schema.ast._tag !== "Objects" || schema.ast.indexSignatures.length > 0) return []
const known = new Set(schema.ast.propertySignatures.map((item) => String(item.name)))
return Object.keys(data).filter((key) => !known.has(key))
}
@@ -1347,6 +1347,7 @@ test("config parser preserves permission order while ignoring unknown top-level
expect(Object.keys(config.permission!)).toEqual(["bash", "*", "edit"])
expect(config).not.toHaveProperty("plugins")
expect(ConfigParse.unrecognizedKeys(ConfigV1.Info, { plugins: ["example"] })).toEqual(["plugins"])
})
// MCP config merging tests