fix(core): accept deprecated reference config key (#31659)

This commit is contained in:
Luke Parker 2026-06-10 20:32:35 +10:00 committed by GitHub
parent 97e713e8aa
commit 90fb32be30
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 69 additions and 2 deletions

View File

@ -2,7 +2,9 @@
"$schema": "https://opencode.ai/config.json",
"provider": {},
"permission": {},
"references": {
// TODO: flip back to `references` once a release containing the v1 `reference` migration ships.
// The release pipeline runs the latest published opencode against this file, which only knows `reference`.
"reference": {
"effect": {
"repository": "github.com/Effect-TS/effect-smol",
"description": "Use for Effect v4 and effect-smol implementation details",

View File

@ -45,6 +45,9 @@ export const Info = Schema.Struct({
references: Schema.optional(ConfigReference.Info).annotate({
description: "Named git or local directory references",
}),
reference: Schema.optional(ConfigReference.Info).annotate({
description: "@deprecated Use 'references' field instead. Named git or local directory references",
}),
watcher: Schema.optional(Schema.Struct({ ignore: Schema.optional(Schema.mutable(Schema.Array(Schema.String))) })),
snapshot: Schema.optional(Schema.Boolean).annotate({
description:

View File

@ -12,6 +12,7 @@ const keys = new Set([
"logLevel",
"server",
"command",
"reference",
"snapshot",
"plugin",
"autoshare",
@ -62,7 +63,7 @@ export function migrate(info: typeof ConfigV1.Info.Type) {
skills: info.skills && [...(info.skills.paths ?? []), ...(info.skills.urls ?? [])],
commands: info.command,
instructions: info.instructions,
references: info.references,
references: info.references ?? info.reference,
plugins: info.plugin?.map((plugin) =>
typeof plugin === "string" ? plugin : { package: plugin[0], options: plugin[1] },
),

View File

@ -70,7 +70,9 @@ describe("Config", () => {
Effect.sync(() => {
expect(ConfigMigrateV1.isV1({ snapshot: false })).toBe(true)
expect(ConfigMigrateV1.isV1({ snapshot: false, agents: {} })).toBe(true)
expect(ConfigMigrateV1.isV1({ reference: {} })).toBe(true)
expect(ConfigMigrateV1.isV1({ shell: "/bin/zsh", model: "anthropic/claude" })).toBe(false)
expect(ConfigMigrateV1.isV1({ references: {} })).toBe(false)
}),
)
@ -431,6 +433,42 @@ describe("Config", () => {
),
)
it.live("migrates the deprecated reference key into references", () =>
Effect.acquireRelease(
Effect.promise(() => tmpdir()),
(tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]()),
).pipe(
Effect.flatMap((tmp) =>
Effect.gen(function* () {
yield* Effect.promise(() =>
fs.writeFile(
path.join(tmp.path, "opencode.json"),
JSON.stringify({
reference: {
local: { path: "../library" },
sdk: { repository: "github.com/example/sdk", branch: "main" },
shorthand: "github.com/example/docs",
},
}),
),
)
return yield* Effect.gen(function* () {
const config = yield* Config.Service
const documents = (yield* config.entries()).filter((entry) => entry.type === "document")
expect(documents).toHaveLength(1)
expect(documents[0]?.info.references).toEqual({
local: { path: "../library" },
sdk: { repository: "github.com/example/sdk", branch: "main" },
shorthand: "github.com/example/docs",
})
}).pipe(Effect.provide(testLayer(tmp.path)))
}),
),
),
)
it.live("migrates v1 configuration when a v1-only key is present", () =>
Effect.acquireRelease(
Effect.promise(() => tmpdir()),

View File

@ -722,6 +722,26 @@ it.instance("migrates mode field to agent field", () =>
}),
)
it.instance("accepts the deprecated reference field", () =>
Effect.gen(function* () {
const test = yield* TestInstance
yield* writeConfigEffect(test.directory, {
$schema: "https://opencode.ai/config.json",
reference: {
local: { path: "../library" },
sdk: { repository: "github.com/example/sdk", branch: "main" },
shorthand: "github.com/example/docs",
},
})
const config = yield* Config.use.get()
expect(config.reference).toEqual({
local: { path: "../library" },
sdk: { repository: "github.com/example/sdk", branch: "main" },
shorthand: "github.com/example/docs",
})
}),
)
it.instance("loads config from .opencode directory", () =>
Effect.gen(function* () {
const test = yield* TestInstance

View File

@ -1931,6 +1931,9 @@ export type Config = {
references?: {
[key: string]: string | ConfigV2ReferenceGit | ConfigV2ReferenceLocal
}
reference?: {
[key: string]: string | ConfigV2ReferenceGit | ConfigV2ReferenceLocal
}
watcher?: {
ignore?: Array<string>
}