Skip to content

Commit 326471a

Browse files
authored
refactor: split config lsp and formatter schemas (#22986)
1 parent 6405e3a commit 326471a

6 files changed

Lines changed: 63 additions & 51 deletions

File tree

AGENTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
- Use Bun APIs when possible, like `Bun.file()`
1515
- Rely on type inference when possible; avoid explicit type annotations or interfaces unless necessary for exports or clarity
1616
- Prefer functional array methods (flatMap, filter, map) over for loops; use type guards on filter to maintain type inference downstream
17+
- In `src/config`, follow the existing self-export pattern at the top of the file (for example `export * as ConfigAgent from "./agent"`) when adding a new config module.
1718

1819
Reduce total variable count by inlining when a value is only used once.
1920

packages/opencode/AGENTS.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ See `specs/effect/migration.md` for the compact pattern reference and examples.
2323
- Use `Effect.callback` for callback-based APIs.
2424
- Prefer `DateTime.nowAsDate` over `new Date(yield* Clock.currentTimeMillis)` when you need a `Date`.
2525

26+
## Module conventions
27+
28+
- In `src/config`, follow the existing self-export pattern at the top of the file (for example `export * as ConfigAgent from "./agent"`) when adding a new config module.
29+
2630
## Schemas and errors
2731

2832
- Use `Schema.Class` for multi-field data.

packages/opencode/src/config/config.ts

Lines changed: 4 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import { Auth } from "../auth"
1212
import { Env } from "../env"
1313
import { applyEdits, modify } from "jsonc-parser"
1414
import { Instance, type InstanceContext } from "../project/instance"
15-
import * as LSPServer from "../lsp/server"
1615
import { InstallationLocal, InstallationVersion } from "@/installation/version"
1716
import { existsSync } from "fs"
1817
import { GlobalBus } from "@/bus/global"
@@ -37,6 +36,8 @@ import { ConfigPermission } from "./permission"
3736
import { ConfigProvider } from "./provider"
3837
import { ConfigSkills } from "./skills"
3938
import { ConfigPaths } from "./paths"
39+
import { ConfigFormatter } from "./formatter"
40+
import { ConfigLSP } from "./lsp"
4041

4142
const log = Log.create({ service: "config" })
4243

@@ -186,56 +187,8 @@ export const Info = z
186187
)
187188
.optional()
188189
.describe("MCP (Model Context Protocol) server configurations"),
189-
formatter: z
190-
.union([
191-
z.literal(false),
192-
z.record(
193-
z.string(),
194-
z.object({
195-
disabled: z.boolean().optional(),
196-
command: z.array(z.string()).optional(),
197-
environment: z.record(z.string(), z.string()).optional(),
198-
extensions: z.array(z.string()).optional(),
199-
}),
200-
),
201-
])
202-
.optional(),
203-
lsp: z
204-
.union([
205-
z.literal(false),
206-
z.record(
207-
z.string(),
208-
z.union([
209-
z.object({
210-
disabled: z.literal(true),
211-
}),
212-
z.object({
213-
command: z.array(z.string()),
214-
extensions: z.array(z.string()).optional(),
215-
disabled: z.boolean().optional(),
216-
env: z.record(z.string(), z.string()).optional(),
217-
initialization: z.record(z.string(), z.any()).optional(),
218-
}),
219-
]),
220-
),
221-
])
222-
.optional()
223-
.refine(
224-
(data) => {
225-
if (!data) return true
226-
if (typeof data === "boolean") return true
227-
const serverIds = new Set(Object.values(LSPServer).map((s) => s.id))
228-
229-
return Object.entries(data).every(([id, config]) => {
230-
if (config.disabled) return true
231-
if (serverIds.has(id)) return true
232-
return Boolean(config.extensions)
233-
})
234-
},
235-
{
236-
error: "For custom LSP servers, 'extensions' array is required.",
237-
},
238-
),
190+
formatter: ConfigFormatter.Info.optional(),
191+
lsp: ConfigLSP.Info.optional(),
239192
instructions: z.array(z.string()).optional().describe("Additional instruction files or patterns to include"),
240193
layout: Layout.optional().describe("@deprecated Always uses stretch layout."),
241194
permission: ConfigPermission.Info.optional(),
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
export * as ConfigFormatter from "./formatter"
2+
3+
import z from "zod"
4+
5+
export const Entry = z.object({
6+
disabled: z.boolean().optional(),
7+
command: z.array(z.string()).optional(),
8+
environment: z.record(z.string(), z.string()).optional(),
9+
extensions: z.array(z.string()).optional(),
10+
})
11+
12+
export const Info = z.union([z.literal(false), z.record(z.string(), Entry)])
13+
export type Info = z.infer<typeof Info>

packages/opencode/src/config/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ export * as Config from "./config"
22
export * as ConfigAgent from "./agent"
33
export * as ConfigCommand from "./command"
44
export * as ConfigError from "./error"
5+
export * as ConfigFormatter from "./formatter"
6+
export * as ConfigLSP from "./lsp"
57
export * as ConfigVariable from "./variable"
68
export { ConfigManaged } from "./managed"
79
export * as ConfigMarkdown from "./markdown"
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
export * as ConfigLSP from "./lsp"
2+
3+
import z from "zod"
4+
import * as LSPServer from "../lsp/server"
5+
6+
export const Disabled = z.object({
7+
disabled: z.literal(true),
8+
})
9+
10+
export const Entry = z.union([
11+
Disabled,
12+
z.object({
13+
command: z.array(z.string()),
14+
extensions: z.array(z.string()).optional(),
15+
disabled: z.boolean().optional(),
16+
env: z.record(z.string(), z.string()).optional(),
17+
initialization: z.record(z.string(), z.any()).optional(),
18+
}),
19+
])
20+
21+
export const Info = z
22+
.union([z.literal(false), z.record(z.string(), Entry)])
23+
.refine(
24+
(data) => {
25+
if (typeof data === "boolean") return true
26+
const serverIds = new Set(Object.values(LSPServer).map((server) => server.id))
27+
28+
return Object.entries(data).every(([id, config]) => {
29+
if (config.disabled) return true
30+
if (serverIds.has(id)) return true
31+
return Boolean(config.extensions)
32+
})
33+
},
34+
{
35+
error: "For custom LSP servers, 'extensions' array is required.",
36+
},
37+
)
38+
39+
export type Info = z.infer<typeof Info>

0 commit comments

Comments
 (0)