import fs from "node:fs"; import path from "node:path"; import process from "node:process"; import { z } from "zod"; const cliAgentSchema = z.object({ name: z.string().min(1), command: z.string().min(1), args: z.array(z.string()).default([]), inputMode: z.enum(["stdin", "arg"]).default("stdin"), timeoutMs: z.number().int().positive().default(120_000), outputMaxBytes: z.number().int().positive().default(64_000), cwd: z.string().optional() }); const policySchema = z.object({ allowedUsers: z.array(z.string()).default([]), allowedChats: z.array(z.string()).default([]), requireMentionInGroup: z.boolean().default(false) }); const feishuSchema = z.object({ enabled: z.boolean().default(false), appId: z.string().default(""), appSecret: z.string().default(""), verificationToken: z.string().default(""), botNames: z.array(z.string()).default([]) }); const wecomSchema = z.object({ enabled: z.boolean().default(false), corpId: z.string().default(""), agentId: z.string().default(""), secret: z.string().default("") }); const qqSchema = z.object({ enabled: z.boolean().default(false), appId: z.string().default(""), clientSecret: z.string().default(""), botSecret: z.string().default(""), verifySignature: z.boolean().default(true), botNames: z.array(z.string()).default([]) }); const webhookSchema = z.object({ enabled: z.boolean().default(true), secret: z.string().default("") }); const weixinSchema = z.object({ enabled: z.boolean().default(false), mode: z.enum(["external-webhook", "not-implemented"]).default("external-webhook"), secret: z.string().default("") }); export const configSchema = z.object({ server: z.object({ host: z.string().default("0.0.0.0"), port: z.number().int().positive().max(65_535).default(3000), publicBaseUrl: z.string().default("") }).default({}), policy: policySchema.default({}), defaultAgent: z.string().min(1).default("echo"), agents: z.array(cliAgentSchema).min(1), platforms: z.object({ feishu: feishuSchema.default({}), wecom: wecomSchema.default({}), qq: qqSchema.default({}), webhook: webhookSchema.default({}), weixin: weixinSchema.default({}) }).default({}) }); export type AppConfig = z.infer; export type CliAgentConfig = z.infer; export type GatewayPolicy = z.infer; export function resolveConfigPath(configPath = process.env.GORI_GATEWAY_CONFIG): string { return path.resolve(configPath || "config.example.json"); } export function parseConfig(rawConfig: unknown): AppConfig { const config = configSchema.parse(rawConfig); if (!config.agents.some((agent) => agent.name === config.defaultAgent)) { throw new Error(`defaultAgent '${config.defaultAgent}' is not present in agents`); } return config; } export function loadConfig(configPath = process.env.GORI_GATEWAY_CONFIG): AppConfig { return loadConfigFromPath(resolveConfigPath(configPath)); } export function loadConfigFromPath(configPath: string): AppConfig { const raw = fs.readFileSync(configPath, "utf8"); const parsed = JSON.parse(raw) as unknown; return parseConfig(parsed); }