import { z } from "zod" export const RegistryErrorCode = { NETWORK_ERROR: "NETWORK_ERROR", NOT_FOUND: "NOT_FOUND", UNAUTHORIZED: "UNAUTHORIZED", FORBIDDEN: "FORBIDDEN", FETCH_ERROR: "FETCH_ERROR", NOT_CONFIGURED: "NOT_CONFIGURED", INVALID_CONFIG: "INVALID_CONFIG", MISSING_ENV_VARS: "MISSING_ENV_VARS", LOCAL_FILE_ERROR: "LOCAL_FILE_ERROR", PARSE_ERROR: "PARSE_ERROR", VALIDATION_ERROR: "VALIDATION_ERROR", UNKNOWN_ERROR: "UNKNOWN_ERROR", } as const export type RegistryErrorCode = (typeof RegistryErrorCode)[keyof typeof RegistryErrorCode] export class RegistryError extends Error { public readonly code: RegistryErrorCode public readonly statusCode?: number public readonly context?: Record public readonly suggestion?: string public readonly timestamp: Date public readonly cause?: unknown constructor( message: string, options: { code?: RegistryErrorCode statusCode?: number cause?: unknown context?: Record suggestion?: string } = {}, ) { super(message) this.name = "RegistryError" this.code = options.code || RegistryErrorCode.UNKNOWN_ERROR this.statusCode = options.statusCode this.cause = options.cause this.context = options.context this.suggestion = options.suggestion this.timestamp = new Date() if (Error.captureStackTrace) { Error.captureStackTrace(this, this.constructor) } } } export class RegistryNotFoundError extends RegistryError { constructor( public readonly url: string, cause?: unknown, ) { const message = `The item at ${url} was not found. It may not exist at the registry.` super(message, { code: RegistryErrorCode.NOT_FOUND, statusCode: 404, cause, context: { url }, suggestion: "Check if the item name is correct and the registry URL is accessible.", }) this.name = "RegistryNotFoundError" } } export class RegistryUnauthorizedError extends RegistryError { constructor( public readonly url: string, cause?: unknown, ) { const message = `You are not authorized to access the item at ${url}. If this is a remote registry, you may need to authenticate.` super(message, { code: RegistryErrorCode.UNAUTHORIZED, statusCode: 401, cause, context: { url }, suggestion: "Check your authentication credentials and environment variables.", }) this.name = "RegistryUnauthorizedError" } } export class RegistryForbiddenError extends RegistryError { constructor( public readonly url: string, cause?: unknown, ) { const message = `You are not authorized to access the item at ${url}. If this is a remote registry, you may need to authenticate.` super(message, { code: RegistryErrorCode.FORBIDDEN, statusCode: 403, cause, context: { url }, suggestion: "Check your authentication credentials and environment variables.", }) this.name = "RegistryForbiddenError" } } export class RegistryFetchError extends RegistryError { constructor( public readonly url: string, statusCode?: number, public readonly responseBody?: string, cause?: unknown, ) { const baseMessage = statusCode ? `Failed to fetch from registry (${statusCode}): ${url}` : `Failed to fetch from registry: ${url}` const message = typeof cause === "string" && cause ? `${baseMessage} - ${cause}` : baseMessage let suggestion = "Check your network connection and try again." if (statusCode === 404) { suggestion = "The requested resource was not found. Check the URL or item name." } else if (statusCode === 500) { suggestion = "The registry server encountered an error. Try again later." } else if (statusCode && statusCode >= 400 && statusCode < 500) { suggestion = "There was a client error. Check your request parameters." } super(message, { code: RegistryErrorCode.FETCH_ERROR, statusCode, cause, context: { url, responseBody }, suggestion, }) this.name = "RegistryFetchError" } } export class RegistryNotConfiguredError extends RegistryError { constructor(public readonly registryName: string | null) { const message = registryName ? `Unknown registry "${registryName}". Make sure it is defined in agents.json as follows: { "registries": { "${registryName}": "[URL_TO_REGISTRY]" } }` : `Unknown registry. Make sure it is defined in agents.json under "registries".` super(message, { code: RegistryErrorCode.NOT_CONFIGURED, context: { registryName }, suggestion: "Add the registry configuration to your agents.json file. Consult the registry documentation for the correct format.", }) this.name = "RegistryNotConfiguredError" } } export class RegistryLocalFileError extends RegistryError { constructor( public readonly filePath: string, cause?: unknown, ) { super(`Failed to read local registry file: ${filePath}`, { code: RegistryErrorCode.LOCAL_FILE_ERROR, cause, context: { filePath }, suggestion: "Check if the file exists and you have read permissions.", }) this.name = "RegistryLocalFileError" } } export class RegistryParseError extends RegistryError { public readonly parseError: unknown constructor( public readonly item: string, parseError: unknown, ) { let message = `Failed to parse registry item: ${item}` if (parseError instanceof z.ZodError) { message = `Failed to parse registry item: ${item}\n${parseError.issues .map((e) => ` - ${e.path.join(".")}: ${e.message}`) .join("\n")}` } super(message, { code: RegistryErrorCode.PARSE_ERROR, cause: parseError, context: { item }, suggestion: "The registry item may be corrupted or have an invalid format. Please make sure it returns a valid JSON object.", }) this.parseError = parseError this.name = "RegistryParseError" } } export class RegistryMissingEnvironmentVariablesError extends RegistryError { constructor( public readonly registryName: string, public readonly missingVars: string[], ) { const message = `Registry "${registryName}" requires the following environment variables:\n\n` + missingVars.map((v) => ` • ${v}`).join("\n") super(message, { code: RegistryErrorCode.MISSING_ENV_VARS, context: { registryName, missingVars }, suggestion: "Set the required environment variables to your .env or .env.local file.", }) this.name = "RegistryMissingEnvironmentVariablesError" } } export class RegistryInvalidNamespaceError extends RegistryError { constructor(public readonly name: string) { const message = `Invalid registry namespace: "${name}". Registry names must start with @ (e.g., @awesome-ai).` super(message, { code: RegistryErrorCode.VALIDATION_ERROR, context: { name }, suggestion: "Use a valid registry name starting with @ or provide a direct URL to the registry.", }) this.name = "RegistryInvalidNamespaceError" } } export class ConfigMissingError extends RegistryError { constructor(public readonly cwd: string) { const message = `No agents.json found in ${cwd} or parent directories.` super(message, { code: RegistryErrorCode.NOT_CONFIGURED, context: { cwd }, suggestion: "Run 'awesome-ai init' to create an agents.json file, or check that you're in the correct directory.", }) this.name = "ConfigMissingError" } } export class ConfigParseError extends RegistryError { constructor( public readonly cwd: string, parseError: unknown, ) { let message = `Invalid agents.json configuration in ${cwd}.` if (parseError instanceof z.ZodError) { message = `Invalid agents.json configuration in ${cwd}:\n${parseError.issues .map((e) => ` - ${e.path.join(".")}: ${e.message}`) .join("\n")}` } super(message, { code: RegistryErrorCode.INVALID_CONFIG, cause: parseError, context: { cwd }, suggestion: "Check your agents.json file for syntax errors or invalid configuration. Run 'awesome-ai init' to regenerate a valid configuration.", }) this.name = "ConfigParseError" } }