浏览代码

VSCode: enhance error handling to differentiate external errors from extension-specific ones

paviko 2 月之前
父节点
当前提交
bcb1e4820e
共有 1 个文件被更改,包括 39 次插入1 次删除
  1. 39 1
      hosts/vscode-plugin/src/utils/ErrorHandler.ts

+ 39 - 1
hosts/vscode-plugin/src/utils/ErrorHandler.ts

@@ -1,4 +1,5 @@
 import * as vscode from "vscode"
+import * as path from "path"
 import { RecoveryUtils } from "./RecoveryUtils"
 import { logger } from "../globals"
 
@@ -825,6 +826,22 @@ export class ErrorHandler {
       return { message, stack }
     }
 
+    const normalizeForStackMatch = (value: string): string => value.replace(/\\/g, "/")
+
+    const isFromThisExtension = (err: unknown): boolean => {
+      const { stack } = getErrorStrings(err)
+      if (!stack) {
+        return false
+      }
+
+      // Important: the extension host process is shared across extensions.
+      // Only treat global errors as "ours" if the stack trace points to our code.
+      const s = normalizeForStackMatch(stack)
+      const dir = normalizeForStackMatch(__dirname)
+      const parent = normalizeForStackMatch(path.resolve(__dirname, ".."))
+      return s.includes(dir) || s.includes(parent)
+    }
+
     const isIgnorableGlobalRejection = (err: unknown): boolean => {
       const { message, stack } = getErrorStrings(err)
       // Known benign errors from other extensions (e.g., Windsurf acknowledgeCascadeCodeEdit)
@@ -851,7 +868,14 @@ export class ErrorHandler {
 
     // Handle unhandled promise rejections
     process.on("unhandledRejection", (reason, promise) => {
-      const error = reason instanceof Error ? reason : new Error(String(reason))
+      // Preserve original message/stack for attribution. Creating a new Error() here would
+      // point the stack at *this* handler and falsely attribute external errors to OpenCode.
+      const { message, stack } = getErrorStrings(reason)
+      const error = reason instanceof Error ? reason : new Error(message)
+      if (!(reason instanceof Error) && stack) {
+        error.stack = stack
+      }
+
       // Suppress known benign global rejections from other extensions
       if (isIgnorableGlobalRejection(error)) {
         logger.appendLine(`[IGNORED] Unhandled rejection suppressed: ${error.message}`)
@@ -860,6 +884,13 @@ export class ErrorHandler {
       if (suppressLanguageServerError(error, "Unhandled rejection suppressed")) {
         return
       }
+
+      // Don't surface errors coming from other extensions running in the same extension host.
+      if (!isFromThisExtension(reason)) {
+        logger.appendLine(`[IGNORED] External unhandled rejection: ${message}`)
+        return
+      }
+
       this.handleError(
         this.createErrorContext(ErrorCategory.VALIDATION, ErrorSeverity.ERROR, "Global", "unhandledRejection", error, {
           promise: promise.toString(),
@@ -872,6 +903,13 @@ export class ErrorHandler {
       if (suppressLanguageServerError(error, "Uncaught exception suppressed")) {
         return
       }
+
+      if (!isFromThisExtension(error)) {
+        const { message } = getErrorStrings(error)
+        logger.appendLine(`[IGNORED] External uncaught exception: ${message}`)
+        return
+      }
+
       this.handleError(
         this.createErrorContext(ErrorCategory.VALIDATION, ErrorSeverity.CRITICAL, "Global", "uncaughtException", error),
       )