Skip to content

Commit 4875757

Browse files
authored
feat: create global opencode.jsonc if no configs exist (#26992)
1 parent 5cc8480 commit 4875757

2 files changed

Lines changed: 58 additions & 0 deletions

File tree

packages/opencode/src/config/config.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,16 @@ export const layer = Layer.effect(
409409

410410
const loadGlobal = Effect.fnUntraced(function* () {
411411
let result: Info = {}
412+
// Seed the default global config with the schema for editor completion, but avoid writing when the user
413+
// explicitly routes config through env-provided paths or content.
414+
if (!Flag.OPENCODE_CONFIG && !Flag.OPENCODE_CONFIG_DIR && !Flag.OPENCODE_CONFIG_CONTENT) {
415+
const file = globalConfigFile()
416+
if (!existsSync(file)) {
417+
yield* fs
418+
.writeWithDirs(file, JSON.stringify({ $schema: "https://opencode.ai/config.json" }, null, 2))
419+
.pipe(Effect.catch(() => Effect.void))
420+
}
421+
}
412422
result = mergeConfig(result, yield* loadFile(path.join(Global.Path.config, "config.json")))
413423
result = mergeConfig(result, yield* loadFile(path.join(Global.Path.config, "opencode.json")))
414424
result = mergeConfig(result, yield* loadFile(path.join(Global.Path.config, "opencode.jsonc")))

packages/opencode/test/config/config.test.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,54 @@ test("loads config with defaults when no files exist", async () => {
141141
})
142142
})
143143

144+
test("creates global jsonc config with schema when no global configs exist", async () => {
145+
await using tmp = await tmpdir()
146+
const prev = Global.Path.config
147+
;(Global.Path as { config: string }).config = tmp.path
148+
await clear(true)
149+
150+
try {
151+
await WithInstance.provide({
152+
directory: tmp.path,
153+
fn: async () => {
154+
await load()
155+
},
156+
})
157+
158+
const content = await Filesystem.readText(path.join(tmp.path, "opencode.jsonc"))
159+
expect(content).toContain('"$schema": "https://opencode.ai/config.json"')
160+
} finally {
161+
;(Global.Path as { config: string }).config = prev
162+
await clear(true)
163+
}
164+
})
165+
166+
test("does not create global config when OPENCODE_CONFIG_DIR is set", async () => {
167+
await using tmp = await tmpdir()
168+
await using custom = await tmpdir()
169+
const prevConfig = Global.Path.config
170+
const prevEnv = process.env.OPENCODE_CONFIG_DIR
171+
;(Global.Path as { config: string }).config = tmp.path
172+
process.env.OPENCODE_CONFIG_DIR = custom.path
173+
await clear(true)
174+
175+
try {
176+
await WithInstance.provide({
177+
directory: tmp.path,
178+
fn: async () => {
179+
await load()
180+
},
181+
})
182+
183+
expect(await Filesystem.exists(path.join(tmp.path, "opencode.jsonc"))).toBe(false)
184+
} finally {
185+
;(Global.Path as { config: string }).config = prevConfig
186+
if (prevEnv === undefined) delete process.env.OPENCODE_CONFIG_DIR
187+
else process.env.OPENCODE_CONFIG_DIR = prevEnv
188+
await clear(true)
189+
}
190+
})
191+
144192
test("loads JSON config file", async () => {
145193
await using tmp = await tmpdir({
146194
init: async (dir) => {

0 commit comments

Comments
 (0)