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

fix: show toast error message on ConfigMarkdown parse error (#8049)

Co-authored-by: Aiden Cline <[email protected]>
Maciek Szczesniak 3 месяцев назад
Родитель
Сommit
37f30993fa
2 измененных файлов с 43 добавлено и 10 удалено
  1. 29 6
      packages/opencode/src/config/config.ts
  2. 14 4
      packages/opencode/src/skill/skill.ts

+ 29 - 6
packages/opencode/src/config/config.ts

@@ -19,6 +19,8 @@ import { BunProc } from "@/bun"
 import { Installation } from "@/installation"
 import { Installation } from "@/installation"
 import { ConfigMarkdown } from "./markdown"
 import { ConfigMarkdown } from "./markdown"
 import { existsSync } from "fs"
 import { existsSync } from "fs"
+import { Bus } from "@/bus"
+import { Session } from "@/session"
 
 
 export namespace Config {
 export namespace Config {
   const log = Log.create({ service: "config" })
   const log = Log.create({ service: "config" })
@@ -231,8 +233,15 @@ export namespace Config {
       dot: true,
       dot: true,
       cwd: dir,
       cwd: dir,
     })) {
     })) {
-      const md = await ConfigMarkdown.parse(item)
-      if (!md.data) continue
+      const md = await ConfigMarkdown.parse(item).catch((err) => {
+        const message = ConfigMarkdown.FrontmatterError.isInstance(err)
+          ? `${err.data.path}: ${err.data.message}`
+          : `Failed to parse command ${item}`
+        Bus.publish(Session.Event.Error, { error: new NamedError.Unknown({ message }).toObject() })
+        log.error("failed to load command", { command: item, err })
+        return undefined
+      })
+      if (!md) continue
 
 
       const patterns = ["/.opencode/command/", "/.opencode/commands/", "/command/", "/commands/"]
       const patterns = ["/.opencode/command/", "/.opencode/commands/", "/command/", "/commands/"]
       const file = rel(item, patterns) ?? path.basename(item)
       const file = rel(item, patterns) ?? path.basename(item)
@@ -263,8 +272,15 @@ export namespace Config {
       dot: true,
       dot: true,
       cwd: dir,
       cwd: dir,
     })) {
     })) {
-      const md = await ConfigMarkdown.parse(item)
-      if (!md.data) continue
+      const md = await ConfigMarkdown.parse(item).catch((err) => {
+        const message = ConfigMarkdown.FrontmatterError.isInstance(err)
+          ? `${err.data.path}: ${err.data.message}`
+          : `Failed to parse agent ${item}`
+        Bus.publish(Session.Event.Error, { error: new NamedError.Unknown({ message }).toObject() })
+        log.error("failed to load agent", { agent: item, err })
+        return undefined
+      })
+      if (!md) continue
 
 
       const patterns = ["/.opencode/agent/", "/.opencode/agents/", "/agent/", "/agents/"]
       const patterns = ["/.opencode/agent/", "/.opencode/agents/", "/agent/", "/agents/"]
       const file = rel(item, patterns) ?? path.basename(item)
       const file = rel(item, patterns) ?? path.basename(item)
@@ -294,8 +310,15 @@ export namespace Config {
       dot: true,
       dot: true,
       cwd: dir,
       cwd: dir,
     })) {
     })) {
-      const md = await ConfigMarkdown.parse(item)
-      if (!md.data) continue
+      const md = await ConfigMarkdown.parse(item).catch((err) => {
+        const message = ConfigMarkdown.FrontmatterError.isInstance(err)
+          ? `${err.data.path}: ${err.data.message}`
+          : `Failed to parse mode ${item}`
+        Bus.publish(Session.Event.Error, { error: new NamedError.Unknown({ message }).toObject() })
+        log.error("failed to load mode", { mode: item, err })
+        return undefined
+      })
+      if (!md) continue
 
 
       const config = {
       const config = {
         name: path.basename(item, ".md"),
         name: path.basename(item, ".md"),

+ 14 - 4
packages/opencode/src/skill/skill.ts

@@ -1,4 +1,5 @@
 import z from "zod"
 import z from "zod"
+import path from "path"
 import { Config } from "../config/config"
 import { Config } from "../config/config"
 import { Instance } from "../project/instance"
 import { Instance } from "../project/instance"
 import { NamedError } from "@opencode-ai/util/error"
 import { NamedError } from "@opencode-ai/util/error"
@@ -7,6 +8,9 @@ import { Log } from "../util/log"
 import { Global } from "@/global"
 import { Global } from "@/global"
 import { Filesystem } from "@/util/filesystem"
 import { Filesystem } from "@/util/filesystem"
 import { Flag } from "@/flag/flag"
 import { Flag } from "@/flag/flag"
+import { Bus } from "@/bus"
+import { TuiEvent } from "@/cli/cmd/tui/event"
+import { Session } from "@/session"
 
 
 export namespace Skill {
 export namespace Skill {
   const log = Log.create({ service: "skill" })
   const log = Log.create({ service: "skill" })
@@ -42,10 +46,16 @@ export namespace Skill {
     const skills: Record<string, Info> = {}
     const skills: Record<string, Info> = {}
 
 
     const addSkill = async (match: string) => {
     const addSkill = async (match: string) => {
-      const md = await ConfigMarkdown.parse(match)
-      if (!md) {
-        return
-      }
+      const md = await ConfigMarkdown.parse(match).catch((err) => {
+        const message = ConfigMarkdown.FrontmatterError.isInstance(err)
+          ? `${err.data.path}: ${err.data.message}`
+          : `Failed to parse skill ${match}`
+        Bus.publish(Session.Event.Error, { error: new NamedError.Unknown({ message }).toObject() })
+        log.error("failed to load skill", { skill: match, err })
+        return undefined
+      })
+
+      if (!md) return
 
 
       const parsed = Info.pick({ name: true, description: true }).safeParse(md.data)
       const parsed = Info.pick({ name: true, description: true }).safeParse(md.data)
       if (!parsed.success) return
       if (!parsed.success) return