(input: unknown)
| 33 | } |
| 34 | |
| 35 | export function FormatError(input: unknown): string | undefined { |
| 36 | if (input instanceof Error && isRecord(input.cause) && "body" in input.cause) { |
| 37 | const formatted = FormatError(input.cause.body) |
| 38 | if (formatted) return formatted |
| 39 | } |
| 40 | |
| 41 | // CliError: domain failure surfaced from an effectCmd handler via fail("...") |
| 42 | if (isTaggedError(input, "CliError")) { |
| 43 | if (typeof input.exitCode === "number") process.exitCode = input.exitCode |
| 44 | return stringField(input, "message") ?? "" |
| 45 | } |
| 46 | |
| 47 | // MCPFailed: { name: string } |
| 48 | if (NamedError.hasName(input, "MCPFailed")) { |
| 49 | const data = isRecord(input) && isRecord(input.data) ? stringField(input.data, "name") : undefined |
| 50 | return `MCP server "${data}" failed. Note, opencode does not support MCP authentication yet.` |
| 51 | } |
| 52 | |
| 53 | // AccountServiceError, AccountTransportError: TaggedErrorClass |
| 54 | if (isTaggedError(input, "AccountServiceError") || isTaggedError(input, "AccountTransportError")) { |
| 55 | return stringField(input, "message") ?? "" |
| 56 | } |
| 57 | |
| 58 | // ProviderModelNotFoundError: { providerID: string, modelID: string, suggestions?: string[] } |
| 59 | const providerModelNotFound = configData(input, "ProviderModelNotFoundError") |
| 60 | if (providerModelNotFound) { |
| 61 | const suggestions = Array.isArray(providerModelNotFound.suggestions) |
| 62 | ? providerModelNotFound.suggestions.filter((x) => typeof x === "string") |
| 63 | : [] |
| 64 | return [ |
| 65 | `Model not found: ${stringField(providerModelNotFound, "providerID")}/${stringField(providerModelNotFound, "modelID")}`, |
| 66 | ...(suggestions.length ? ["Did you mean: " + suggestions.join(", ")] : []), |
| 67 | `Try: \`opencode models\` to list available models`, |
| 68 | `Or check your config (opencode.json) provider/model names`, |
| 69 | ].join("\n") |
| 70 | } |
| 71 | |
| 72 | // ProviderInitError: { providerID: string } |
| 73 | const providerInit = configData(input, "ProviderInitError") |
| 74 | if (providerInit) { |
| 75 | return `Failed to initialize provider "${stringField(providerInit, "providerID")}". Check credentials and configuration.` |
| 76 | } |
| 77 | |
| 78 | // ConfigJsonError: { path: string, message?: string } |
| 79 | const configJson = configData(input, "ConfigJsonError") |
| 80 | if (configJson) { |
| 81 | const message = stringField(configJson, "message") |
| 82 | return `Config file at ${stringField(configJson, "path")} is not valid JSON(C)` + (message ? `: ${message}` : "") |
| 83 | } |
| 84 | |
| 85 | // ConfigDirectoryTypoError: { dir: string, path: string, suggestion: string } |
| 86 | const configDirectoryTypo = configData(input, "ConfigDirectoryTypoError") |
| 87 | if (configDirectoryTypo) { |
| 88 | return `Directory "${stringField(configDirectoryTypo, "dir")}" in ${stringField(configDirectoryTypo, "path")} is not valid. Rename the directory to "${stringField(configDirectoryTypo, "suggestion")}" or remove it. This is a common typo.` |
| 89 | } |
| 90 | |
| 91 | // ConfigFrontmatterError: { message: string } |
| 92 | const configFrontmatter = configData(input, "ConfigFrontmatterError") |
no test coverage detected