|
|
@@ -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),
|
|
|
)
|