Pārlūkot izejas kodu

feat: jsonc configuration file support (#1434)

Aiden Cline 6 mēneši atpakaļ
vecāks
revīzija
7e9050edb9

+ 1 - 0
bun.lock

@@ -47,6 +47,7 @@
         "hono": "catalog:",
         "hono-openapi": "0.4.8",
         "isomorphic-git": "1.32.1",
+        "jsonc-parser": "3.3.1",
         "open": "10.1.2",
         "remeda": "catalog:",
         "tree-sitter": "0.22.4",

+ 1 - 0
packages/opencode/package.json

@@ -45,6 +45,7 @@
     "hono": "catalog:",
     "hono-openapi": "0.4.8",
     "isomorphic-git": "1.32.1",
+    "jsonc-parser": "3.3.1",
     "open": "10.1.2",
     "remeda": "catalog:",
     "turndown": "7.2.0",

+ 5 - 1
packages/opencode/src/cli/error.ts

@@ -5,7 +5,11 @@ import { UI } from "./ui"
 export function FormatError(input: unknown) {
   if (MCP.Failed.isInstance(input))
     return `MCP server "${input.data.name}" failed. Note, opencode does not support MCP authentication yet.`
-  if (Config.JsonError.isInstance(input)) return `Config file at ${input.data.path} is not valid JSON`
+  if (Config.JsonError.isInstance(input)) {
+    return (
+      `Config file at ${input.data.path} is not valid JSON(C)` + (input.data.message ? `: ${input.data.message}` : "")
+    )
+  }
   if (Config.InvalidError.isInstance(input))
     return [
       `Config file at ${input.data.path} is invalid`,

+ 16 - 5
packages/opencode/src/config/config.ts

@@ -12,6 +12,7 @@ import { NamedError } from "../util/error"
 import matter from "gray-matter"
 import { Flag } from "../flag/flag"
 import { Auth } from "../auth"
+import { type ParseError as JsoncParseError, parse as parseJsonc, printParseErrorCode } from "jsonc-parser"
 
 export namespace Config {
   const log = Log.create({ service: "config" })
@@ -371,11 +372,20 @@ export namespace Config {
       }
     }
 
-    let data: any
-    try {
-      data = JSON.parse(text)
-    } catch (err) {
-      throw new JsonError({ path: configPath }, { cause: err as Error })
+    const errors: JsoncParseError[] = []
+    const data = parseJsonc(text, errors, { allowTrailingComma: true })
+    if (errors.length) {
+      throw new JsonError({
+        path: configPath,
+        message: errors
+          .map((e) => {
+            const lines = text.substring(0, e.offset).split("\n")
+            const line = lines.length
+            const column = lines[lines.length - 1].length + 1
+            return `${printParseErrorCode(e.error)} at line ${line}, column ${column}`
+          })
+          .join("; "),
+      })
     }
 
     const parsed = Info.safeParse(data)
@@ -392,6 +402,7 @@ export namespace Config {
     "ConfigJsonError",
     z.object({
       path: z.string(),
+      message: z.string().optional(),
     }),
   )
 

+ 8 - 2
packages/web/src/content/docs/docs/config.mdx

@@ -5,9 +5,14 @@ description: Using the opencode JSON config.
 
 You can configure opencode using a JSON config file.
 
-```json title="opencode.json"
+## Format
+
+opencode supports both JSON and JSONC (JSON with Comments) formats. You can use comments in your configuration files:
+
+```jsonc title="opencode.jsonc"
 {
   "$schema": "https://opencode.ai/config.json",
+  // Theme configuration
   "theme": "opencode",
   "model": "anthropic/claude-sonnet-4-20250514",
   "autoupdate": true
@@ -199,7 +204,7 @@ about rules here](/docs/rules).
 
 You can configure specialized agents for specific tasks through the `agent` option.
 
-```json title="opencode.json"
+```jsonc title="opencode.jsonc"
 {
   "$schema": "https://opencode.ai/config.json",
   "agent": {
@@ -208,6 +213,7 @@ You can configure specialized agents for specific tasks through the `agent` opti
       "model": "anthropic/claude-sonnet-4-20250514",
       "prompt": "You are a code reviewer. Focus on security, performance, and maintainability.",
       "tools": {
+        // Disable file modification tools for review-only agent
         "write": false,
         "edit": false
       }