Просмотр исходного кода

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

Luke Parker 2 месяцев назад
Родитель
Сommit
90fb32be30

+ 3 - 1
.opencode/opencode.jsonc

@@ -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",

+ 3 - 0
packages/core/src/v1/config/config.ts

@@ -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:

+ 2 - 1
packages/core/src/v1/config/migrate.ts

@@ -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] },
     ),

+ 38 - 0
packages/core/test/config/config.test.ts

@@ -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()),

+ 20 - 0
packages/opencode/test/config/config.test.ts

@@ -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

+ 3 - 0
packages/sdk/js/src/v2/gen/types.gen.ts

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