@snack-kit/porygon 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -0
- package/dist/index.cjs +89 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +46 -2
- package/dist/index.d.ts +46 -2
- package/dist/index.js +88 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/porygon.ts","../src/config/defaults.ts","../src/config/schema.ts","../src/errors/index.ts","../src/config/config-loader.ts","../src/interceptor/interceptor.ts","../src/process/process-handle.ts","../src/process/process-manager.ts","../src/session/session-manager.ts","../src/adapters/claude/index.ts","../src/adapters/base.ts","../src/adapters/claude/types.ts","../src/adapters/claude/message-mapper.ts","../src/adapters/opencode/index.ts","../src/adapters/opencode/types.ts","../src/adapters/opencode/api-client.ts","../src/adapters/opencode/message-mapper.ts","../src/interceptor/guard.ts"],"sourcesContent":["import { EventEmitter } from \"node:events\";\nimport type { PorygonConfig } from \"@/types/config.js\";\nimport type { PromptRequest, AgentMessage } from \"@/types/common.js\";\nimport type {\n IAgentAdapter,\n AdapterCapabilities,\n SessionInfo,\n SessionListOptions,\n ModelInfo,\n} from \"@/types/adapter.js\";\nimport { ConfigLoader } from \"@/config/config-loader.js\";\nimport {\n InterceptorManager,\n type InterceptorDirection,\n type InterceptorFn,\n} from \"@/interceptor/interceptor.js\";\nimport { ProcessManager } from \"@/process/process-manager.js\";\nimport { SessionManager } from \"@/session/session-manager.js\";\nimport { ClaudeAdapter } from \"@/adapters/claude/index.js\";\nimport { OpenCodeAdapter } from \"@/adapters/opencode/index.js\";\nimport { AdapterNotFoundError } from \"@/errors/index.js\";\n\n/**\n * 健康检查结果(扁平化结构)\n */\nexport interface HealthCheckResult {\n available: boolean;\n version?: string;\n supported?: boolean;\n warnings?: string[];\n error?: string;\n}\n\n/**\n * Porygon 事件类型定义\n */\nexport interface PorygonEvents {\n \"session:created\": (info: SessionInfo) => void;\n \"session:resumed\": (info: SessionInfo) => void;\n \"process:spawn\": (backend: string, pid: number) => void;\n \"process:exit\": (backend: string, code: number | null) => void;\n \"process:error\": (backend: string, error: Error) => void;\n \"process:restart\": (backend: string, attempt: number) => void;\n \"interceptor:rejected\": (direction: string, reason: string) => void;\n \"health:degraded\": (backend: string, warning: string) => void;\n}\n\n/**\n * Porygon 主门面类,提供统一的 LLM 后端交互接口。\n * 管理适配器注册、拦截器流水线、进程生命周期和会话管理。\n */\nexport class Porygon extends EventEmitter {\n private config: PorygonConfig;\n private adapters = new Map<string, IAgentAdapter>();\n private interceptors: InterceptorManager;\n private processManager: ProcessManager;\n private sessionManager: SessionManager;\n\n constructor(config?: Partial<PorygonConfig>) {\n super();\n this.config = ConfigLoader.load(config);\n this.interceptors = new InterceptorManager();\n this.processManager = new ProcessManager();\n this.sessionManager = new SessionManager();\n\n this.registerBuiltinAdapters();\n }\n\n /**\n * 注册内置适配器\n */\n private registerBuiltinAdapters(): void {\n const claudeConfig = this.config.backends?.[\"claude\"];\n // 将全局代理合并到后端配置(后端级代理优先)\n const mergedClaudeConfig = {\n ...claudeConfig,\n proxy: claudeConfig?.proxy ?? this.config.proxy,\n };\n const claudeAdapter = new ClaudeAdapter(this.processManager, mergedClaudeConfig);\n this.registerAdapter(claudeAdapter);\n\n const opencodeConfig = this.config.backends?.[\"opencode\"];\n const mergedOpencodeConfig = {\n ...opencodeConfig,\n proxy: opencodeConfig?.proxy ?? this.config.proxy,\n };\n const opencodeAdapter = new OpenCodeAdapter(this.processManager, mergedOpencodeConfig);\n this.registerAdapter(opencodeAdapter);\n }\n\n /**\n * 注册自定义适配器\n * @param adapter 适配器实例\n */\n registerAdapter(adapter: IAgentAdapter): void {\n this.adapters.set(adapter.backend, adapter);\n this.sessionManager.registerAdapter(adapter.backend, adapter);\n }\n\n /**\n * 获取指定后端的适配器\n * @param backend 后端名称,默认使用配置中的 defaultBackend\n */\n private getAdapter(backend?: string): IAgentAdapter {\n const name = backend ?? this.config.defaultBackend ?? \"claude\";\n const adapter = this.adapters.get(name);\n if (!adapter) throw new AdapterNotFoundError(name);\n return adapter;\n }\n\n /**\n * 流式查询,返回 AgentMessage 异步生成器。\n * 作为与 LLM 后端交互的主要入口。\n * @param request 提示请求参数\n * @yields AgentMessage 消息流\n */\n async *query(request: PromptRequest): AsyncGenerator<AgentMessage> {\n const adapter = this.getAdapter(request.backend);\n const backendName = adapter.backend;\n\n const mergedRequest = this.mergeRequest(request, backendName);\n\n // 执行输入拦截器\n const processedPrompt = await this.interceptors.processInput(\n mergedRequest.prompt,\n { backend: backendName, sessionId: mergedRequest.resume },\n );\n mergedRequest.prompt = processedPrompt;\n\n for await (const message of adapter.query(mergedRequest)) {\n // 对文本内容执行输出拦截器\n if (message.type === \"assistant\" || message.type === \"result\") {\n const processedText = await this.interceptors.processOutput(\n message.text,\n {\n backend: backendName,\n sessionId: message.sessionId,\n messageType: message.type,\n },\n );\n yield { ...message, text: processedText };\n } else {\n yield message;\n }\n }\n }\n\n /**\n * 简单运行模式,收集所有消息并返回最终结果文本\n * @param request 提示请求参数\n * @returns 最终结果文本\n */\n async run(request: PromptRequest): Promise<string> {\n let resultText = \"\";\n for await (const msg of this.query(request)) {\n if (msg.type === \"result\") {\n resultText = msg.text;\n } else if (msg.type === \"assistant\") {\n resultText = msg.text;\n }\n }\n return resultText;\n }\n\n /**\n * 注册拦截器\n * @param direction 拦截方向\n * @param fn 拦截器函数\n * @returns 取消注册的函数\n */\n use(direction: InterceptorDirection, fn: InterceptorFn): () => void {\n return this.interceptors.use(direction, fn);\n }\n\n /**\n * 获取后端能力声明\n * @param backend 后端名称\n */\n getCapabilities(backend?: string): AdapterCapabilities {\n return this.getAdapter(backend).getCapabilities();\n }\n\n /**\n * 获取指定后端的可用模型列表\n * @param backend 后端名称\n */\n async listModels(backend?: string): Promise<ModelInfo[]> {\n return this.getAdapter(backend).listModels();\n }\n\n /**\n * 检查单个后端的健康状态\n * @param backend 后端名称\n */\n async checkBackend(backend: string): Promise<HealthCheckResult> {\n const adapter = this.getAdapter(backend);\n try {\n const available = await adapter.isAvailable();\n if (!available) {\n return { available: false };\n }\n const compat = await adapter.checkCompatibility();\n const result: HealthCheckResult = {\n available: true,\n version: compat.version,\n supported: compat.supported,\n };\n if (compat.warnings.length > 0) {\n result.warnings = compat.warnings;\n }\n if (!compat.supported) {\n this.emit(\"health:degraded\", backend, compat.warnings.join(\"; \"));\n }\n return result;\n } catch (err) {\n return {\n available: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n }\n\n /**\n * 对所有已注册后端进行健康检查。\n * 返回扁平化结构,包含 version/supported/warnings 等字段。\n */\n async healthCheck(): Promise<Record<string, HealthCheckResult>> {\n const entries = Array.from(this.adapters.keys());\n const checks = entries.map(async (name) => {\n const result = await this.checkBackend(name);\n return [name, result] as const;\n });\n\n const settled = await Promise.allSettled(checks);\n const results: Record<string, HealthCheckResult> = {};\n\n for (const item of settled) {\n if (item.status === \"fulfilled\") {\n const [name, result] = item.value;\n results[name] = result;\n }\n }\n\n return results;\n }\n\n /**\n * 读取或更新后端设置\n * @param backend 后端名称\n * @param newSettings 要更新的设置项(可选)\n * @returns 当前设置\n */\n async settings(\n backend: string,\n newSettings?: Record<string, unknown>,\n ): Promise<Record<string, unknown>> {\n const adapter = this.getAdapter(backend);\n if (newSettings) {\n await adapter.updateSettings(newSettings);\n }\n return adapter.getSettings();\n }\n\n /**\n * 列出指定后端的会话\n * @param backend 后端名称\n * @param options 查询选项\n */\n async listSessions(\n backend?: string,\n options?: SessionListOptions,\n ): Promise<SessionInfo[]> {\n const name = backend ?? this.config.defaultBackend ?? \"claude\";\n return this.sessionManager.list(name, options);\n }\n\n /**\n * 中止正在运行的查询\n * @param backend 后端名称\n * @param sessionId 会话 ID\n */\n abort(backend: string, sessionId: string): void {\n this.getAdapter(backend).abort(sessionId);\n }\n\n /**\n * 释放所有资源\n */\n async dispose(): Promise<void> {\n const promises: Promise<void>[] = [];\n for (const [, adapter] of this.adapters) {\n promises.push(adapter.dispose());\n }\n await Promise.allSettled(promises);\n await this.processManager.terminateAll();\n this.adapters.clear();\n this.sessionManager.clearCache();\n }\n\n /**\n * 合并请求参数与配置默认值。\n *\n * 合并策略:\n * - model: request > backendConfig > 不设置(后端使用自身默认值)\n * - timeoutMs: request > defaults\n * - maxTurns: request > defaults\n * - cwd: request > backendConfig\n * - appendSystemPrompt: **追加模式** — defaults + backendConfig + request 三层拼接(换行分隔)\n * 但如果 request.systemPrompt 已设置(替换模式),则忽略所有 appendSystemPrompt\n *\n * @param request 原始请求\n * @param backend 后端名称\n * @returns 合并后的请求\n */\n private mergeRequest(\n request: PromptRequest,\n backend: string,\n ): PromptRequest {\n const backendConfig = this.config.backends?.[backend];\n const defaults = this.config.defaults;\n\n const appendParts: string[] = [];\n if (defaults?.appendSystemPrompt) {\n appendParts.push(defaults.appendSystemPrompt);\n }\n if (backendConfig?.appendSystemPrompt) {\n appendParts.push(backendConfig.appendSystemPrompt);\n }\n if (request.appendSystemPrompt) {\n appendParts.push(request.appendSystemPrompt);\n }\n\n return {\n ...request,\n model: request.model ?? backendConfig?.model,\n timeoutMs: request.timeoutMs ?? defaults?.timeoutMs,\n maxTurns: request.maxTurns ?? defaults?.maxTurns,\n cwd: request.cwd ?? backendConfig?.cwd,\n appendSystemPrompt: request.systemPrompt\n ? undefined\n : appendParts.length > 0\n ? appendParts.join(\"\\n\")\n : undefined,\n };\n }\n}\n\n/**\n * 创建 Porygon 实例的工厂函数\n * @param config 可选的配置参数\n * @returns Porygon 实例\n */\nexport function createPorygon(config?: Partial<PorygonConfig>): Porygon {\n return new Porygon(config);\n}\n","import type { PorygonConfig } from \"@/types/config.js\";\n\nexport const DEFAULT_CONFIG: Required<Pick<PorygonConfig, \"defaults\">> &\n PorygonConfig = {\n defaultBackend: \"claude\",\n backends: {},\n defaults: {\n timeoutMs: 300_000, // 5 minutes\n maxTurns: 50,\n },\n proxy: undefined,\n};\n\n/** 进程管理默认值 */\nexport const PROCESS_DEFAULTS = {\n GRACE_PERIOD_MS: 5_000,\n MAX_RESTARTS: 3,\n RESTART_INTERVAL_MS: 1_000,\n HEALTH_CHECK_INTERVAL_MS: 30_000,\n} as const;\n","import { z } from \"zod\";\nimport type { PorygonConfig } from \"@/types/config.js\";\nimport { ConfigValidationError } from \"@/errors/index.js\";\n\n/**\n * 代理配置校验 Schema\n */\nexport const ProxyConfigSchema = z.object({\n url: z.string().url(),\n noProxy: z.string().optional(),\n});\n\n/**\n * 后端配置校验 Schema\n */\nexport const BackendConfigSchema = z.object({\n model: z.string().optional(),\n appendSystemPrompt: z.string().optional(),\n proxy: ProxyConfigSchema.optional(),\n cwd: z.string().optional(),\n serverUrl: z.string().optional(),\n apiKey: z.string().optional(),\n interactive: z.boolean().optional(),\n cliPath: z.string().optional(),\n options: z.record(z.string(), z.unknown()).optional(),\n});\n\n/**\n * Porygon 全局配置校验 Schema\n */\nexport const PorygonConfigSchema = z.object({\n defaultBackend: z.string().optional(),\n backends: z.record(z.string(), BackendConfigSchema).optional(),\n defaults: z\n .object({\n appendSystemPrompt: z.string().optional(),\n timeoutMs: z.number().positive().optional(),\n maxTurns: z.number().int().positive().optional(),\n })\n .optional(),\n proxy: ProxyConfigSchema.optional(),\n});\n\n/**\n * 校验配置并返回类型安全的结果\n * @param config - 待校验的配置对象\n * @returns 校验通过的配置\n * @throws ConfigValidationError 校验失败时抛出\n */\nexport function validateConfig(config: unknown): PorygonConfig {\n const result = PorygonConfigSchema.safeParse(config);\n if (!result.success) {\n const issues = result.error.issues.map((issue) => ({\n path: issue.path.join(\".\"),\n message: issue.message,\n }));\n throw new ConfigValidationError(\n `配置校验失败: ${issues.map((i) => `${i.path}: ${i.message}`).join(\"; \")}`\n );\n }\n return result.data;\n}\n","/**\n * Porygon 基础错误类\n */\nexport class PorygonError extends Error {\n readonly code: string;\n\n constructor(code: string, message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = \"PorygonError\";\n this.code = code;\n }\n}\n\nexport class AdapterNotFoundError extends PorygonError {\n constructor(backend: string, options?: ErrorOptions) {\n super(\"ADAPTER_NOT_FOUND\", `Adapter not found: ${backend}`, options);\n this.name = \"AdapterNotFoundError\";\n }\n}\n\nexport class AdapterNotAvailableError extends PorygonError {\n constructor(backend: string, options?: ErrorOptions) {\n super(\"ADAPTER_NOT_AVAILABLE\", `Adapter not available: ${backend}`, options);\n this.name = \"AdapterNotAvailableError\";\n }\n}\n\nexport class AdapterIncompatibleError extends PorygonError {\n constructor(backend: string, version: string, options?: ErrorOptions) {\n super(\n \"ADAPTER_INCOMPATIBLE\",\n `Adapter incompatible: ${backend} version ${version}`,\n options,\n );\n this.name = \"AdapterIncompatibleError\";\n }\n}\n\nexport class SessionNotFoundError extends PorygonError {\n constructor(sessionId: string, options?: ErrorOptions) {\n super(\"SESSION_NOT_FOUND\", `Session not found: ${sessionId}`, options);\n this.name = \"SessionNotFoundError\";\n }\n}\n\nexport class InterceptorRejectedError extends PorygonError {\n constructor(reason: string, options?: ErrorOptions) {\n super(\"INTERCEPTOR_REJECTED\", `Interceptor rejected: ${reason}`, options);\n this.name = \"InterceptorRejectedError\";\n }\n}\n\nexport class AgentExecutionError extends PorygonError {\n constructor(message: string, options?: ErrorOptions) {\n super(\"AGENT_EXECUTION_ERROR\", message, options);\n this.name = \"AgentExecutionError\";\n }\n}\n\nexport class AgentTimeoutError extends PorygonError {\n constructor(timeoutMs: number, options?: ErrorOptions) {\n super(\"AGENT_TIMEOUT\", `Agent timed out after ${timeoutMs}ms`, options);\n this.name = \"AgentTimeoutError\";\n }\n}\n\nexport class ConfigValidationError extends PorygonError {\n constructor(message: string, options?: ErrorOptions) {\n super(\"CONFIG_VALIDATION_ERROR\", message, options);\n this.name = \"ConfigValidationError\";\n }\n}\n","import type { PorygonConfig } from \"@/types/config.js\";\nimport { DEFAULT_CONFIG } from \"./defaults.js\";\nimport { validateConfig } from \"./schema.js\";\n\n/**\n * 判断值是否为普通对象\n */\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * 深度合并两个对象,source 覆盖 target 中的同名属性\n * @param target - 基础对象\n * @param source - 覆盖对象\n * @returns 合并后的新对象\n */\nfunction deepMerge<T extends Record<string, unknown>>(\n target: T,\n source: Partial<T>\n): T {\n const result = { ...target } as Record<string, unknown>;\n\n for (const key of Object.keys(source)) {\n const sourceVal = source[key as keyof typeof source];\n const targetVal = result[key];\n\n if (sourceVal === undefined) {\n continue;\n }\n\n if (isPlainObject(targetVal) && isPlainObject(sourceVal)) {\n result[key] = deepMerge(\n targetVal as Record<string, unknown>,\n sourceVal as Record<string, unknown>\n );\n } else {\n result[key] = sourceVal;\n }\n }\n\n return result as T;\n}\n\n/**\n * 从环境变量读取配置覆盖\n */\nfunction loadEnvOverrides(): Partial<PorygonConfig> {\n const config: Partial<PorygonConfig> = {};\n\n const defaultBackend = process.env[\"PORYGON_DEFAULT_BACKEND\"];\n if (defaultBackend) {\n config.defaultBackend = defaultBackend;\n }\n\n const proxyUrl = process.env[\"PORYGON_PROXY_URL\"];\n if (proxyUrl) {\n config.proxy = {\n url: proxyUrl,\n noProxy: process.env[\"PORYGON_PROXY_NO_PROXY\"],\n };\n }\n\n return config;\n}\n\n/**\n * ConfigLoader: 从多个来源加载并合并配置。\n *\n * 优先级(后者覆盖前者):\n * 1. 内置默认值\n * 2. 环境变量 (PORYGON_DEFAULT_BACKEND, PORYGON_PROXY_URL, PORYGON_PROXY_NO_PROXY)\n * 3. createPorygon(config) 编程式传入\n */\nexport class ConfigLoader {\n /**\n * 加载并合并配置\n * @param userConfig - 用户传入的配置(可选)\n * @returns 校验通过的最终配置\n * @throws ConfigValidationError 校验失败时抛出\n */\n static load(userConfig?: Partial<PorygonConfig>): PorygonConfig {\n // 1. 以默认值为基础\n let merged: Record<string, unknown> = { ...DEFAULT_CONFIG };\n\n // 2. 应用环境变量覆盖\n const envOverrides = loadEnvOverrides();\n merged = deepMerge(merged, envOverrides);\n\n // 3. 深度合并用户配置\n if (userConfig) {\n merged = deepMerge(merged, userConfig);\n }\n\n // 4. 使用 Zod Schema 校验\n return validateConfig(merged);\n }\n}\n","import { InterceptorRejectedError } from \"@/errors/index.js\";\n\nexport type InterceptorDirection = \"input\" | \"output\";\n\nexport interface InterceptorContext {\n direction: InterceptorDirection;\n backend: string;\n sessionId?: string;\n /** 仅输出方向可用 */\n messageType?: string;\n}\n\n/**\n * 拦截器函数签名\n * - 返回 string: 替换文本,传递给下一个拦截器\n * - 返回 false: 拒绝消息,抛出 InterceptorRejectedError\n * - 返回 true/undefined: 不修改,传递原始文本给下一个拦截器\n */\nexport type InterceptorFn = (\n text: string,\n context: InterceptorContext\n) => string | boolean | undefined | Promise<string | boolean | undefined>;\n\n/**\n * 拦截器管理器,用于对输入/输出消息进行流水线式处理\n */\nexport class InterceptorManager {\n private inputInterceptors: InterceptorFn[] = [];\n private outputInterceptors: InterceptorFn[] = [];\n\n /**\n * 注册拦截器\n * @param direction - 拦截方向\n * @param fn - 拦截器函数\n * @returns 取消注册的函数\n */\n use(direction: InterceptorDirection, fn: InterceptorFn): () => void {\n const list =\n direction === \"input\" ? this.inputInterceptors : this.outputInterceptors;\n list.push(fn);\n\n return () => {\n const idx = list.indexOf(fn);\n if (idx !== -1) {\n list.splice(idx, 1);\n }\n };\n }\n\n /**\n * 执行输入拦截器流水线\n * @param text - 原始输入文本\n * @param context - 拦截器上下文(不含 direction)\n * @returns 处理后的文本\n * @throws InterceptorRejectedError 拦截器返回 false 时抛出\n */\n async processInput(\n text: string,\n context: Omit<InterceptorContext, \"direction\">\n ): Promise<string> {\n return this.runPipeline(text, \"input\", context, this.inputInterceptors);\n }\n\n /**\n * 执行输出拦截器流水线\n * @param text - 原始输出文本\n * @param context - 拦截器上下文(不含 direction)\n * @returns 处理后的文本\n * @throws InterceptorRejectedError 拦截器返回 false 时抛出\n */\n async processOutput(\n text: string,\n context: Omit<InterceptorContext, \"direction\">\n ): Promise<string> {\n return this.runPipeline(text, \"output\", context, this.outputInterceptors);\n }\n\n /**\n * 执行拦截器流水线\n */\n private async runPipeline(\n text: string,\n direction: InterceptorDirection,\n context: Omit<InterceptorContext, \"direction\">,\n interceptors: InterceptorFn[]\n ): Promise<string> {\n const fullContext: InterceptorContext = { ...context, direction };\n let current = text;\n\n for (const fn of interceptors) {\n const result = await fn(current, fullContext);\n\n if (result === false) {\n throw new InterceptorRejectedError(direction);\n }\n\n if (typeof result === \"string\") {\n current = result;\n }\n // true / undefined -> 不修改,继续传递 current\n }\n\n return current;\n }\n}\n","import { spawn, type ChildProcess } from \"node:child_process\";\nimport { EventEmitter } from \"node:events\";\nimport { createInterface } from \"node:readline\";\nimport type {\n SpawnOptions,\n ProcessResult,\n PersistentProcessOptions,\n} from \"@/types/process.js\";\n\n/** 优雅终止等待时长(毫秒) */\nconst GRACE_PERIOD_MS = 5_000;\n\n/**\n * EphemeralProcess:一次性进程执行,支持流式输出。\n * 适用于 `claude -p` 和 `opencode run` 等短生命周期调用场景。\n */\nexport class EphemeralProcess {\n private childProcess: ChildProcess | null = null;\n private aborted = false;\n\n /**\n * 执行命令并收集输出。支持 AbortController 进行取消操作。\n * @param options 进程启动选项\n * @param abortSignal 可选的中止信号\n * @returns 进程执行结果\n */\n async execute(\n options: SpawnOptions,\n abortSignal?: AbortSignal,\n ): Promise<ProcessResult> {\n return new Promise<ProcessResult>((resolve, reject) => {\n if (abortSignal?.aborted) {\n reject(new Error(\"Process aborted before start\"));\n return;\n }\n\n this.aborted = false;\n const child = spawn(options.command, options.args, {\n cwd: options.cwd,\n env: options.env ? { ...process.env, ...options.env } : undefined,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n this.childProcess = child;\n\n const stdoutChunks: Buffer[] = [];\n const stderrChunks: Buffer[] = [];\n\n child.stdout?.on(\"data\", (chunk: Buffer) => {\n stdoutChunks.push(chunk);\n });\n\n child.stderr?.on(\"data\", (chunk: Buffer) => {\n stderrChunks.push(chunk);\n });\n\n let timeoutTimer: ReturnType<typeof setTimeout> | undefined;\n if (options.timeoutMs !== undefined && options.timeoutMs > 0) {\n timeoutTimer = setTimeout(() => {\n this.terminate();\n reject(new Error(`Process timed out after ${options.timeoutMs}ms`));\n }, options.timeoutMs);\n }\n\n const onAbort = (): void => {\n this.terminate();\n reject(new Error(\"Process aborted\"));\n };\n abortSignal?.addEventListener(\"abort\", onAbort, { once: true });\n\n child.on(\"error\", (err: Error) => {\n if (timeoutTimer) clearTimeout(timeoutTimer);\n abortSignal?.removeEventListener(\"abort\", onAbort);\n this.childProcess = null;\n reject(err);\n });\n\n child.on(\"close\", (code: number | null, signal: NodeJS.Signals | null) => {\n if (timeoutTimer) clearTimeout(timeoutTimer);\n abortSignal?.removeEventListener(\"abort\", onAbort);\n this.childProcess = null;\n resolve({\n exitCode: code,\n signal: signal,\n stdout: Buffer.concat(stdoutChunks).toString(\"utf-8\"),\n stderr: Buffer.concat(stderrChunks).toString(\"utf-8\"),\n });\n });\n });\n }\n\n /**\n * 以流式方式执行命令,逐行输出 stdout 内容。\n * @param options 进程启动选项\n * @param abortSignal 可选的中止信号\n */\n async *executeStreaming(\n options: SpawnOptions,\n abortSignal?: AbortSignal,\n ): AsyncGenerator<string> {\n if (abortSignal?.aborted) {\n throw new Error(\"Process aborted before start\");\n }\n\n this.aborted = false;\n const child = spawn(options.command, options.args, {\n cwd: options.cwd,\n env: options.env ?? undefined,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n this.childProcess = child;\n\n let timeoutTimer: ReturnType<typeof setTimeout> | undefined;\n if (options.timeoutMs !== undefined && options.timeoutMs > 0) {\n timeoutTimer = setTimeout(() => {\n this.terminate();\n }, options.timeoutMs);\n }\n\n const onAbort = (): void => {\n this.terminate();\n };\n abortSignal?.addEventListener(\"abort\", onAbort, { once: true });\n\n // 收集 stderr 用于错误诊断\n const stderrChunks: Buffer[] = [];\n child.stderr?.on(\"data\", (chunk: Buffer) => {\n stderrChunks.push(chunk);\n });\n\n // 监听子进程退出码\n let exitCode: number | null = null;\n const exitPromise = new Promise<void>((resolve) => {\n child.on(\"close\", (code) => {\n exitCode = code;\n resolve();\n });\n });\n\n // 使用 readline 进行逐行读取\n const rl = createInterface({ input: child.stdout! });\n let yieldedLines = 0;\n\n try {\n for await (const line of rl) {\n yieldedLines++;\n yield line;\n }\n\n // readline 结束后等待进程退出,获取退出码\n await exitPromise;\n\n // 进程非正常退出且没有产出任何数据时,将 stderr 作为错误抛出\n if (exitCode !== 0 && yieldedLines === 0 && !this.aborted) {\n const stderr = Buffer.concat(stderrChunks).toString(\"utf-8\").trim();\n throw new Error(\n stderr || `Process exited with code ${exitCode}`,\n );\n }\n } finally {\n if (timeoutTimer) clearTimeout(timeoutTimer);\n abortSignal?.removeEventListener(\"abort\", onAbort);\n rl.close();\n this.childProcess = null;\n }\n }\n\n /** 获取底层子进程的 PID */\n get pid(): number | undefined {\n return this.childProcess?.pid;\n }\n\n /** 终止进程:先发送 SIGTERM,超时后发送 SIGKILL */\n terminate(): void {\n if (!this.childProcess || this.aborted) return;\n this.aborted = true;\n this.childProcess.kill(\"SIGTERM\");\n const ref = this.childProcess;\n setTimeout(() => {\n if (!ref.killed) {\n ref.kill(\"SIGKILL\");\n }\n }, GRACE_PERIOD_MS);\n }\n}\n\n/**\n * PersistentProcess:长期运行的服务进程,支持自动重启。\n * 适用于 `opencode serve` 等持久化服务场景。\n */\nexport class PersistentProcess extends EventEmitter {\n private process: ChildProcess | null = null;\n private restartCount = 0;\n private stopped = false;\n private healthCheckTimer: ReturnType<typeof setInterval> | null = null;\n private readonly options: PersistentProcessOptions;\n\n constructor(options: PersistentProcessOptions) {\n super();\n this.options = options;\n }\n\n /** 启动持久进程 */\n async start(): Promise<void> {\n this.stopped = false;\n\n const child = spawn(this.options.command, this.options.args, {\n cwd: this.options.cwd,\n env: this.options.env\n ? { ...process.env, ...this.options.env }\n : undefined,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n this.process = child;\n\n child.on(\"error\", (err: Error) => {\n this.emit(\"error\", err);\n });\n\n child.on(\"exit\", (code: number | null) => {\n this.process = null;\n this.stopHealthCheck();\n this.handleCrash(code);\n });\n\n // 启动健康检查\n if (this.options.healthCheckFn && this.options.healthCheckIntervalMs > 0) {\n this.healthCheckTimer = setInterval(() => {\n this.options.healthCheckFn!().catch((err: unknown) => {\n this.emit(\"healthCheckFailed\", err);\n });\n }, this.options.healthCheckIntervalMs);\n }\n\n this.emit(\"started\", child.pid);\n }\n\n /** 处理进程崩溃,按指数退避策略重启 */\n private handleCrash(code: number | null): void {\n if (this.stopped) return;\n\n this.emit(\"exit\", code);\n\n if (this.restartCount < this.options.maxRestarts) {\n const delay =\n this.options.restartIntervalMs * Math.pow(2, this.restartCount);\n this.restartCount++;\n this.emit(\"restart\", this.restartCount);\n\n setTimeout(() => {\n if (!this.stopped) {\n this.start().catch((err: unknown) => {\n this.emit(\"fatal\", err);\n });\n }\n }, delay);\n } else {\n this.emit(\n \"fatal\",\n new Error(\n `Max restarts (${this.options.maxRestarts}) exceeded, last exit code: ${code}`,\n ),\n );\n }\n }\n\n /** 停止健康检查定时器 */\n private stopHealthCheck(): void {\n if (this.healthCheckTimer) {\n clearInterval(this.healthCheckTimer);\n this.healthCheckTimer = null;\n }\n }\n\n /** 停止持久进程 */\n async stop(): Promise<void> {\n this.stopped = true;\n this.stopHealthCheck();\n\n if (this.process) {\n const child = this.process;\n child.kill(\"SIGTERM\");\n\n await new Promise<void>((resolve) => {\n const timer = setTimeout(() => {\n if (!child.killed) {\n child.kill(\"SIGKILL\");\n }\n resolve();\n }, GRACE_PERIOD_MS);\n\n child.on(\"exit\", () => {\n clearTimeout(timer);\n resolve();\n });\n });\n\n this.process = null;\n }\n }\n\n /** 获取底层子进程的 PID */\n get pid(): number | undefined {\n return this.process?.pid;\n }\n\n /** 当前进程是否正在运行 */\n get isRunning(): boolean {\n return this.process !== null && !this.process.killed;\n }\n}\n","import { EphemeralProcess, PersistentProcess } from \"./process-handle.js\";\nimport type { PersistentProcessOptions } from \"@/types/process.js\";\n\n/**\n * ProcessManager:统一管理所有子进程。\n * 注册退出钩子,确保主进程退出时清理所有子进程。\n */\nexport class ProcessManager {\n private readonly ephemeral = new Map<string, EphemeralProcess>();\n private readonly persistent = new Map<string, PersistentProcess>();\n\n /** 全局静态标记,确保信号处理器只注册一次 */\n private static cleanupRegistered = false;\n /** 所有活跃的 ProcessManager 实例(弱引用避免阻止 GC) */\n private static readonly instances = new Set<ProcessManager>();\n\n constructor() {\n ProcessManager.instances.add(this);\n ProcessManager.registerCleanup();\n }\n\n /** 注册进程退出清理钩子(仅清理资源,不劫持宿主退出行为) */\n private static registerCleanup(): void {\n if (ProcessManager.cleanupRegistered) return;\n ProcessManager.cleanupRegistered = true;\n\n const cleanup = (): void => {\n for (const instance of ProcessManager.instances) {\n instance.terminateAllSync();\n }\n };\n\n process.on(\"exit\", cleanup);\n\n // 信号处理:仅清理子进程资源,不调用 process.exit(),\n // 让宿主进程自行决定退出逻辑\n process.on(\"SIGTERM\", cleanup);\n process.on(\"SIGINT\", cleanup);\n }\n\n /**\n * 创建一次性进程实例并注册到管理器\n * @param sessionId 会话标识\n * @returns 一次性进程实例\n */\n createEphemeral(sessionId: string): EphemeralProcess {\n const proc = new EphemeralProcess();\n this.ephemeral.set(sessionId, proc);\n return proc;\n }\n\n /**\n * 从管理器中移除一次性进程\n * @param sessionId 会话标识\n */\n removeEphemeral(sessionId: string): void {\n this.ephemeral.delete(sessionId);\n }\n\n /**\n * 启动或获取持久进程\n * @param backend 后端标识\n * @param options 持久进程选项\n * @returns 持久进程实例\n */\n async startPersistent(\n backend: string,\n options: PersistentProcessOptions,\n ): Promise<PersistentProcess> {\n const existing = this.persistent.get(backend);\n if (existing?.isRunning) return existing;\n\n const proc = new PersistentProcess(options);\n this.persistent.set(backend, proc);\n await proc.start();\n return proc;\n }\n\n /**\n * 获取指定后端的持久进程\n * @param backend 后端标识\n */\n getPersistent(backend: string): PersistentProcess | undefined {\n return this.persistent.get(backend);\n }\n\n /**\n * 获取指定会话的一次性进程\n * @param sessionId 会话标识\n */\n getEphemeral(sessionId: string): EphemeralProcess | undefined {\n return this.ephemeral.get(sessionId);\n }\n\n /** 异步终止所有托管进程 */\n async terminateAll(): Promise<void> {\n const promises: Promise<void>[] = [];\n\n for (const [, proc] of this.ephemeral) {\n proc.terminate();\n }\n\n for (const [, proc] of this.persistent) {\n promises.push(proc.stop());\n }\n\n this.ephemeral.clear();\n await Promise.allSettled(promises);\n this.persistent.clear();\n }\n\n /** 同步终止所有托管进程(用于 exit 钩子) */\n private terminateAllSync(): void {\n for (const [, proc] of this.ephemeral) {\n proc.terminate();\n }\n\n for (const [, proc] of this.persistent) {\n const pid = proc.pid;\n if (pid) {\n try {\n process.kill(pid, \"SIGTERM\");\n } catch {\n // 进程可能已退出,忽略错误\n }\n }\n }\n }\n\n /**\n * 销毁实例,从全局实例列表中移除\n */\n destroy(): void {\n ProcessManager.instances.delete(this);\n }\n}\n","import type { IAgentAdapter, SessionInfo, SessionListOptions } from \"@/types/adapter.js\";\nimport type { AgentMessage } from \"@/types/common.js\";\nimport { SessionNotFoundError, AdapterNotFoundError } from \"@/errors/index.js\";\n\n/**\n * SessionManager: 管理会话生命周期,委托后端适配器执行实际操作。\n * 会话归属于后端适配器,本类提供缓存与统一访问接口。\n */\nexport class SessionManager {\n private cache = new Map<string, SessionInfo>();\n private adapters = new Map<string, IAgentAdapter>();\n\n /**\n * 注册适配器用于会话管理\n * @param backend 后端标识\n * @param adapter 适配器实例\n */\n registerAdapter(backend: string, adapter: IAgentAdapter): void {\n this.adapters.set(backend, adapter);\n }\n\n /**\n * 注销适配器\n * @param backend 后端标识\n */\n unregisterAdapter(backend: string): void {\n this.adapters.delete(backend);\n }\n\n /**\n * 获取指定后端的适配器,不存在时抛出错误\n * @param backend 后端标识\n */\n private getAdapter(backend: string): IAgentAdapter {\n const adapter = this.adapters.get(backend);\n if (!adapter) {\n throw new AdapterNotFoundError(backend);\n }\n return adapter;\n }\n\n /**\n * 列出指定后端的会话,结果会写入缓存\n * @param backend 后端标识\n * @param options 查询选项\n */\n async list(backend: string, options?: SessionListOptions): Promise<SessionInfo[]> {\n const adapter = this.getAdapter(backend);\n const sessions = await adapter.listSessions(options);\n for (const session of sessions) {\n this.cache.set(session.sessionId, session);\n }\n return sessions;\n }\n\n /**\n * 从缓存中获取会话信息\n * @param sessionId 会话 ID\n */\n get(sessionId: string): SessionInfo | undefined {\n return this.cache.get(sessionId);\n }\n\n /**\n * 恢复会话,委托适配器以 resume 标志执行查询\n * @param backend 后端标识\n * @param sessionId 要恢复的会话 ID\n * @param prompt 提示词\n */\n async *resume(\n backend: string,\n sessionId: string,\n prompt: string\n ): AsyncGenerator<AgentMessage> {\n const adapter = this.getAdapter(backend);\n yield* adapter.query({ prompt, resume: sessionId });\n }\n\n /**\n * 从缓存中移除指定会话\n * @param sessionId 会话 ID\n */\n evict(sessionId: string): void {\n this.cache.delete(sessionId);\n }\n\n /**\n * 清空全部会话缓存\n */\n clearCache(): void {\n this.cache.clear();\n }\n}\n","import { readFile, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { randomUUID } from \"node:crypto\";\nimport { AbstractAgentAdapter } from \"@/adapters/base.js\";\nimport { EphemeralProcess } from \"@/process/process-handle.js\";\nimport type {\n PromptRequest,\n AgentMessage,\n AdapterCapabilities,\n SessionInfo,\n SessionListOptions,\n ModelInfo,\n} from \"@/types/index.js\";\nimport { mapClaudeEvent } from \"./message-mapper.js\";\n\n/** Claude 设置文件路径 */\nconst CLAUDE_SETTINGS_PATH = join(homedir(), \".claude\", \"settings.json\");\n\n/** Claude 可用模型列表(使用别名自动匹配最新版本) */\nconst CLAUDE_MODELS: ModelInfo[] = [\n { id: \"sonnet\", name: \"Sonnet\", provider: \"anthropic\" },\n { id: \"opus\", name: \"Opus\", provider: \"anthropic\" },\n { id: \"haiku\", name: \"Haiku\", provider: \"anthropic\" },\n];\n\n/**\n * Claude Code CLI 适配器。\n * 通过 `claude -p --output-format stream-json` 命令与 Claude Code 交互。\n */\nexport class ClaudeAdapter extends AbstractAgentAdapter {\n readonly backend = \"claude\";\n\n /** CLI 命令名或路径 */\n private get cliCommand(): string {\n return this.config?.cliPath ?? \"claude\";\n }\n\n /**\n * 检查 Claude CLI 是否可用\n */\n async isAvailable(): Promise<boolean> {\n try {\n const proc = new EphemeralProcess();\n const result = await proc.execute({\n command: \"which\",\n args: [this.cliCommand],\n });\n return result.exitCode === 0;\n } catch {\n return false;\n }\n }\n\n /**\n * 获取 Claude CLI 版本号\n */\n async getVersion(): Promise<string> {\n const proc = new EphemeralProcess();\n const result = await proc.execute({\n command: this.cliCommand,\n args: [\"--version\"],\n });\n\n if (result.exitCode !== 0) {\n throw new Error(`获取 Claude 版本失败: ${result.stderr}`);\n }\n\n // claude --version 输出格式可能为 \"claude X.Y.Z\" 或纯版本号\n const output = result.stdout.trim();\n const match = /(\\d+\\.\\d+\\.\\d+)/.exec(output);\n if (!match) {\n throw new Error(`无法解析 Claude 版本号: ${output}`);\n }\n\n return match[1];\n }\n\n /**\n * 获取 Claude 适配器能力声明\n */\n getCapabilities(): AdapterCapabilities {\n return {\n features: new Set([\n \"streaming\",\n \"session-resume\",\n \"system-prompt\",\n \"tool-restriction\",\n \"mcp\",\n \"subagents\",\n \"worktree\",\n ]),\n streamingMode: \"chunked\",\n outputFormats: [\"text\", \"json\", \"stream-json\"],\n testedVersionRange: \">=1.0.0\",\n };\n }\n\n /**\n * 向 Claude 发送提示并以流式方式接收响应\n * @param request 提示请求参数\n */\n async *query(request: PromptRequest): AsyncGenerator<AgentMessage> {\n const sessionId = request.resume ?? randomUUID();\n const controller = this.createAbortController(sessionId);\n const proc = this.processManager.createEphemeral(sessionId);\n\n try {\n const args = this.buildArgs(request);\n const cwd = request.cwd ?? this.config?.cwd;\n\n // 构建子进程环境变量:排除 CLAUDECODE,注入代理和请求级环境变量\n const cleanEnv: Record<string, string> = {};\n for (const [k, v] of Object.entries(process.env)) {\n if (k !== \"CLAUDECODE\" && v !== undefined) {\n cleanEnv[k] = v;\n }\n }\n\n // 注入代理环境变量(配置级)\n const proxyUrl = this.config?.proxy?.url;\n if (proxyUrl) {\n this.applyProxyEnv(cleanEnv, proxyUrl, this.config?.proxy?.noProxy);\n }\n\n // 注入请求级环境变量(最高优先级,可覆盖上面的所有变量)\n if (request.envVars) {\n for (const [k, v] of Object.entries(request.envVars)) {\n if (v) cleanEnv[k] = v;\n }\n }\n\n const streamOptions = {\n command: this.cliCommand,\n args,\n ...(cwd ? { cwd } : {}),\n env: cleanEnv,\n timeoutMs: request.timeoutMs,\n };\n\n // 输出调试信息:完整的 CLI 命令\n const cmdStr = [this.cliCommand, ...args.map(a => /[\\s\"']/.test(a) ? JSON.stringify(a) : a)].join(\" \");\n const debugCmd = cwd ? `cd ${JSON.stringify(cwd)} && ${cmdStr}` : cmdStr;\n // 调试命令信息通过 system 消息输出,避免直接使用 console\n\n yield {\n type: \"system\" as const,\n timestamp: Date.now(),\n sessionId,\n cwd,\n raw: { debug_command: debugCmd },\n };\n\n for await (const line of proc.executeStreaming(\n streamOptions,\n controller.signal,\n )) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(trimmed) as Record<string, unknown>;\n } catch {\n // JSON 解析失败,跳过该行\n // JSON 解析失败的行静默跳过,非结构化输出无需处理\n continue;\n }\n\n const messages = mapClaudeEvent(parsed, sessionId);\n for (const message of messages) {\n yield message;\n }\n }\n } finally {\n this.removeAbortController(sessionId);\n this.processManager.removeEphemeral(sessionId);\n }\n }\n\n /**\n * 列出 Claude 会话\n * @param options 查询选项\n */\n async listSessions(options?: SessionListOptions): Promise<SessionInfo[]> {\n const proc = new EphemeralProcess();\n const args = [\"sessions\", \"list\", \"--output\", \"json\"];\n\n if (options?.limit) {\n args.push(\"--limit\", String(options.limit));\n }\n\n const result = await proc.execute({\n command: this.cliCommand,\n args,\n cwd: options?.cwd,\n });\n\n if (result.exitCode !== 0) {\n throw new Error(`获取 Claude 会话列表失败: ${result.stderr}`);\n }\n\n const output = result.stdout.trim();\n if (!output) return [];\n\n let rawSessions: unknown;\n try {\n rawSessions = JSON.parse(output);\n } catch {\n throw new Error(`解析 Claude 会话列表失败: ${output.slice(0, 200)}`);\n }\n\n if (!Array.isArray(rawSessions)) return [];\n\n return rawSessions.map((session: unknown) => {\n const s = session as Record<string, unknown>;\n return {\n sessionId: String(s[\"id\"] ?? s[\"session_id\"] ?? \"\"),\n backend: this.backend,\n summary: typeof s[\"summary\"] === \"string\" ? s[\"summary\"] : undefined,\n lastModified:\n typeof s[\"last_modified\"] === \"number\"\n ? s[\"last_modified\"]\n : typeof s[\"last_modified\"] === \"string\"\n ? new Date(s[\"last_modified\"]).getTime()\n : Date.now(),\n cwd: typeof s[\"cwd\"] === \"string\" ? s[\"cwd\"] : undefined,\n metadata: s as Record<string, unknown>,\n };\n });\n }\n\n /**\n * 获取 Claude 可用模型列表。\n * Claude CLI 支持使用简短别名(sonnet/opus/haiku)自动选择当前最新版本。\n */\n async listModels(): Promise<ModelInfo[]> {\n return CLAUDE_MODELS;\n }\n\n /**\n * 读取 Claude 设置\n */\n async getSettings(): Promise<Record<string, unknown>> {\n try {\n const content = await readFile(CLAUDE_SETTINGS_PATH, \"utf-8\");\n const parsed: unknown = JSON.parse(content);\n if (typeof parsed === \"object\" && parsed !== null) {\n return parsed as Record<string, unknown>;\n }\n return {};\n } catch {\n return {};\n }\n }\n\n /**\n * 更新 Claude 设置(读取-合并-写入)\n * @param settings 要合并的设置项\n */\n async updateSettings(settings: Record<string, unknown>): Promise<void> {\n const current = await this.getSettings();\n const merged = { ...current, ...settings };\n await writeFile(\n CLAUDE_SETTINGS_PATH,\n JSON.stringify(merged, null, 2),\n \"utf-8\",\n );\n }\n\n /**\n * 释放适配器资源\n */\n async dispose(): Promise<void> {\n // 中止所有活跃会话\n for (const [sessionId] of this.abortControllers) {\n this.abort(sessionId);\n }\n }\n\n /**\n * 将代理配置注入到环境变量中\n * @param env 环境变量对象\n * @param proxyUrl 代理地址\n * @param noProxy 不走代理的地址列表\n */\n private applyProxyEnv(env: Record<string, string>, proxyUrl: string, noProxy?: string): void {\n env[\"http_proxy\"] = proxyUrl;\n env[\"https_proxy\"] = proxyUrl;\n env[\"HTTP_PROXY\"] = proxyUrl;\n env[\"HTTPS_PROXY\"] = proxyUrl;\n env[\"all_proxy\"] = proxyUrl;\n env[\"ALL_PROXY\"] = proxyUrl;\n if (noProxy) {\n env[\"no_proxy\"] = noProxy;\n env[\"NO_PROXY\"] = noProxy;\n }\n }\n\n private buildArgs(request: PromptRequest): string[] {\n const args: string[] = [\n \"-p\",\n request.prompt,\n \"--output-format\",\n \"stream-json\",\n \"--verbose\",\n ];\n\n // 恢复会话\n if (request.resume) {\n args.push(\"--resume\", request.resume);\n }\n\n // 模型选择\n const model = request.model ?? this.config?.model;\n if (model) {\n args.push(\"--model\", model);\n }\n\n // 系统提示词\n if (request.systemPrompt) {\n args.push(\"--system-prompt\", request.systemPrompt);\n }\n\n const appendPrompt =\n request.appendSystemPrompt ?? this.config?.appendSystemPrompt;\n if (appendPrompt) {\n args.push(\"--append-system-prompt\", appendPrompt);\n }\n\n // 工具限制\n if (request.allowedTools && request.allowedTools.length > 0) {\n for (const tool of request.allowedTools) {\n args.push(\"--allowedTools\", tool);\n }\n }\n\n if (request.disallowedTools && request.disallowedTools.length > 0) {\n for (const tool of request.disallowedTools) {\n args.push(\"--disallowedTools\", tool);\n }\n }\n\n // 最大轮次\n if (request.maxTurns !== undefined) {\n args.push(\"--max-turns\", String(request.maxTurns));\n }\n\n // 跳过权限确认(非交互模式必需)\n // 优先从 BackendConfig.interactive 读取,false 表示跳过权限确认\n // 向后兼容:仍支持 options.dangerouslySkipPermissions\n const interactive = this.config?.interactive;\n const skipPerms = interactive === false\n || request.backendOptions?.dangerouslySkipPermissions\n || this.config?.options?.dangerouslySkipPermissions;\n if (skipPerms) {\n args.push(\"--dangerously-skip-permissions\");\n }\n\n // MCP 服务器配置\n if (request.mcpServers) {\n for (const [name, config] of Object.entries(request.mcpServers)) {\n const serverSpec: Record<string, unknown> = {\n command: config.command,\n ...(config.args ? { args: config.args } : {}),\n ...(config.env ? { env: config.env } : {}),\n ...(config.url ? { url: config.url } : {}),\n };\n args.push(\"--mcp-server\", `${name}=${JSON.stringify(serverSpec)}`);\n }\n }\n\n return args;\n }\n}\n","import type { ProcessManager } from \"@/process/process-manager.js\";\nimport type {\n PromptRequest,\n AgentMessage,\n AdapterCapabilities,\n CompatibilityResult,\n SessionInfo,\n SessionListOptions,\n IAgentAdapter,\n ModelInfo,\n BackendConfig,\n} from \"@/types/index.js\";\n\n/**\n * 简易语义版本范围匹配,支持 >=X.Y.Z 格式\n * @param version 当前版本号\n * @param range 版本范围表达式\n * @returns 是否满足范围要求\n */\nfunction satisfiesRange(version: string, range: string): boolean {\n const parseVersion = (v: string): [number, number, number] | null => {\n const match = /^v?(\\d+)\\.(\\d+)\\.(\\d+)/.exec(v.trim());\n if (!match) return null;\n return [Number(match[1]), Number(match[2]), Number(match[3])];\n };\n\n const trimmed = range.trim();\n\n // 处理 >=X.Y.Z 格式\n if (trimmed.startsWith(\">=\")) {\n const rangeVersion = parseVersion(trimmed.slice(2));\n const currentVersion = parseVersion(version);\n if (!rangeVersion || !currentVersion) return false;\n\n for (let i = 0; i < 3; i++) {\n if (currentVersion[i] > rangeVersion[i]) return true;\n if (currentVersion[i] < rangeVersion[i]) return false;\n }\n return true; // 版本相等\n }\n\n // 处理 <=X.Y.Z 格式\n if (trimmed.startsWith(\"<=\")) {\n const rangeVersion = parseVersion(trimmed.slice(2));\n const currentVersion = parseVersion(version);\n if (!rangeVersion || !currentVersion) return false;\n\n for (let i = 0; i < 3; i++) {\n if (currentVersion[i] < rangeVersion[i]) return true;\n if (currentVersion[i] > rangeVersion[i]) return false;\n }\n return true;\n }\n\n // 精确匹配\n const rangeVersion = parseVersion(trimmed);\n const currentVersion = parseVersion(version);\n if (!rangeVersion || !currentVersion) return false;\n return (\n currentVersion[0] === rangeVersion[0] &&\n currentVersion[1] === rangeVersion[1] &&\n currentVersion[2] === rangeVersion[2]\n );\n}\n\n/**\n * Agent 适配器抽象基类,实现 IAgentAdapter 接口的公共逻辑。\n * 子类需实现所有 abstract 方法以完成具体后端的适配。\n */\nexport abstract class AbstractAgentAdapter implements IAgentAdapter {\n abstract readonly backend: string;\n\n /** 活跃的 AbortController 映射,按 sessionId 索引 */\n protected readonly abortControllers = new Map<string, AbortController>();\n\n protected readonly processManager: ProcessManager;\n protected readonly config?: BackendConfig;\n\n constructor(processManager: ProcessManager, config?: BackendConfig) {\n this.processManager = processManager;\n this.config = config;\n }\n\n /**\n * 默认兼容性检查:获取当前版本并与 testedVersionRange 进行比较\n */\n async checkCompatibility(): Promise<CompatibilityResult> {\n const warnings: string[] = [];\n\n let version: string;\n try {\n version = await this.getVersion();\n } catch {\n return {\n version: \"unknown\",\n supported: false,\n warnings: [`无法获取 ${this.backend} 版本信息`],\n };\n }\n\n const capabilities = this.getCapabilities();\n const supported = satisfiesRange(version, capabilities.testedVersionRange);\n\n if (!supported) {\n warnings.push(\n `${this.backend} 版本 ${version} 不在测试范围 ${capabilities.testedVersionRange} 内,可能存在兼容性问题`,\n );\n }\n\n return { version, supported, warnings };\n }\n\n /**\n * 中止指定会话的执行\n * @param sessionId 会话标识\n */\n abort(sessionId: string): void {\n const controller = this.abortControllers.get(sessionId);\n if (controller) {\n controller.abort();\n this.abortControllers.delete(sessionId);\n }\n }\n\n /**\n * 创建并注册 AbortController\n * @param sessionId 会话标识\n * @returns AbortController 实例\n */\n protected createAbortController(sessionId: string): AbortController {\n // 如已有旧的 controller,先中止\n const existing = this.abortControllers.get(sessionId);\n if (existing) {\n existing.abort();\n }\n const controller = new AbortController();\n this.abortControllers.set(sessionId, controller);\n return controller;\n }\n\n /**\n * 清理指定会话的 AbortController\n * @param sessionId 会话标识\n */\n protected removeAbortController(sessionId: string): void {\n this.abortControllers.delete(sessionId);\n }\n\n abstract isAvailable(): Promise<boolean>;\n abstract getVersion(): Promise<string>;\n abstract getCapabilities(): AdapterCapabilities;\n abstract query(request: PromptRequest): AsyncGenerator<AgentMessage>;\n abstract listSessions(options?: SessionListOptions): Promise<SessionInfo[]>;\n abstract listModels(): Promise<ModelInfo[]>;\n abstract getSettings(): Promise<Record<string, unknown>>;\n abstract updateSettings(settings: Record<string, unknown>): Promise<void>;\n abstract dispose(): Promise<void>;\n}\n","/**\n * Claude CLI stream-json 事件基础接口\n */\ninterface ClaudeBaseEvent {\n type: string;\n /** 会话 ID */\n session_id?: string;\n}\n\n/**\n * 系统初始化事件 - 首个事件,包含模型和工具信息\n */\nexport interface ClaudeSystemEvent extends ClaudeBaseEvent {\n type: \"system\";\n subtype: \"init\";\n model?: string;\n tools?: string[];\n cwd?: string;\n}\n\n/**\n * 内容块类型\n */\nexport interface ClaudeTextBlock {\n type: \"text\";\n text: string;\n}\n\nexport interface ClaudeToolUseBlock {\n type: \"tool_use\";\n id: string;\n name: string;\n input: Record<string, unknown>;\n}\n\nexport interface ClaudeToolResultBlock {\n type: \"tool_result\";\n tool_use_id: string;\n content: string;\n}\n\nexport type ClaudeContentBlock =\n | ClaudeTextBlock\n | ClaudeToolUseBlock\n | ClaudeToolResultBlock;\n\n/**\n * 助手消息事件 - 包含完整的助手回复内容块\n */\nexport interface ClaudeAssistantEvent extends ClaudeBaseEvent {\n type: \"assistant\";\n message: {\n content: ClaudeContentBlock[];\n model?: string;\n stop_reason?: string;\n };\n}\n\n/**\n * 流式事件 - 包含增量内容(文本 delta 等)\n */\nexport interface ClaudeStreamEventWrapper extends ClaudeBaseEvent {\n type: \"stream_event\";\n event: {\n type?: string;\n index?: number;\n delta?: {\n type: \"text_delta\" | \"input_json_delta\";\n text?: string;\n partial_json?: string;\n };\n content_block?: ClaudeContentBlock;\n };\n}\n\n/**\n * 结果事件 - 最终结果,包含计费和统计信息\n */\nexport interface ClaudeResultEvent extends ClaudeBaseEvent {\n type: \"result\";\n result: string;\n cost_usd?: number;\n duration_ms?: number;\n duration_api_ms?: number;\n input_tokens?: number;\n output_tokens?: number;\n is_error?: boolean;\n num_turns?: number;\n session_id?: string;\n}\n\n/**\n * Claude CLI stream-json 事件联合类型(判别联合)\n */\nexport type ClaudeStreamEvent =\n | ClaudeSystemEvent\n | ClaudeAssistantEvent\n | ClaudeStreamEventWrapper\n | ClaudeResultEvent;\n\n/**\n * 类型守卫:检查是否为 ClaudeSystemEvent\n */\nexport function isSystemEvent(event: unknown): event is ClaudeSystemEvent {\n if (typeof event !== \"object\" || event === null) return false;\n return (event as Record<string, unknown>)[\"type\"] === \"system\";\n}\n\n/**\n * 类型守卫:检查是否为 ClaudeAssistantEvent\n */\nexport function isAssistantEvent(event: unknown): event is ClaudeAssistantEvent {\n if (typeof event !== \"object\" || event === null) return false;\n const obj = event as Record<string, unknown>;\n return obj[\"type\"] === \"assistant\" && typeof obj[\"message\"] === \"object\" && obj[\"message\"] !== null;\n}\n\n/**\n * 类型守卫:检查是否为 ClaudeStreamEventWrapper\n */\nexport function isStreamEvent(event: unknown): event is ClaudeStreamEventWrapper {\n if (typeof event !== \"object\" || event === null) return false;\n const obj = event as Record<string, unknown>;\n return obj[\"type\"] === \"stream_event\" && typeof obj[\"event\"] === \"object\" && obj[\"event\"] !== null;\n}\n\n/**\n * 类型守卫:检查是否为 ClaudeResultEvent\n */\nexport function isResultEvent(event: unknown): event is ClaudeResultEvent {\n if (typeof event !== \"object\" || event === null) return false;\n const obj = event as Record<string, unknown>;\n return obj[\"type\"] === \"result\" && \"result\" in obj;\n}\n","import type { AgentMessage } from \"@/types/index.js\";\nimport {\n isSystemEvent,\n isAssistantEvent,\n isStreamEvent,\n isResultEvent,\n type ClaudeContentBlock,\n} from \"./types.js\";\n\n/**\n * 将 Claude CLI stream-json 事件映射为统一的 AgentMessage 数组。\n * Claude CLI 的 assistant 事件可能包含多个内容块(文本 + 工具调用),\n * 本函数将它们拆分为独立的消息逐条返回,确保与 OpenCode 适配器行为一致。\n *\n * 对于不关注的事件类型返回空数组。\n *\n * @param event 解析后的 Claude 事件对象\n * @param sessionId 可选的会话 ID\n * @returns 统一消息数组\n */\nexport function mapClaudeEvent(\n event: Record<string, unknown>,\n sessionId?: string,\n): AgentMessage[] {\n const timestamp = Date.now();\n // Claude 事件可能携带 session_id,优先使用事件中的值\n const resolvedSessionId = (event.session_id as string | undefined) ?? sessionId;\n const baseFields = { timestamp, sessionId: resolvedSessionId, raw: event };\n\n if (isSystemEvent(event)) {\n return [{\n ...baseFields,\n type: \"system\",\n model: event.model,\n tools: event.tools,\n cwd: event.cwd,\n }];\n }\n\n if (isAssistantEvent(event)) {\n const content = event.message.content;\n return mapAssistantContent(content, baseFields);\n }\n\n // stream_event: Claude CLI 实际极少产生此类事件,但保留处理逻辑以备兼容\n if (isStreamEvent(event)) {\n const delta = event.event.delta;\n if (delta?.type === \"text_delta\" && delta.text) {\n return [{\n ...baseFields,\n type: \"stream_chunk\",\n text: delta.text,\n }];\n }\n return [];\n }\n\n if (isResultEvent(event)) {\n return [{\n ...baseFields,\n type: \"result\",\n text: event.result,\n costUsd: event.cost_usd,\n durationMs: event.duration_ms,\n inputTokens: event.input_tokens,\n outputTokens: event.output_tokens,\n }];\n }\n\n // 未知事件类型,忽略\n return [];\n}\n\n/**\n * 将助手消息的内容块拆分为多条 AgentMessage。\n * 每个文本块生成一条 stream_chunk 消息(模拟增量流式),\n * 合并后的完整文本生成一条 assistant 消息,\n * 每个工具调用块生成独立的 tool_use 消息。\n * 这样对外统一表现为增量流式,与 OpenCode 适配器行为一致。\n */\nfunction mapAssistantContent(\n blocks: ClaudeContentBlock[],\n baseFields: { timestamp: number; sessionId?: string; raw: unknown },\n): AgentMessage[] {\n if (!blocks || blocks.length === 0) return [];\n\n const messages: AgentMessage[] = [];\n const textParts: string[] = [];\n\n for (const block of blocks) {\n if (block.type === \"text\" && block.text) {\n textParts.push(block.text);\n // 每个文本块作为 stream_chunk 发出,模拟增量流式\n messages.push({\n ...baseFields,\n type: \"stream_chunk\",\n text: block.text,\n });\n }\n }\n\n // 合并后的完整文本作为 assistant 消息发出(turn 完成标记)\n if (textParts.length > 0) {\n messages.push({\n ...baseFields,\n type: \"assistant\",\n text: textParts.join(\"\\n\"),\n turnComplete: true,\n });\n }\n\n // 每个工具调用块作为独立的 tool_use 消息发出\n for (const block of blocks) {\n if (block.type === \"tool_use\") {\n messages.push({\n ...baseFields,\n type: \"tool_use\",\n toolName: block.name,\n input: block.input,\n });\n }\n // tool_result 块映射为带 output 的 tool_use 消息\n if (block.type === \"tool_result\") {\n messages.push({\n ...baseFields,\n type: \"tool_use\",\n toolName: block.tool_use_id,\n input: {},\n output: block.content,\n });\n }\n }\n\n return messages;\n}\n","import { readFile, writeFile, mkdir } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { EphemeralProcess } from \"@/process/process-handle.js\";\nimport { AbstractAgentAdapter } from \"@/adapters/base.js\";\nimport type { ProcessManager } from \"@/process/process-manager.js\";\nimport type {\n AdapterCapabilities,\n CompatibilityResult,\n SessionInfo,\n SessionListOptions,\n PromptRequest,\n AgentMessage,\n ModelInfo,\n BackendConfig,\n} from \"@/types/index.js\";\nimport { OpenCodeApiClient } from \"./api-client.js\";\nimport { mapOpenCodeEventToMessage } from \"./message-mapper.js\";\n\n/** opencode serve 默认端口 */\nconst DEFAULT_SERVE_PORT = 39393;\n\n/** 等待 serve 进程就绪的最大时长(毫秒) */\nconst SERVE_READY_TIMEOUT_MS = 30_000;\n\n/** 等待 serve 进程就绪的轮询间隔(毫秒) */\nconst SERVE_POLL_INTERVAL_MS = 500;\n\n/** opencode 测试版本范围 */\nconst TESTED_VERSION_RANGE = \">=0.1.0\";\n\n/** 默认最大重启次数 */\nconst MAX_RESTARTS = 3;\n\n/** 默认重启间隔(毫秒) */\nconst RESTART_INTERVAL_MS = 2_000;\n\n/** 健康检查间隔(毫秒) */\nconst HEALTH_CHECK_INTERVAL_MS = 30_000;\n\n/**\n * OpenCode 适配器。\n * 通过 `opencode serve` 启动 HTTP 服务,使用 REST API + SSE 进行交互。\n */\nexport class OpenCodeAdapter extends AbstractAgentAdapter {\n readonly backend = \"opencode\";\n\n private apiClient: OpenCodeApiClient | null = null;\n private servePort: number;\n /** 远程服务器 URL(提供时跳过自启 serve) */\n private remoteServerUrl?: string;\n /** API Key(用于 Basic Auth) */\n private apiKey?: string;\n\n /**\n * @param processManager 进程管理器实例\n * @param config 可选的后端配置\n * - serverUrl: 远程 OpenCode 服务地址,提供时跳过自启 serve\n * - apiKey: API Key,用于 Basic Auth 认证\n * - options.servePort: 本地 serve 端口(仅自启模式)\n */\n constructor(processManager: ProcessManager, config?: BackendConfig) {\n super(processManager, config);\n const opts = config?.options ?? {};\n // 优先从顶级字段读取,向后兼容 options 中的值\n this.remoteServerUrl = config?.serverUrl ?? (opts.serverUrl as string | undefined);\n this.apiKey = config?.apiKey ?? (opts.apiKey as string | undefined);\n this.servePort = (opts.servePort as number) ?? DEFAULT_SERVE_PORT;\n }\n\n /**\n * 检查 opencode 命令是否可用\n */\n async isAvailable(): Promise<boolean> {\n // 远程模式:通过健康检查判断\n if (this.remoteServerUrl) {\n try {\n const client = new OpenCodeApiClient(this.remoteServerUrl, this.apiKey);\n return await client.healthCheck();\n } catch {\n return false;\n }\n }\n // 本地模式:检查命令是否存在\n try {\n const proc = new EphemeralProcess();\n const result = await proc.execute({\n command: \"opencode\",\n args: [\"--version\"],\n timeoutMs: 10_000,\n });\n return result.exitCode === 0;\n } catch {\n return false;\n }\n }\n\n /**\n * 获取 opencode 版本号\n */\n async getVersion(): Promise<string> {\n const proc = new EphemeralProcess();\n const result = await proc.execute({\n command: \"opencode\",\n args: [\"version\"],\n timeoutMs: 10_000,\n });\n\n if (result.exitCode !== 0) {\n throw new Error(`Failed to get opencode version: ${result.stderr}`);\n }\n\n return result.stdout.trim();\n }\n\n /**\n * 获取适配器能力声明\n */\n getCapabilities(): AdapterCapabilities {\n return {\n features: new Set([\n \"streaming\",\n \"session-resume\",\n \"system-prompt\",\n \"serve-mode\",\n ]),\n streamingMode: \"delta\",\n outputFormats: [\"text\"],\n testedVersionRange: TESTED_VERSION_RANGE,\n };\n }\n\n /**\n * 执行查询:启动 serve 进程(如未启动),创建/恢复会话,发送消息并流式返回结果\n * @param request 请求参数\n * @yields AgentMessage 统一消息流\n */\n async *query(request: PromptRequest): AsyncGenerator<AgentMessage> {\n // 确保 serve 进程已启动\n const client = await this.ensureServeRunning();\n\n // 创建或恢复会话\n let sessionId: string;\n if (request.resume) {\n sessionId = request.resume;\n } else {\n const session = await client.createSession(request.cwd);\n sessionId = session.id;\n }\n\n // 复用基类的 AbortController 管理\n const controller = this.createAbortController(sessionId);\n\n try {\n // 发送消息\n await client.sendMessage(sessionId, request.prompt);\n\n // 流式读取事件\n for await (const event of client.streamEvents(\n sessionId,\n controller.signal,\n )) {\n const message = mapOpenCodeEventToMessage(event);\n if (message) {\n yield message;\n }\n }\n } finally {\n this.removeAbortController(sessionId);\n }\n }\n\n /**\n * 列出历史会话\n * @param options 查询选项\n */\n async listSessions(options?: SessionListOptions): Promise<SessionInfo[]> {\n const client = await this.ensureServeRunning();\n const sessions = await client.listSessions();\n\n let filtered = sessions;\n\n if (options?.cwd) {\n filtered = filtered.filter((s) => s.cwd === options.cwd);\n }\n\n if (options?.limit !== undefined && options.limit > 0) {\n filtered = filtered.slice(0, options.limit);\n }\n\n return filtered.map((s) => ({\n sessionId: s.id,\n backend: this.backend,\n summary: s.title,\n lastModified: s.updatedAt,\n cwd: s.cwd,\n }));\n }\n\n /**\n * 获取 OpenCode 可用模型列表(通过 `opencode models` 命令)\n */\n async listModels(): Promise<ModelInfo[]> {\n try {\n const proc = new EphemeralProcess();\n const result = await proc.execute({\n command: \"opencode\",\n args: [\"models\"],\n timeoutMs: 15_000,\n });\n\n if (result.exitCode !== 0) return [];\n\n const lines = result.stdout.trim().split(\"\\n\").filter(Boolean);\n return lines.map((line) => {\n const trimmed = line.trim();\n const slashIndex = trimmed.indexOf(\"/\");\n if (slashIndex >= 0) {\n return {\n id: trimmed,\n name: trimmed.slice(slashIndex + 1),\n provider: trimmed.slice(0, slashIndex),\n };\n }\n return { id: trimmed, name: trimmed };\n });\n } catch {\n return [];\n }\n }\n\n /**\n * 读取 opencode 配置文件\n */\n async getSettings(): Promise<Record<string, unknown>> {\n const configPath = this.getConfigPath();\n try {\n const content = await readFile(configPath, \"utf-8\");\n return JSON.parse(content) as Record<string, unknown>;\n } catch {\n return {};\n }\n }\n\n /**\n * 更新 opencode 配置文件(读取-合并-写入)\n * @param settings 要合并的配置项\n */\n async updateSettings(settings: Record<string, unknown>): Promise<void> {\n const configPath = this.getConfigPath();\n const configDir = join(homedir(), \".config\", \"opencode\");\n\n let existing: Record<string, unknown>;\n try {\n const content = await readFile(configPath, \"utf-8\");\n existing = JSON.parse(content) as Record<string, unknown>;\n } catch {\n existing = {};\n }\n\n const merged = { ...existing, ...settings };\n\n await mkdir(configDir, { recursive: true });\n await writeFile(configPath, JSON.stringify(merged, null, 2), \"utf-8\");\n }\n\n /**\n * 释放资源:停止 serve 进程,中止所有活跃流\n */\n async dispose(): Promise<void> {\n // 中止所有活跃会话(复用基类的 abortControllers)\n for (const [sessionId] of this.abortControllers) {\n this.abort(sessionId);\n }\n\n // 停止持久进程\n const persistent = this.processManager.getPersistent(this.backend);\n if (persistent) {\n await persistent.stop();\n }\n\n this.apiClient = null;\n }\n\n /**\n * 确保 opencode serve 进程已启动并可用\n * @returns 可用的 API 客户端\n */\n private async ensureServeRunning(): Promise<OpenCodeApiClient> {\n if (this.apiClient) {\n const healthy = await this.apiClient.healthCheck();\n if (healthy) return this.apiClient;\n }\n\n // 远程模式:直连远程服务器,不自启 serve\n if (this.remoteServerUrl) {\n const client = new OpenCodeApiClient(this.remoteServerUrl, this.apiKey);\n const healthy = await client.healthCheck();\n if (!healthy) {\n throw new Error(\n `无法连接远程 OpenCode 服务: ${this.remoteServerUrl}`,\n );\n }\n this.apiClient = client;\n return client;\n }\n\n // 本地模式:自启 serve\n const client = new OpenCodeApiClient(\n `http://localhost:${this.servePort}`,\n this.apiKey,\n );\n\n // 检查是否已有 serve 进程在运行\n const alreadyRunning = await client.healthCheck();\n if (alreadyRunning) {\n this.apiClient = client;\n return client;\n }\n\n // 启动 serve 进程\n await this.processManager.startPersistent(this.backend, {\n command: \"opencode\",\n args: [\"serve\", \"--port\", String(this.servePort)],\n maxRestarts: MAX_RESTARTS,\n restartIntervalMs: RESTART_INTERVAL_MS,\n healthCheckIntervalMs: HEALTH_CHECK_INTERVAL_MS,\n healthCheckFn: () => client.healthCheck().then((ok) => {\n if (!ok) throw new Error(\"Health check failed\");\n return ok;\n }),\n });\n\n // 等待 serve 进程就绪\n await this.waitForServeReady(client);\n\n this.apiClient = client;\n return client;\n }\n\n /**\n * 轮询等待 serve 服务可达\n * @param client API 客户端\n */\n private async waitForServeReady(client: OpenCodeApiClient): Promise<void> {\n const deadline = Date.now() + SERVE_READY_TIMEOUT_MS;\n\n while (Date.now() < deadline) {\n const healthy = await client.healthCheck();\n if (healthy) return;\n\n await this.delay(SERVE_POLL_INTERVAL_MS);\n }\n\n throw new Error(\n `opencode serve did not become ready within ${SERVE_READY_TIMEOUT_MS}ms`,\n );\n }\n\n /**\n * 延迟指定毫秒\n * @param ms 毫秒数\n */\n private delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n /**\n * 获取 opencode 配置文件路径\n */\n private getConfigPath(): string {\n return join(homedir(), \".config\", \"opencode\", \"config.json\");\n }\n}\n","/**\n * OpenCode API 会话对象\n */\nexport interface OpenCodeSession {\n id: string;\n title?: string;\n cwd?: string;\n createdAt: number;\n updatedAt: number;\n}\n\n/**\n * 创建会话请求参数\n */\nexport interface CreateSessionRequest {\n cwd?: string;\n}\n\n/**\n * 创建会话响应\n */\nexport interface CreateSessionResponse {\n id: string;\n}\n\n/**\n * 会话列表响应\n */\nexport interface ListSessionsResponse {\n sessions: OpenCodeSession[];\n}\n\n/**\n * 发送消息请求参数\n */\nexport interface SendMessageRequest {\n content: string;\n}\n\n/**\n * SSE 事件类型\n */\nexport type OpenCodeEventType =\n | \"session.created\"\n | \"message.start\"\n | \"message.delta\"\n | \"message.complete\"\n | \"tool_use.start\"\n | \"tool_use.delta\"\n | \"tool_use.complete\"\n | \"error\"\n | \"done\";\n\n/**\n * SSE 事件基础结构\n */\ninterface BaseOpenCodeEvent {\n type: OpenCodeEventType;\n sessionId: string;\n timestamp: number;\n}\n\n/**\n * 会话创建事件\n */\nexport interface SessionCreatedEvent extends BaseOpenCodeEvent {\n type: \"session.created\";\n model?: string;\n tools?: string[];\n cwd?: string;\n}\n\n/**\n * 消息开始事件\n */\nexport interface MessageStartEvent extends BaseOpenCodeEvent {\n type: \"message.start\";\n}\n\n/**\n * 消息增量文本事件\n */\nexport interface MessageDeltaEvent extends BaseOpenCodeEvent {\n type: \"message.delta\";\n text: string;\n}\n\n/**\n * 消息完成事件\n */\nexport interface MessageCompleteEvent extends BaseOpenCodeEvent {\n type: \"message.complete\";\n text: string;\n durationMs?: number;\n costUsd?: number;\n inputTokens?: number;\n outputTokens?: number;\n}\n\n/**\n * 工具调用开始事件\n */\nexport interface ToolUseStartEvent extends BaseOpenCodeEvent {\n type: \"tool_use.start\";\n toolName: string;\n input: Record<string, unknown>;\n}\n\n/**\n * 工具调用增量事件\n */\nexport interface ToolUseDeltaEvent extends BaseOpenCodeEvent {\n type: \"tool_use.delta\";\n toolName: string;\n output: string;\n}\n\n/**\n * 工具调用完成事件\n */\nexport interface ToolUseCompleteEvent extends BaseOpenCodeEvent {\n type: \"tool_use.complete\";\n toolName: string;\n input: Record<string, unknown>;\n output: string;\n}\n\n/**\n * 错误事件\n */\nexport interface ErrorEvent extends BaseOpenCodeEvent {\n type: \"error\";\n message: string;\n code?: string;\n}\n\n/**\n * 完成事件\n */\nexport interface DoneEvent extends BaseOpenCodeEvent {\n type: \"done\";\n}\n\n/**\n * 所有 SSE 事件联合类型\n */\nexport type OpenCodeEvent =\n | SessionCreatedEvent\n | MessageStartEvent\n | MessageDeltaEvent\n | MessageCompleteEvent\n | ToolUseStartEvent\n | ToolUseDeltaEvent\n | ToolUseCompleteEvent\n | ErrorEvent\n | DoneEvent;\n\n/**\n * OpenCode 配置文件结构\n */\nexport interface OpenCodeConfig {\n model?: string;\n provider?: string;\n systemPrompt?: string;\n [key: string]: unknown;\n}\n\n/**\n * API 客户端错误\n */\nexport class OpenCodeApiError extends Error {\n readonly statusCode: number;\n readonly responseBody: string;\n\n constructor(statusCode: number, responseBody: string) {\n super(`OpenCode API error (${statusCode}): ${responseBody}`);\n this.name = \"OpenCodeApiError\";\n this.statusCode = statusCode;\n this.responseBody = responseBody;\n }\n}\n","import type {\n OpenCodeSession,\n OpenCodeEvent,\n CreateSessionResponse,\n ListSessionsResponse,\n OpenCodeApiError as OpenCodeApiErrorType,\n} from \"./types.js\";\nimport { OpenCodeApiError } from \"./types.js\";\n\n/** SSE 重连等待时长(毫秒) */\nconst SSE_RECONNECT_DELAY_MS = 1_000;\n\n/** 默认请求超时时长(毫秒) */\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\n/**\n * OpenCode HTTP API 客户端。\n * 与 `opencode serve` HTTP 服务进行通信。\n */\nexport class OpenCodeApiClient {\n private readonly baseUrl: string;\n private readonly apiKey?: string;\n\n /**\n * @param baseUrl opencode serve 服务的基础 URL,例如 http://localhost:39393\n * @param apiKey 可选的 API Key,用于 Basic Auth 认证(username: opencode, password: apiKey)\n */\n constructor(baseUrl: string, apiKey?: string) {\n // 移除末尾斜杠\n this.baseUrl = baseUrl.replace(/\\/+$/, \"\");\n this.apiKey = apiKey;\n }\n\n /**\n * 创建新会话\n * @param cwd 可选的工作目录\n * @returns 包含会话 ID 的对象\n */\n async createSession(cwd?: string): Promise<CreateSessionResponse> {\n const body: Record<string, unknown> = {};\n if (cwd) {\n body.cwd = cwd;\n }\n\n const response = await this.request<CreateSessionResponse>(\n \"/api/session\",\n {\n method: \"POST\",\n body: JSON.stringify(body),\n },\n );\n return response;\n }\n\n /**\n * 获取所有会话列表\n * @returns 会话数组\n */\n async listSessions(): Promise<OpenCodeSession[]> {\n const response = await this.request<ListSessionsResponse>(\n \"/api/sessions\",\n { method: \"GET\" },\n );\n return response.sessions;\n }\n\n /**\n * 向指定会话发送消息\n * @param sessionId 会话 ID\n * @param content 消息内容\n */\n async sendMessage(sessionId: string, content: string): Promise<void> {\n await this.request<unknown>(\n `/api/session/${encodeURIComponent(sessionId)}/message`,\n {\n method: \"POST\",\n body: JSON.stringify({ content }),\n },\n );\n }\n\n /**\n * 以 SSE 流式方式订阅会话事件\n * @param sessionId 会话 ID\n * @param abortSignal 可选的中止信号\n * @yields OpenCode SSE 事件\n */\n async *streamEvents(\n sessionId: string,\n abortSignal?: AbortSignal,\n ): AsyncGenerator<OpenCodeEvent> {\n const url = `${this.baseUrl}/api/session/${encodeURIComponent(sessionId)}/events`;\n\n const response = await fetch(url, {\n method: \"GET\",\n headers: {\n Accept: \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n ...this.buildAuthHeaders(),\n },\n signal: abortSignal,\n });\n\n if (!response.ok) {\n const body = await response.text().catch(() => \"\");\n throw new OpenCodeApiError(response.status, body);\n }\n\n if (!response.body) {\n throw new Error(\"Response body is null, SSE streaming unavailable\");\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n\n // SSE 协议:事件由双换行分隔\n const parts = buffer.split(\"\\n\\n\");\n // 最后一段可能是不完整的,保留在 buffer 中\n buffer = parts.pop() ?? \"\";\n\n for (const part of parts) {\n const event = this.parseSseEvent(part);\n if (event) {\n yield event;\n // 收到 done 事件则终止流\n if (event.type === \"done\") {\n return;\n }\n }\n }\n }\n\n // 处理 buffer 中可能残留的最后一个事件\n if (buffer.trim()) {\n const event = this.parseSseEvent(buffer);\n if (event) {\n yield event;\n }\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n /**\n * 健康检查:验证 opencode serve 服务是否可达\n * @returns 服务是否健康\n */\n async healthCheck(): Promise<boolean> {\n try {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), 5_000);\n\n const response = await fetch(`${this.baseUrl}/api/sessions`, {\n method: \"GET\",\n headers: this.buildAuthHeaders(),\n signal: controller.signal,\n });\n\n clearTimeout(timer);\n return response.ok;\n } catch {\n return false;\n }\n }\n\n /**\n * 解析单个 SSE 事件文本块\n * @param raw 原始 SSE 文本块\n * @returns 解析后的事件对象,解析失败返回 null\n */\n private parseSseEvent(raw: string): OpenCodeEvent | null {\n const lines = raw.split(\"\\n\");\n let data = \"\";\n\n for (const line of lines) {\n // 忽略注释行\n if (line.startsWith(\":\")) continue;\n\n if (line.startsWith(\"data: \")) {\n data += line.slice(6);\n } else if (line.startsWith(\"data:\")) {\n data += line.slice(5);\n }\n }\n\n if (!data) return null;\n\n try {\n return JSON.parse(data) as OpenCodeEvent;\n } catch {\n return null;\n }\n }\n\n /**\n * 发送 HTTP 请求的通用方法\n * @param path API 路径\n * @param init fetch 请求选项\n * @returns 解析后的 JSON 响应\n */\n /**\n * 构建包含认证信息的请求 headers\n */\n private buildAuthHeaders(): Record<string, string> {\n const headers: Record<string, string> = {};\n if (this.apiKey) {\n const credentials = Buffer.from(`opencode:${this.apiKey}`).toString(\"base64\");\n headers[\"Authorization\"] = `Basic ${credentials}`;\n }\n return headers;\n }\n\n private async request<T>(path: string, init: RequestInit): Promise<T> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), DEFAULT_TIMEOUT_MS);\n\n try {\n const response = await fetch(`${this.baseUrl}${path}`, {\n ...init,\n headers: {\n \"Content-Type\": \"application/json\",\n ...this.buildAuthHeaders(),\n ...init.headers,\n },\n signal: controller.signal,\n });\n\n if (!response.ok) {\n const body = await response.text().catch(() => \"\");\n throw new OpenCodeApiError(response.status, body);\n }\n\n const text = await response.text();\n if (!text) return {} as T;\n return JSON.parse(text) as T;\n } finally {\n clearTimeout(timer);\n }\n }\n}\n","import type { AgentMessage } from \"@/types/index.js\";\nimport type { OpenCodeEvent } from \"./types.js\";\n\n/**\n * 将 OpenCode SSE 事件映射为统一的 AgentMessage 格式\n * @param event OpenCode SSE 事件\n * @returns 对应的 AgentMessage,无法映射时返回 null\n */\nexport function mapOpenCodeEventToMessage(\n event: OpenCodeEvent,\n): AgentMessage | null {\n const base = {\n timestamp: event.timestamp ?? Date.now(),\n sessionId: event.sessionId,\n raw: event,\n };\n\n switch (event.type) {\n case \"session.created\":\n return {\n ...base,\n type: \"system\",\n model: event.model,\n tools: event.tools,\n cwd: event.cwd,\n };\n\n case \"message.delta\":\n return {\n ...base,\n type: \"stream_chunk\",\n text: event.text,\n };\n\n case \"message.complete\":\n return {\n ...base,\n type: \"result\",\n text: event.text,\n durationMs: event.durationMs,\n costUsd: event.costUsd,\n inputTokens: event.inputTokens,\n outputTokens: event.outputTokens,\n };\n\n case \"tool_use.start\":\n return {\n ...base,\n type: \"tool_use\",\n toolName: event.toolName,\n input: event.input,\n };\n\n case \"tool_use.complete\":\n return {\n ...base,\n type: \"tool_use\",\n toolName: event.toolName,\n input: event.input,\n output: event.output,\n };\n\n case \"error\":\n return {\n ...base,\n type: \"error\",\n message: event.message,\n code: event.code,\n };\n\n // message.start / tool_use.delta / done 事件不需要映射为独立消息\n case \"message.start\":\n case \"tool_use.delta\":\n case \"done\":\n return null;\n\n default:\n return null;\n }\n}\n","import type { InterceptorFn, InterceptorContext } from \"./interceptor.js\";\n\n/**\n * 防护拦截器触发时的处理动作\n */\nexport type GuardAction = \"reject\" | \"redact\";\n\n/**\n * 防护拦截器配置选项\n */\nexport interface GuardOptions {\n /**\n * 输入侧:阻止用户通过 prompt 注入攻击套取系统提示词或绕过规则。\n * 匹配到任一模式时触发防护。\n * @example [/忽略.*指令/, /重复.*系统提示/, /ignore.*instructions/i]\n */\n blockedPatterns?: RegExp[];\n\n /**\n * 输出侧:防止模型在回复中泄露系统提示词内容。\n * 提供需要保护的关键词列表,若输出中包含这些关键词则触发防护。\n * @example [\"内部密钥\", \"SECRET_TOKEN\"]\n */\n sensitiveKeywords?: string[];\n\n /**\n * 触发防护时的处理动作:\n * - \"reject\": 拒绝消息,抛出 InterceptorRejectedError(默认)\n * - \"redact\": 替换匹配内容为 [REDACTED],允许消息继续传递\n */\n action?: GuardAction;\n\n /**\n * 自定义判定函数,在内置规则之后执行。\n * 返回 true 表示触发防护,返回 false 或 undefined 表示放行。\n */\n customCheck?: (text: string, context: InterceptorContext) => boolean | undefined;\n\n /**\n * 仅对指定后端生效,不设则对所有后端生效\n */\n backends?: string[];\n}\n\n/** 内置的常见 prompt 注入模式(中英文) */\nconst BUILTIN_INPUT_PATTERNS: RegExp[] = [\n // 中文\n /忽略.{0,10}(之前|上面|以上|所有).{0,10}(指令|规则|提示|约束)/i,\n /重复.{0,10}(系统|完整).{0,10}(提示|指令|prompt)/i,\n /输出.{0,10}(系统|完整).{0,10}(提示|指令|prompt)/i,\n /告诉我.{0,10}(系统|你的).{0,10}(提示|指令|prompt)/i,\n /显示.{0,10}(系统|隐藏|完整).{0,10}(提示|指令|prompt)/i,\n /你的(系统|初始).{0,10}(提示|指令|设定)/i,\n // English\n /ignore.{0,15}(previous|above|all|prior).{0,15}(instructions?|rules?|prompts?|constraints?)/i,\n /repeat.{0,15}(system|full|entire|complete).{0,15}(prompt|instructions?|message)/i,\n /reveal.{0,15}(system|hidden|full).{0,15}(prompt|instructions?)/i,\n /show.{0,15}(system|hidden|full).{0,15}(prompt|instructions?)/i,\n /what.{0,15}(is|are).{0,15}(your|the).{0,15}(system|initial).{0,15}(prompt|instructions?)/i,\n /print.{0,15}(system|full|entire).{0,15}(prompt|instructions?|message)/i,\n /disregard.{0,15}(previous|above|all|prior).{0,15}(instructions?|rules?)/i,\n];\n\n/**\n * 创建输入防护拦截器。\n * 检测并阻止常见的 prompt 注入攻击,防止用户套取系统提示词或绕过规则。\n *\n * @param options 防护配置选项\n * @returns 可注册到 `porygon.use(\"input\", ...)` 的拦截器函数\n *\n * @example\n * ```ts\n * // 使用内置规则\n * porygon.use(\"input\", createInputGuard());\n *\n * // 自定义阻止模式\n * porygon.use(\"input\", createInputGuard({\n * blockedPatterns: [/我是管理员/, /sudo mode/i],\n * action: \"reject\",\n * }));\n * ```\n */\nexport function createInputGuard(options?: GuardOptions): InterceptorFn {\n const patterns = [\n ...BUILTIN_INPUT_PATTERNS,\n ...(options?.blockedPatterns ?? []),\n ];\n const action = options?.action ?? \"reject\";\n const backends = options?.backends;\n\n return (text: string, context: InterceptorContext) => {\n // 后端过滤\n if (backends && !backends.includes(context.backend)) {\n return undefined;\n }\n\n // 模式匹配\n for (const pattern of patterns) {\n if (pattern.test(text)) {\n if (action === \"reject\") {\n return false;\n }\n // redact: 替换匹配内容\n return text.replace(pattern, \"[REDACTED]\");\n }\n }\n\n // 自定义检查\n if (options?.customCheck?.(text, context)) {\n if (action === \"reject\") {\n return false;\n }\n return \"[REDACTED]\";\n }\n\n return undefined;\n };\n}\n\n/**\n * 创建输出防护拦截器。\n * 检测模型输出中是否包含敏感关键词,防止系统提示词内容泄露。\n *\n * @param options 防护配置选项\n * @returns 可注册到 `porygon.use(\"output\", ...)` 的拦截器函数\n *\n * @example\n * ```ts\n * porygon.use(\"output\", createOutputGuard({\n * sensitiveKeywords: [\"内部API密钥\", \"sk-xxxx\"],\n * action: \"redact\",\n * }));\n * ```\n */\nexport function createOutputGuard(options?: GuardOptions): InterceptorFn {\n const keywords = options?.sensitiveKeywords ?? [];\n const action = options?.action ?? \"redact\";\n const backends = options?.backends;\n\n return (text: string, context: InterceptorContext) => {\n // 后端过滤\n if (backends && !backends.includes(context.backend)) {\n return undefined;\n }\n\n // 关键词检测\n let matched = false;\n let result = text;\n\n for (const keyword of keywords) {\n if (text.includes(keyword)) {\n matched = true;\n if (action === \"redact\") {\n // 全局替换所有出现的关键词\n result = result.split(keyword).join(\"[REDACTED]\");\n }\n }\n }\n\n // 自定义检查\n if (!matched && options?.customCheck?.(text, context)) {\n matched = true;\n if (action === \"redact\") {\n result = \"[REDACTED]\";\n }\n }\n\n if (!matched) {\n return undefined;\n }\n\n if (action === \"reject\") {\n return false;\n }\n\n return result;\n };\n}\n"],"mappings":"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","names":["EventEmitter","rangeVersion","currentVersion","readFile","writeFile","homedir","join","readFile","join","homedir","writeFile","client","EventEmitter"]}
|
|
1
|
+
{"version":3,"sources":["../src/porygon.ts","../src/config/defaults.ts","../src/config/schema.ts","../src/errors/index.ts","../src/config/config-loader.ts","../src/interceptor/interceptor.ts","../src/process/process-handle.ts","../src/process/process-manager.ts","../src/session/session-manager.ts","../src/adapters/claude/index.ts","../src/adapters/base.ts","../src/adapters/claude/types.ts","../src/adapters/claude/message-mapper.ts","../src/adapters/opencode/index.ts","../src/adapters/opencode/types.ts","../src/adapters/opencode/api-client.ts","../src/adapters/opencode/message-mapper.ts","../src/session/interactive-session.ts","../src/interceptor/guard.ts"],"sourcesContent":["import { EventEmitter } from \"node:events\";\nimport type { PorygonConfig } from \"@/types/config.js\";\nimport type { PromptRequest, AgentMessage } from \"@/types/common.js\";\nimport type {\n IAgentAdapter,\n AdapterCapabilities,\n SessionInfo,\n SessionListOptions,\n ModelInfo,\n} from \"@/types/adapter.js\";\nimport { ConfigLoader } from \"@/config/config-loader.js\";\nimport {\n InterceptorManager,\n type InterceptorDirection,\n type InterceptorFn,\n} from \"@/interceptor/interceptor.js\";\nimport { ProcessManager } from \"@/process/process-manager.js\";\nimport { SessionManager } from \"@/session/session-manager.js\";\nimport { ClaudeAdapter } from \"@/adapters/claude/index.js\";\nimport { OpenCodeAdapter } from \"@/adapters/opencode/index.js\";\nimport { InteractiveSession } from \"@/session/interactive-session.js\";\nimport { AdapterNotFoundError } from \"@/errors/index.js\";\n\n/**\n * 健康检查结果(扁平化结构)\n */\nexport interface HealthCheckResult {\n available: boolean;\n version?: string;\n supported?: boolean;\n warnings?: string[];\n error?: string;\n}\n\n/**\n * Porygon 事件类型定义\n */\nexport interface PorygonEvents {\n \"session:created\": (info: SessionInfo) => void;\n \"session:resumed\": (info: SessionInfo) => void;\n \"process:spawn\": (backend: string, pid: number) => void;\n \"process:exit\": (backend: string, code: number | null) => void;\n \"process:error\": (backend: string, error: Error) => void;\n \"process:restart\": (backend: string, attempt: number) => void;\n \"interceptor:rejected\": (direction: string, reason: string) => void;\n \"health:degraded\": (backend: string, warning: string) => void;\n}\n\n/**\n * Porygon 主门面类,提供统一的 LLM 后端交互接口。\n * 管理适配器注册、拦截器流水线、进程生命周期和会话管理。\n */\nexport class Porygon extends EventEmitter {\n private config: PorygonConfig;\n private adapters = new Map<string, IAgentAdapter>();\n private interceptors: InterceptorManager;\n private processManager: ProcessManager;\n private sessionManager: SessionManager;\n\n constructor(config?: Partial<PorygonConfig>) {\n super();\n this.config = ConfigLoader.load(config);\n this.interceptors = new InterceptorManager();\n this.processManager = new ProcessManager();\n this.sessionManager = new SessionManager();\n\n this.registerBuiltinAdapters();\n }\n\n /**\n * 注册内置适配器\n */\n private registerBuiltinAdapters(): void {\n const claudeConfig = this.config.backends?.[\"claude\"];\n // 将全局代理合并到后端配置(后端级代理优先)\n const mergedClaudeConfig = {\n ...claudeConfig,\n proxy: claudeConfig?.proxy ?? this.config.proxy,\n };\n const claudeAdapter = new ClaudeAdapter(this.processManager, mergedClaudeConfig);\n this.registerAdapter(claudeAdapter);\n\n const opencodeConfig = this.config.backends?.[\"opencode\"];\n const mergedOpencodeConfig = {\n ...opencodeConfig,\n proxy: opencodeConfig?.proxy ?? this.config.proxy,\n };\n const opencodeAdapter = new OpenCodeAdapter(this.processManager, mergedOpencodeConfig);\n this.registerAdapter(opencodeAdapter);\n }\n\n /**\n * 注册自定义适配器\n * @param adapter 适配器实例\n */\n registerAdapter(adapter: IAgentAdapter): void {\n this.adapters.set(adapter.backend, adapter);\n this.sessionManager.registerAdapter(adapter.backend, adapter);\n }\n\n /**\n * 获取指定后端的适配器\n * @param backend 后端名称,默认使用配置中的 defaultBackend\n */\n private getAdapter(backend?: string): IAgentAdapter {\n const name = backend ?? this.config.defaultBackend ?? \"claude\";\n const adapter = this.adapters.get(name);\n if (!adapter) throw new AdapterNotFoundError(name);\n return adapter;\n }\n\n /**\n * 流式查询,返回 AgentMessage 异步生成器。\n * 作为与 LLM 后端交互的主要入口。\n * @param request 提示请求参数\n * @yields AgentMessage 消息流\n */\n async *query(request: PromptRequest): AsyncGenerator<AgentMessage> {\n const adapter = this.getAdapter(request.backend);\n const backendName = adapter.backend;\n\n const mergedRequest = this.mergeRequest(request, backendName);\n\n // 执行输入拦截器\n const processedPrompt = await this.interceptors.processInput(\n mergedRequest.prompt,\n { backend: backendName, sessionId: mergedRequest.resume },\n );\n mergedRequest.prompt = processedPrompt;\n\n for await (const message of adapter.query(mergedRequest)) {\n // 对文本内容执行输出拦截器\n if (message.type === \"assistant\" || message.type === \"result\") {\n const processedText = await this.interceptors.processOutput(\n message.text,\n {\n backend: backendName,\n sessionId: message.sessionId,\n messageType: message.type,\n },\n );\n yield { ...message, text: processedText };\n } else {\n yield message;\n }\n }\n }\n\n /**\n * 简单运行模式,收集所有消息并返回最终结果文本\n * @param request 提示请求参数\n * @returns 最终结果文本\n */\n async run(request: PromptRequest): Promise<string> {\n let resultText = \"\";\n for await (const msg of this.query(request)) {\n if (msg.type === \"result\") {\n resultText = msg.text;\n } else if (msg.type === \"assistant\") {\n resultText = msg.text;\n }\n }\n return resultText;\n }\n\n /**\n * 创建交互式多轮对话会话。\n * 自动管理 sessionId 和 resume,对调用方透明。\n */\n session(options?: Omit<PromptRequest, \"prompt\">): InteractiveSession {\n const backend = options?.backend ?? this.config.defaultBackend ?? \"claude\";\n const adapter = this.getAdapter(backend);\n const merged = this.mergeRequest({ ...options, prompt: \"\" }, backend);\n const { prompt: _, ...baseRequest } = merged;\n return new InteractiveSession(\n crypto.randomUUID(),\n adapter,\n baseRequest,\n );\n }\n\n /**\n * 注册拦截器\n * @param direction 拦截方向\n * @param fn 拦截器函数\n * @returns 取消注册的函数\n */\n use(direction: InterceptorDirection, fn: InterceptorFn): () => void {\n return this.interceptors.use(direction, fn);\n }\n\n /**\n * 获取后端能力声明\n * @param backend 后端名称\n */\n getCapabilities(backend?: string): AdapterCapabilities {\n return this.getAdapter(backend).getCapabilities();\n }\n\n /**\n * 获取指定后端的可用模型列表\n * @param backend 后端名称\n */\n async listModels(backend?: string): Promise<ModelInfo[]> {\n return this.getAdapter(backend).listModels();\n }\n\n /**\n * 检查单个后端的健康状态\n * @param backend 后端名称\n */\n async checkBackend(backend: string): Promise<HealthCheckResult> {\n const adapter = this.getAdapter(backend);\n try {\n const available = await adapter.isAvailable();\n if (!available) {\n return { available: false };\n }\n const compat = await adapter.checkCompatibility();\n const result: HealthCheckResult = {\n available: true,\n version: compat.version,\n supported: compat.supported,\n };\n if (compat.warnings.length > 0) {\n result.warnings = compat.warnings;\n }\n if (!compat.supported) {\n this.emit(\"health:degraded\", backend, compat.warnings.join(\"; \"));\n }\n return result;\n } catch (err) {\n return {\n available: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n }\n\n /**\n * 对所有已注册后端进行健康检查。\n * 返回扁平化结构,包含 version/supported/warnings 等字段。\n */\n async healthCheck(): Promise<Record<string, HealthCheckResult>> {\n const entries = Array.from(this.adapters.keys());\n const checks = entries.map(async (name) => {\n const result = await this.checkBackend(name);\n return [name, result] as const;\n });\n\n const settled = await Promise.allSettled(checks);\n const results: Record<string, HealthCheckResult> = {};\n\n for (const item of settled) {\n if (item.status === \"fulfilled\") {\n const [name, result] = item.value;\n results[name] = result;\n }\n }\n\n return results;\n }\n\n /**\n * 读取或更新后端设置\n * @param backend 后端名称\n * @param newSettings 要更新的设置项(可选)\n * @returns 当前设置\n */\n async settings(\n backend: string,\n newSettings?: Record<string, unknown>,\n ): Promise<Record<string, unknown>> {\n const adapter = this.getAdapter(backend);\n if (newSettings) {\n await adapter.updateSettings(newSettings);\n }\n return adapter.getSettings();\n }\n\n /**\n * 列出指定后端的会话\n * @param backend 后端名称\n * @param options 查询选项\n */\n async listSessions(\n backend?: string,\n options?: SessionListOptions,\n ): Promise<SessionInfo[]> {\n const name = backend ?? this.config.defaultBackend ?? \"claude\";\n return this.sessionManager.list(name, options);\n }\n\n /**\n * 中止正在运行的查询\n * @param backend 后端名称\n * @param sessionId 会话 ID\n */\n abort(backend: string, sessionId: string): void {\n this.getAdapter(backend).abort(sessionId);\n }\n\n /**\n * 释放所有资源\n */\n async dispose(): Promise<void> {\n const promises: Promise<void>[] = [];\n for (const [, adapter] of this.adapters) {\n promises.push(adapter.dispose());\n }\n await Promise.allSettled(promises);\n await this.processManager.terminateAll();\n this.adapters.clear();\n this.sessionManager.clearCache();\n }\n\n /**\n * 合并请求参数与配置默认值。\n *\n * 合并策略:\n * - model: request > backendConfig > 不设置(后端使用自身默认值)\n * - timeoutMs: request > defaults\n * - maxTurns: request > defaults\n * - cwd: request > backendConfig\n * - appendSystemPrompt: **追加模式** — defaults + backendConfig + request 三层拼接(换行分隔)\n * 但如果 request.systemPrompt 已设置(替换模式),则忽略所有 appendSystemPrompt\n *\n * @param request 原始请求\n * @param backend 后端名称\n * @returns 合并后的请求\n */\n private mergeRequest(\n request: PromptRequest,\n backend: string,\n ): PromptRequest {\n const backendConfig = this.config.backends?.[backend];\n const defaults = this.config.defaults;\n\n const appendParts: string[] = [];\n if (defaults?.appendSystemPrompt) {\n appendParts.push(defaults.appendSystemPrompt);\n }\n if (backendConfig?.appendSystemPrompt) {\n appendParts.push(backendConfig.appendSystemPrompt);\n }\n if (request.appendSystemPrompt) {\n appendParts.push(request.appendSystemPrompt);\n }\n\n return {\n ...request,\n model: request.model ?? backendConfig?.model,\n timeoutMs: request.timeoutMs ?? defaults?.timeoutMs,\n maxTurns: request.maxTurns ?? defaults?.maxTurns,\n cwd: request.cwd ?? backendConfig?.cwd,\n appendSystemPrompt: request.systemPrompt\n ? undefined\n : appendParts.length > 0\n ? appendParts.join(\"\\n\")\n : undefined,\n };\n }\n}\n\n/**\n * 创建 Porygon 实例的工厂函数\n * @param config 可选的配置参数\n * @returns Porygon 实例\n */\nexport function createPorygon(config?: Partial<PorygonConfig>): Porygon {\n return new Porygon(config);\n}\n","import type { PorygonConfig } from \"@/types/config.js\";\n\nexport const DEFAULT_CONFIG: Required<Pick<PorygonConfig, \"defaults\">> &\n PorygonConfig = {\n defaultBackend: \"claude\",\n backends: {},\n defaults: {\n timeoutMs: 300_000, // 5 minutes\n maxTurns: 50,\n },\n proxy: undefined,\n};\n\n/** 进程管理默认值 */\nexport const PROCESS_DEFAULTS = {\n GRACE_PERIOD_MS: 5_000,\n MAX_RESTARTS: 3,\n RESTART_INTERVAL_MS: 1_000,\n HEALTH_CHECK_INTERVAL_MS: 30_000,\n} as const;\n","import { z } from \"zod\";\nimport type { PorygonConfig } from \"@/types/config.js\";\nimport { ConfigValidationError } from \"@/errors/index.js\";\n\n/**\n * 代理配置校验 Schema\n */\nexport const ProxyConfigSchema = z.object({\n url: z.string().url(),\n noProxy: z.string().optional(),\n});\n\n/**\n * 后端配置校验 Schema\n */\nexport const BackendConfigSchema = z.object({\n model: z.string().optional(),\n appendSystemPrompt: z.string().optional(),\n proxy: ProxyConfigSchema.optional(),\n cwd: z.string().optional(),\n serverUrl: z.string().optional(),\n apiKey: z.string().optional(),\n interactive: z.boolean().optional(),\n cliPath: z.string().optional(),\n options: z.record(z.string(), z.unknown()).optional(),\n});\n\n/**\n * Porygon 全局配置校验 Schema\n */\nexport const PorygonConfigSchema = z.object({\n defaultBackend: z.string().optional(),\n backends: z.record(z.string(), BackendConfigSchema).optional(),\n defaults: z\n .object({\n appendSystemPrompt: z.string().optional(),\n timeoutMs: z.number().positive().optional(),\n maxTurns: z.number().int().positive().optional(),\n })\n .optional(),\n proxy: ProxyConfigSchema.optional(),\n});\n\n/**\n * 校验配置并返回类型安全的结果\n * @param config - 待校验的配置对象\n * @returns 校验通过的配置\n * @throws ConfigValidationError 校验失败时抛出\n */\nexport function validateConfig(config: unknown): PorygonConfig {\n const result = PorygonConfigSchema.safeParse(config);\n if (!result.success) {\n const issues = result.error.issues.map((issue) => ({\n path: issue.path.join(\".\"),\n message: issue.message,\n }));\n throw new ConfigValidationError(\n `配置校验失败: ${issues.map((i) => `${i.path}: ${i.message}`).join(\"; \")}`\n );\n }\n return result.data;\n}\n","/**\n * Porygon 基础错误类\n */\nexport class PorygonError extends Error {\n readonly code: string;\n\n constructor(code: string, message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = \"PorygonError\";\n this.code = code;\n }\n}\n\nexport class AdapterNotFoundError extends PorygonError {\n constructor(backend: string, options?: ErrorOptions) {\n super(\"ADAPTER_NOT_FOUND\", `Adapter not found: ${backend}`, options);\n this.name = \"AdapterNotFoundError\";\n }\n}\n\nexport class AdapterNotAvailableError extends PorygonError {\n constructor(backend: string, options?: ErrorOptions) {\n super(\"ADAPTER_NOT_AVAILABLE\", `Adapter not available: ${backend}`, options);\n this.name = \"AdapterNotAvailableError\";\n }\n}\n\nexport class AdapterIncompatibleError extends PorygonError {\n constructor(backend: string, version: string, options?: ErrorOptions) {\n super(\n \"ADAPTER_INCOMPATIBLE\",\n `Adapter incompatible: ${backend} version ${version}`,\n options,\n );\n this.name = \"AdapterIncompatibleError\";\n }\n}\n\nexport class SessionNotFoundError extends PorygonError {\n constructor(sessionId: string, options?: ErrorOptions) {\n super(\"SESSION_NOT_FOUND\", `Session not found: ${sessionId}`, options);\n this.name = \"SessionNotFoundError\";\n }\n}\n\nexport class InterceptorRejectedError extends PorygonError {\n constructor(reason: string, options?: ErrorOptions) {\n super(\"INTERCEPTOR_REJECTED\", `Interceptor rejected: ${reason}`, options);\n this.name = \"InterceptorRejectedError\";\n }\n}\n\nexport class AgentExecutionError extends PorygonError {\n constructor(message: string, options?: ErrorOptions) {\n super(\"AGENT_EXECUTION_ERROR\", message, options);\n this.name = \"AgentExecutionError\";\n }\n}\n\nexport class AgentTimeoutError extends PorygonError {\n constructor(timeoutMs: number, options?: ErrorOptions) {\n super(\"AGENT_TIMEOUT\", `Agent timed out after ${timeoutMs}ms`, options);\n this.name = \"AgentTimeoutError\";\n }\n}\n\nexport class ConfigValidationError extends PorygonError {\n constructor(message: string, options?: ErrorOptions) {\n super(\"CONFIG_VALIDATION_ERROR\", message, options);\n this.name = \"ConfigValidationError\";\n }\n}\n","import type { PorygonConfig } from \"@/types/config.js\";\nimport { DEFAULT_CONFIG } from \"./defaults.js\";\nimport { validateConfig } from \"./schema.js\";\n\n/**\n * 判断值是否为普通对象\n */\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * 深度合并两个对象,source 覆盖 target 中的同名属性\n * @param target - 基础对象\n * @param source - 覆盖对象\n * @returns 合并后的新对象\n */\nfunction deepMerge<T extends Record<string, unknown>>(\n target: T,\n source: Partial<T>\n): T {\n const result = { ...target } as Record<string, unknown>;\n\n for (const key of Object.keys(source)) {\n const sourceVal = source[key as keyof typeof source];\n const targetVal = result[key];\n\n if (sourceVal === undefined) {\n continue;\n }\n\n if (isPlainObject(targetVal) && isPlainObject(sourceVal)) {\n result[key] = deepMerge(\n targetVal as Record<string, unknown>,\n sourceVal as Record<string, unknown>\n );\n } else {\n result[key] = sourceVal;\n }\n }\n\n return result as T;\n}\n\n/**\n * 从环境变量读取配置覆盖\n */\nfunction loadEnvOverrides(): Partial<PorygonConfig> {\n const config: Partial<PorygonConfig> = {};\n\n const defaultBackend = process.env[\"PORYGON_DEFAULT_BACKEND\"];\n if (defaultBackend) {\n config.defaultBackend = defaultBackend;\n }\n\n const proxyUrl = process.env[\"PORYGON_PROXY_URL\"];\n if (proxyUrl) {\n config.proxy = {\n url: proxyUrl,\n noProxy: process.env[\"PORYGON_PROXY_NO_PROXY\"],\n };\n }\n\n return config;\n}\n\n/**\n * ConfigLoader: 从多个来源加载并合并配置。\n *\n * 优先级(后者覆盖前者):\n * 1. 内置默认值\n * 2. 环境变量 (PORYGON_DEFAULT_BACKEND, PORYGON_PROXY_URL, PORYGON_PROXY_NO_PROXY)\n * 3. createPorygon(config) 编程式传入\n */\nexport class ConfigLoader {\n /**\n * 加载并合并配置\n * @param userConfig - 用户传入的配置(可选)\n * @returns 校验通过的最终配置\n * @throws ConfigValidationError 校验失败时抛出\n */\n static load(userConfig?: Partial<PorygonConfig>): PorygonConfig {\n // 1. 以默认值为基础\n let merged: Record<string, unknown> = { ...DEFAULT_CONFIG };\n\n // 2. 应用环境变量覆盖\n const envOverrides = loadEnvOverrides();\n merged = deepMerge(merged, envOverrides);\n\n // 3. 深度合并用户配置\n if (userConfig) {\n merged = deepMerge(merged, userConfig);\n }\n\n // 4. 使用 Zod Schema 校验\n return validateConfig(merged);\n }\n}\n","import { InterceptorRejectedError } from \"@/errors/index.js\";\n\nexport type InterceptorDirection = \"input\" | \"output\";\n\nexport interface InterceptorContext {\n direction: InterceptorDirection;\n backend: string;\n sessionId?: string;\n /** 仅输出方向可用 */\n messageType?: string;\n}\n\n/**\n * 拦截器函数签名\n * - 返回 string: 替换文本,传递给下一个拦截器\n * - 返回 false: 拒绝消息,抛出 InterceptorRejectedError\n * - 返回 true/undefined: 不修改,传递原始文本给下一个拦截器\n */\nexport type InterceptorFn = (\n text: string,\n context: InterceptorContext\n) => string | boolean | undefined | Promise<string | boolean | undefined>;\n\n/**\n * 拦截器管理器,用于对输入/输出消息进行流水线式处理\n */\nexport class InterceptorManager {\n private inputInterceptors: InterceptorFn[] = [];\n private outputInterceptors: InterceptorFn[] = [];\n\n /**\n * 注册拦截器\n * @param direction - 拦截方向\n * @param fn - 拦截器函数\n * @returns 取消注册的函数\n */\n use(direction: InterceptorDirection, fn: InterceptorFn): () => void {\n const list =\n direction === \"input\" ? this.inputInterceptors : this.outputInterceptors;\n list.push(fn);\n\n return () => {\n const idx = list.indexOf(fn);\n if (idx !== -1) {\n list.splice(idx, 1);\n }\n };\n }\n\n /**\n * 执行输入拦截器流水线\n * @param text - 原始输入文本\n * @param context - 拦截器上下文(不含 direction)\n * @returns 处理后的文本\n * @throws InterceptorRejectedError 拦截器返回 false 时抛出\n */\n async processInput(\n text: string,\n context: Omit<InterceptorContext, \"direction\">\n ): Promise<string> {\n return this.runPipeline(text, \"input\", context, this.inputInterceptors);\n }\n\n /**\n * 执行输出拦截器流水线\n * @param text - 原始输出文本\n * @param context - 拦截器上下文(不含 direction)\n * @returns 处理后的文本\n * @throws InterceptorRejectedError 拦截器返回 false 时抛出\n */\n async processOutput(\n text: string,\n context: Omit<InterceptorContext, \"direction\">\n ): Promise<string> {\n return this.runPipeline(text, \"output\", context, this.outputInterceptors);\n }\n\n /**\n * 执行拦截器流水线\n */\n private async runPipeline(\n text: string,\n direction: InterceptorDirection,\n context: Omit<InterceptorContext, \"direction\">,\n interceptors: InterceptorFn[]\n ): Promise<string> {\n const fullContext: InterceptorContext = { ...context, direction };\n let current = text;\n\n for (const fn of interceptors) {\n const result = await fn(current, fullContext);\n\n if (result === false) {\n throw new InterceptorRejectedError(direction);\n }\n\n if (typeof result === \"string\") {\n current = result;\n }\n // true / undefined -> 不修改,继续传递 current\n }\n\n return current;\n }\n}\n","import { spawn, type ChildProcess } from \"node:child_process\";\nimport { EventEmitter } from \"node:events\";\nimport { createInterface } from \"node:readline\";\nimport type {\n SpawnOptions,\n ProcessResult,\n PersistentProcessOptions,\n} from \"@/types/process.js\";\n\n/** 优雅终止等待时长(毫秒) */\nconst GRACE_PERIOD_MS = 5_000;\n\n/**\n * EphemeralProcess:一次性进程执行,支持流式输出。\n * 适用于 `claude -p` 和 `opencode run` 等短生命周期调用场景。\n */\nexport class EphemeralProcess {\n private childProcess: ChildProcess | null = null;\n private aborted = false;\n\n /**\n * 执行命令并收集输出。支持 AbortController 进行取消操作。\n * @param options 进程启动选项\n * @param abortSignal 可选的中止信号\n * @returns 进程执行结果\n */\n async execute(\n options: SpawnOptions,\n abortSignal?: AbortSignal,\n ): Promise<ProcessResult> {\n return new Promise<ProcessResult>((resolve, reject) => {\n if (abortSignal?.aborted) {\n reject(new Error(\"Process aborted before start\"));\n return;\n }\n\n this.aborted = false;\n const child = spawn(options.command, options.args, {\n cwd: options.cwd,\n env: options.env ? { ...process.env, ...options.env } : undefined,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n this.childProcess = child;\n\n const stdoutChunks: Buffer[] = [];\n const stderrChunks: Buffer[] = [];\n\n child.stdout?.on(\"data\", (chunk: Buffer) => {\n stdoutChunks.push(chunk);\n });\n\n child.stderr?.on(\"data\", (chunk: Buffer) => {\n stderrChunks.push(chunk);\n });\n\n let timeoutTimer: ReturnType<typeof setTimeout> | undefined;\n if (options.timeoutMs !== undefined && options.timeoutMs > 0) {\n timeoutTimer = setTimeout(() => {\n this.terminate();\n reject(new Error(`Process timed out after ${options.timeoutMs}ms`));\n }, options.timeoutMs);\n }\n\n const onAbort = (): void => {\n this.terminate();\n reject(new Error(\"Process aborted\"));\n };\n abortSignal?.addEventListener(\"abort\", onAbort, { once: true });\n\n child.on(\"error\", (err: Error) => {\n if (timeoutTimer) clearTimeout(timeoutTimer);\n abortSignal?.removeEventListener(\"abort\", onAbort);\n this.childProcess = null;\n reject(err);\n });\n\n child.on(\"close\", (code: number | null, signal: NodeJS.Signals | null) => {\n if (timeoutTimer) clearTimeout(timeoutTimer);\n abortSignal?.removeEventListener(\"abort\", onAbort);\n this.childProcess = null;\n resolve({\n exitCode: code,\n signal: signal,\n stdout: Buffer.concat(stdoutChunks).toString(\"utf-8\"),\n stderr: Buffer.concat(stderrChunks).toString(\"utf-8\"),\n });\n });\n });\n }\n\n /**\n * 以流式方式执行命令,逐行输出 stdout 内容。\n * @param options 进程启动选项\n * @param abortSignal 可选的中止信号\n */\n async *executeStreaming(\n options: SpawnOptions,\n abortSignal?: AbortSignal,\n ): AsyncGenerator<string> {\n if (abortSignal?.aborted) {\n throw new Error(\"Process aborted before start\");\n }\n\n this.aborted = false;\n const useStdin = options.stdinData !== undefined;\n const child = spawn(options.command, options.args, {\n cwd: options.cwd,\n env: options.env ?? undefined,\n stdio: [useStdin ? \"pipe\" : \"ignore\", \"pipe\", \"pipe\"],\n });\n this.childProcess = child;\n\n // 写入 stdin 数据后关闭\n if (useStdin && child.stdin) {\n child.stdin.write(options.stdinData, () => {\n child.stdin!.end();\n });\n }\n\n let timeoutTimer: ReturnType<typeof setTimeout> | undefined;\n if (options.timeoutMs !== undefined && options.timeoutMs > 0) {\n timeoutTimer = setTimeout(() => {\n this.terminate();\n }, options.timeoutMs);\n }\n\n const onAbort = (): void => {\n this.terminate();\n };\n abortSignal?.addEventListener(\"abort\", onAbort, { once: true });\n\n // 收集 stderr 用于错误诊断\n const stderrChunks: Buffer[] = [];\n child.stderr?.on(\"data\", (chunk: Buffer) => {\n stderrChunks.push(chunk);\n });\n\n // 监听子进程退出码\n let exitCode: number | null = null;\n const exitPromise = new Promise<void>((resolve) => {\n child.on(\"close\", (code) => {\n exitCode = code;\n resolve();\n });\n });\n\n // 使用 readline 进行逐行读取\n const rl = createInterface({ input: child.stdout! });\n let yieldedLines = 0;\n\n try {\n for await (const line of rl) {\n yieldedLines++;\n yield line;\n }\n\n // readline 结束后等待进程退出,获取退出码\n await exitPromise;\n\n // 进程非正常退出且没有产出任何数据时,将 stderr 作为错误抛出\n if (exitCode !== 0 && yieldedLines === 0 && !this.aborted) {\n const stderr = Buffer.concat(stderrChunks).toString(\"utf-8\").trim();\n throw new Error(\n stderr || `Process exited with code ${exitCode}`,\n );\n }\n } finally {\n if (timeoutTimer) clearTimeout(timeoutTimer);\n abortSignal?.removeEventListener(\"abort\", onAbort);\n rl.close();\n this.childProcess = null;\n }\n }\n\n /** 获取底层子进程的 PID */\n get pid(): number | undefined {\n return this.childProcess?.pid;\n }\n\n /** 终止进程:先发送 SIGTERM,超时后发送 SIGKILL */\n terminate(): void {\n if (!this.childProcess || this.aborted) return;\n this.aborted = true;\n this.childProcess.kill(\"SIGTERM\");\n const ref = this.childProcess;\n setTimeout(() => {\n if (!ref.killed) {\n ref.kill(\"SIGKILL\");\n }\n }, GRACE_PERIOD_MS);\n }\n}\n\n/**\n * PersistentProcess:长期运行的服务进程,支持自动重启。\n * 适用于 `opencode serve` 等持久化服务场景。\n */\nexport class PersistentProcess extends EventEmitter {\n private process: ChildProcess | null = null;\n private restartCount = 0;\n private stopped = false;\n private healthCheckTimer: ReturnType<typeof setInterval> | null = null;\n private readonly options: PersistentProcessOptions;\n\n constructor(options: PersistentProcessOptions) {\n super();\n this.options = options;\n }\n\n /** 启动持久进程 */\n async start(): Promise<void> {\n this.stopped = false;\n\n const child = spawn(this.options.command, this.options.args, {\n cwd: this.options.cwd,\n env: this.options.env\n ? { ...process.env, ...this.options.env }\n : undefined,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n this.process = child;\n\n child.on(\"error\", (err: Error) => {\n this.emit(\"error\", err);\n });\n\n child.on(\"exit\", (code: number | null) => {\n this.process = null;\n this.stopHealthCheck();\n this.handleCrash(code);\n });\n\n // 启动健康检查\n if (this.options.healthCheckFn && this.options.healthCheckIntervalMs > 0) {\n this.healthCheckTimer = setInterval(() => {\n this.options.healthCheckFn!().catch((err: unknown) => {\n this.emit(\"healthCheckFailed\", err);\n });\n }, this.options.healthCheckIntervalMs);\n }\n\n this.emit(\"started\", child.pid);\n }\n\n /** 处理进程崩溃,按指数退避策略重启 */\n private handleCrash(code: number | null): void {\n if (this.stopped) return;\n\n this.emit(\"exit\", code);\n\n if (this.restartCount < this.options.maxRestarts) {\n const delay =\n this.options.restartIntervalMs * Math.pow(2, this.restartCount);\n this.restartCount++;\n this.emit(\"restart\", this.restartCount);\n\n setTimeout(() => {\n if (!this.stopped) {\n this.start().catch((err: unknown) => {\n this.emit(\"fatal\", err);\n });\n }\n }, delay);\n } else {\n this.emit(\n \"fatal\",\n new Error(\n `Max restarts (${this.options.maxRestarts}) exceeded, last exit code: ${code}`,\n ),\n );\n }\n }\n\n /** 停止健康检查定时器 */\n private stopHealthCheck(): void {\n if (this.healthCheckTimer) {\n clearInterval(this.healthCheckTimer);\n this.healthCheckTimer = null;\n }\n }\n\n /** 停止持久进程 */\n async stop(): Promise<void> {\n this.stopped = true;\n this.stopHealthCheck();\n\n if (this.process) {\n const child = this.process;\n child.kill(\"SIGTERM\");\n\n await new Promise<void>((resolve) => {\n const timer = setTimeout(() => {\n if (!child.killed) {\n child.kill(\"SIGKILL\");\n }\n resolve();\n }, GRACE_PERIOD_MS);\n\n child.on(\"exit\", () => {\n clearTimeout(timer);\n resolve();\n });\n });\n\n this.process = null;\n }\n }\n\n /** 获取底层子进程的 PID */\n get pid(): number | undefined {\n return this.process?.pid;\n }\n\n /** 当前进程是否正在运行 */\n get isRunning(): boolean {\n return this.process !== null && !this.process.killed;\n }\n}\n","import { EphemeralProcess, PersistentProcess } from \"./process-handle.js\";\nimport type { PersistentProcessOptions } from \"@/types/process.js\";\n\n/**\n * ProcessManager:统一管理所有子进程。\n * 注册退出钩子,确保主进程退出时清理所有子进程。\n */\nexport class ProcessManager {\n private readonly ephemeral = new Map<string, EphemeralProcess>();\n private readonly persistent = new Map<string, PersistentProcess>();\n\n /** 全局静态标记,确保信号处理器只注册一次 */\n private static cleanupRegistered = false;\n /** 所有活跃的 ProcessManager 实例(弱引用避免阻止 GC) */\n private static readonly instances = new Set<ProcessManager>();\n\n constructor() {\n ProcessManager.instances.add(this);\n ProcessManager.registerCleanup();\n }\n\n /** 注册进程退出清理钩子(仅清理资源,不劫持宿主退出行为) */\n private static registerCleanup(): void {\n if (ProcessManager.cleanupRegistered) return;\n ProcessManager.cleanupRegistered = true;\n\n const cleanup = (): void => {\n for (const instance of ProcessManager.instances) {\n instance.terminateAllSync();\n }\n };\n\n process.on(\"exit\", cleanup);\n\n // 信号处理:仅清理子进程资源,不调用 process.exit(),\n // 让宿主进程自行决定退出逻辑\n process.on(\"SIGTERM\", cleanup);\n process.on(\"SIGINT\", cleanup);\n }\n\n /**\n * 创建一次性进程实例并注册到管理器\n * @param sessionId 会话标识\n * @returns 一次性进程实例\n */\n createEphemeral(sessionId: string): EphemeralProcess {\n const proc = new EphemeralProcess();\n this.ephemeral.set(sessionId, proc);\n return proc;\n }\n\n /**\n * 从管理器中移除一次性进程\n * @param sessionId 会话标识\n */\n removeEphemeral(sessionId: string): void {\n this.ephemeral.delete(sessionId);\n }\n\n /**\n * 启动或获取持久进程\n * @param backend 后端标识\n * @param options 持久进程选项\n * @returns 持久进程实例\n */\n async startPersistent(\n backend: string,\n options: PersistentProcessOptions,\n ): Promise<PersistentProcess> {\n const existing = this.persistent.get(backend);\n if (existing?.isRunning) return existing;\n\n const proc = new PersistentProcess(options);\n this.persistent.set(backend, proc);\n await proc.start();\n return proc;\n }\n\n /**\n * 获取指定后端的持久进程\n * @param backend 后端标识\n */\n getPersistent(backend: string): PersistentProcess | undefined {\n return this.persistent.get(backend);\n }\n\n /**\n * 获取指定会话的一次性进程\n * @param sessionId 会话标识\n */\n getEphemeral(sessionId: string): EphemeralProcess | undefined {\n return this.ephemeral.get(sessionId);\n }\n\n /** 异步终止所有托管进程 */\n async terminateAll(): Promise<void> {\n const promises: Promise<void>[] = [];\n\n for (const [, proc] of this.ephemeral) {\n proc.terminate();\n }\n\n for (const [, proc] of this.persistent) {\n promises.push(proc.stop());\n }\n\n this.ephemeral.clear();\n await Promise.allSettled(promises);\n this.persistent.clear();\n }\n\n /** 同步终止所有托管进程(用于 exit 钩子) */\n private terminateAllSync(): void {\n for (const [, proc] of this.ephemeral) {\n proc.terminate();\n }\n\n for (const [, proc] of this.persistent) {\n const pid = proc.pid;\n if (pid) {\n try {\n process.kill(pid, \"SIGTERM\");\n } catch {\n // 进程可能已退出,忽略错误\n }\n }\n }\n }\n\n /**\n * 销毁实例,从全局实例列表中移除\n */\n destroy(): void {\n ProcessManager.instances.delete(this);\n }\n}\n","import type { IAgentAdapter, SessionInfo, SessionListOptions } from \"@/types/adapter.js\";\nimport type { AgentMessage } from \"@/types/common.js\";\nimport { SessionNotFoundError, AdapterNotFoundError } from \"@/errors/index.js\";\n\n/**\n * SessionManager: 管理会话生命周期,委托后端适配器执行实际操作。\n * 会话归属于后端适配器,本类提供缓存与统一访问接口。\n */\nexport class SessionManager {\n private cache = new Map<string, SessionInfo>();\n private adapters = new Map<string, IAgentAdapter>();\n\n /**\n * 注册适配器用于会话管理\n * @param backend 后端标识\n * @param adapter 适配器实例\n */\n registerAdapter(backend: string, adapter: IAgentAdapter): void {\n this.adapters.set(backend, adapter);\n }\n\n /**\n * 注销适配器\n * @param backend 后端标识\n */\n unregisterAdapter(backend: string): void {\n this.adapters.delete(backend);\n }\n\n /**\n * 获取指定后端的适配器,不存在时抛出错误\n * @param backend 后端标识\n */\n private getAdapter(backend: string): IAgentAdapter {\n const adapter = this.adapters.get(backend);\n if (!adapter) {\n throw new AdapterNotFoundError(backend);\n }\n return adapter;\n }\n\n /**\n * 列出指定后端的会话,结果会写入缓存\n * @param backend 后端标识\n * @param options 查询选项\n */\n async list(backend: string, options?: SessionListOptions): Promise<SessionInfo[]> {\n const adapter = this.getAdapter(backend);\n const sessions = await adapter.listSessions(options);\n for (const session of sessions) {\n this.cache.set(session.sessionId, session);\n }\n return sessions;\n }\n\n /**\n * 从缓存中获取会话信息\n * @param sessionId 会话 ID\n */\n get(sessionId: string): SessionInfo | undefined {\n return this.cache.get(sessionId);\n }\n\n /**\n * 恢复会话,委托适配器以 resume 标志执行查询\n * @param backend 后端标识\n * @param sessionId 要恢复的会话 ID\n * @param prompt 提示词\n */\n async *resume(\n backend: string,\n sessionId: string,\n prompt: string\n ): AsyncGenerator<AgentMessage> {\n const adapter = this.getAdapter(backend);\n yield* adapter.query({ prompt, resume: sessionId });\n }\n\n /**\n * 从缓存中移除指定会话\n * @param sessionId 会话 ID\n */\n evict(sessionId: string): void {\n this.cache.delete(sessionId);\n }\n\n /**\n * 清空全部会话缓存\n */\n clearCache(): void {\n this.cache.clear();\n }\n}\n","import { readFile, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { randomUUID } from \"node:crypto\";\nimport { AbstractAgentAdapter } from \"@/adapters/base.js\";\nimport { EphemeralProcess } from \"@/process/process-handle.js\";\nimport type {\n PromptRequest,\n AgentMessage,\n AdapterCapabilities,\n SessionInfo,\n SessionListOptions,\n ModelInfo,\n} from \"@/types/index.js\";\nimport { mapClaudeEvent } from \"./message-mapper.js\";\n\n/** Claude 设置文件路径 */\nconst CLAUDE_SETTINGS_PATH = join(homedir(), \".claude\", \"settings.json\");\n\n/** Claude 可用模型列表(使用别名自动匹配最新版本) */\nconst CLAUDE_MODELS: ModelInfo[] = [\n { id: \"sonnet\", name: \"Sonnet\", provider: \"anthropic\" },\n { id: \"opus\", name: \"Opus\", provider: \"anthropic\" },\n { id: \"haiku\", name: \"Haiku\", provider: \"anthropic\" },\n];\n\n/**\n * Claude Code CLI 适配器。\n * 通过 `claude -p --output-format stream-json` 命令与 Claude Code 交互。\n */\nexport class ClaudeAdapter extends AbstractAgentAdapter {\n readonly backend = \"claude\";\n\n /** CLI 命令名或路径 */\n private get cliCommand(): string {\n return this.config?.cliPath ?? \"claude\";\n }\n\n /**\n * 检查 Claude CLI 是否可用\n */\n async isAvailable(): Promise<boolean> {\n try {\n const proc = new EphemeralProcess();\n const result = await proc.execute({\n command: \"which\",\n args: [this.cliCommand],\n });\n return result.exitCode === 0;\n } catch {\n return false;\n }\n }\n\n /**\n * 获取 Claude CLI 版本号\n */\n async getVersion(): Promise<string> {\n const proc = new EphemeralProcess();\n const result = await proc.execute({\n command: this.cliCommand,\n args: [\"--version\"],\n });\n\n if (result.exitCode !== 0) {\n throw new Error(`获取 Claude 版本失败: ${result.stderr}`);\n }\n\n // claude --version 输出格式可能为 \"claude X.Y.Z\" 或纯版本号\n const output = result.stdout.trim();\n const match = /(\\d+\\.\\d+\\.\\d+)/.exec(output);\n if (!match) {\n throw new Error(`无法解析 Claude 版本号: ${output}`);\n }\n\n return match[1];\n }\n\n /**\n * 获取 Claude 适配器能力声明\n */\n getCapabilities(): AdapterCapabilities {\n return {\n features: new Set([\n \"streaming\",\n \"session-resume\",\n \"system-prompt\",\n \"tool-restriction\",\n \"mcp\",\n \"subagents\",\n \"worktree\",\n \"interactive-session\",\n ]),\n streamingMode: \"chunked\",\n outputFormats: [\"text\", \"json\", \"stream-json\"],\n testedVersionRange: \">=1.0.0\",\n };\n }\n\n /**\n * 向 Claude 发送提示并以流式方式接收响应\n * @param request 提示请求参数\n */\n async *query(request: PromptRequest): AsyncGenerator<AgentMessage> {\n const sessionId = request.resume ?? randomUUID();\n const controller = this.createAbortController(sessionId);\n const proc = this.processManager.createEphemeral(sessionId);\n\n try {\n const args = this.buildArgs(request);\n const cwd = request.cwd ?? this.config?.cwd;\n\n // 构建子进程环境变量:排除 CLAUDECODE,注入代理和请求级环境变量\n const cleanEnv: Record<string, string> = {};\n for (const [k, v] of Object.entries(process.env)) {\n if (k !== \"CLAUDECODE\" && v !== undefined) {\n cleanEnv[k] = v;\n }\n }\n\n // 注入代理环境变量(配置级)\n const proxyUrl = this.config?.proxy?.url;\n if (proxyUrl) {\n this.applyProxyEnv(cleanEnv, proxyUrl, this.config?.proxy?.noProxy);\n }\n\n // 注入请求级环境变量(最高优先级,可覆盖上面的所有变量)\n if (request.envVars) {\n for (const [k, v] of Object.entries(request.envVars)) {\n if (v) cleanEnv[k] = v;\n }\n }\n\n // 通过 stdin 传递 prompt,避免超长 CLI 参数导致的问题\n const stdinData = this.buildStdinData(request);\n\n const streamOptions = {\n command: this.cliCommand,\n args,\n ...(cwd ? { cwd } : {}),\n env: cleanEnv,\n timeoutMs: request.timeoutMs,\n stdinData,\n };\n\n // 输出调试信息:完整的 CLI 命令\n const cmdStr = [this.cliCommand, ...args.map(a => /[\\s\"']/.test(a) ? JSON.stringify(a) : a)].join(\" \");\n const debugCmd = cwd ? `cd ${JSON.stringify(cwd)} && ${cmdStr}` : cmdStr;\n // 调试命令信息通过 system 消息输出,避免直接使用 console\n\n yield {\n type: \"system\" as const,\n timestamp: Date.now(),\n sessionId,\n cwd,\n raw: { debug_command: debugCmd },\n };\n\n for await (const line of proc.executeStreaming(\n streamOptions,\n controller.signal,\n )) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(trimmed) as Record<string, unknown>;\n } catch {\n // JSON 解析失败,跳过该行\n // JSON 解析失败的行静默跳过,非结构化输出无需处理\n continue;\n }\n\n const messages = mapClaudeEvent(parsed, sessionId);\n for (const message of messages) {\n yield message;\n }\n }\n } finally {\n this.removeAbortController(sessionId);\n this.processManager.removeEphemeral(sessionId);\n }\n }\n\n /**\n * 列出 Claude 会话\n * @param options 查询选项\n */\n async listSessions(options?: SessionListOptions): Promise<SessionInfo[]> {\n const proc = new EphemeralProcess();\n const args = [\"sessions\", \"list\", \"--output\", \"json\"];\n\n if (options?.limit) {\n args.push(\"--limit\", String(options.limit));\n }\n\n const result = await proc.execute({\n command: this.cliCommand,\n args,\n cwd: options?.cwd,\n });\n\n if (result.exitCode !== 0) {\n throw new Error(`获取 Claude 会话列表失败: ${result.stderr}`);\n }\n\n const output = result.stdout.trim();\n if (!output) return [];\n\n let rawSessions: unknown;\n try {\n rawSessions = JSON.parse(output);\n } catch {\n throw new Error(`解析 Claude 会话列表失败: ${output.slice(0, 200)}`);\n }\n\n if (!Array.isArray(rawSessions)) return [];\n\n return rawSessions.map((session: unknown) => {\n const s = session as Record<string, unknown>;\n return {\n sessionId: String(s[\"id\"] ?? s[\"session_id\"] ?? \"\"),\n backend: this.backend,\n summary: typeof s[\"summary\"] === \"string\" ? s[\"summary\"] : undefined,\n lastModified:\n typeof s[\"last_modified\"] === \"number\"\n ? s[\"last_modified\"]\n : typeof s[\"last_modified\"] === \"string\"\n ? new Date(s[\"last_modified\"]).getTime()\n : Date.now(),\n cwd: typeof s[\"cwd\"] === \"string\" ? s[\"cwd\"] : undefined,\n metadata: s as Record<string, unknown>,\n };\n });\n }\n\n /**\n * 获取 Claude 可用模型列表。\n * Claude CLI 支持使用简短别名(sonnet/opus/haiku)自动选择当前最新版本。\n */\n async listModels(): Promise<ModelInfo[]> {\n return CLAUDE_MODELS;\n }\n\n /**\n * 读取 Claude 设置\n */\n async getSettings(): Promise<Record<string, unknown>> {\n try {\n const content = await readFile(CLAUDE_SETTINGS_PATH, \"utf-8\");\n const parsed: unknown = JSON.parse(content);\n if (typeof parsed === \"object\" && parsed !== null) {\n return parsed as Record<string, unknown>;\n }\n return {};\n } catch {\n return {};\n }\n }\n\n /**\n * 更新 Claude 设置(读取-合并-写入)\n * @param settings 要合并的设置项\n */\n async updateSettings(settings: Record<string, unknown>): Promise<void> {\n const current = await this.getSettings();\n const merged = { ...current, ...settings };\n await writeFile(\n CLAUDE_SETTINGS_PATH,\n JSON.stringify(merged, null, 2),\n \"utf-8\",\n );\n }\n\n /**\n * 释放适配器资源\n */\n async dispose(): Promise<void> {\n // 中止所有活跃会话\n for (const [sessionId] of this.abortControllers) {\n this.abort(sessionId);\n }\n }\n\n /**\n * 将代理配置注入到环境变量中\n * @param env 环境变量对象\n * @param proxyUrl 代理地址\n * @param noProxy 不走代理的地址列表\n */\n private applyProxyEnv(env: Record<string, string>, proxyUrl: string, noProxy?: string): void {\n env[\"http_proxy\"] = proxyUrl;\n env[\"https_proxy\"] = proxyUrl;\n env[\"HTTP_PROXY\"] = proxyUrl;\n env[\"HTTPS_PROXY\"] = proxyUrl;\n env[\"all_proxy\"] = proxyUrl;\n env[\"ALL_PROXY\"] = proxyUrl;\n if (noProxy) {\n env[\"no_proxy\"] = noProxy;\n env[\"NO_PROXY\"] = noProxy;\n }\n }\n\n /**\n * 构建通过 stdin 传递给 Claude CLI 的数据。\n * 使用 stdin 而非 CLI 参数传递 prompt,避免超长参数导致的 403 错误。\n */\n private buildStdinData(request: PromptRequest): string {\n return request.prompt;\n }\n\n private buildArgs(request: PromptRequest): string[] {\n const args: string[] = [\n \"--print\",\n \"--output-format\",\n \"stream-json\",\n \"--verbose\",\n ];\n\n // 恢复会话\n if (request.resume) {\n args.push(\"--resume\", request.resume);\n }\n\n // 模型选择\n const model = request.model ?? this.config?.model;\n if (model) {\n args.push(\"--model\", model);\n }\n\n // 系统提示词通过 --system-prompt 参数传递(短内容)\n // 或通过 stdin 的 <system> 标签传递(长内容,见 buildStdinData)\n if (request.systemPrompt) {\n args.push(\"--system-prompt\", request.systemPrompt);\n }\n\n const appendPrompt =\n request.appendSystemPrompt ?? this.config?.appendSystemPrompt;\n if (appendPrompt) {\n args.push(\"--append-system-prompt\", appendPrompt);\n }\n\n // 工具限制\n if (request.allowedTools && request.allowedTools.length > 0) {\n for (const tool of request.allowedTools) {\n args.push(\"--allowedTools\", tool);\n }\n }\n\n if (request.disallowedTools && request.disallowedTools.length > 0) {\n for (const tool of request.disallowedTools) {\n args.push(\"--disallowedTools\", tool);\n }\n }\n\n // 最大轮次\n if (request.maxTurns !== undefined) {\n args.push(\"--max-turns\", String(request.maxTurns));\n }\n\n // 跳过权限确认(非交互模式必需)\n // 优先从 BackendConfig.interactive 读取,false 表示跳过权限确认\n // 向后兼容:仍支持 options.dangerouslySkipPermissions\n const interactive = this.config?.interactive;\n const skipPerms = interactive === false\n || request.backendOptions?.dangerouslySkipPermissions\n || this.config?.options?.dangerouslySkipPermissions;\n if (skipPerms) {\n args.push(\"--dangerously-skip-permissions\");\n }\n\n // MCP 服务器配置\n if (request.mcpServers) {\n for (const [name, config] of Object.entries(request.mcpServers)) {\n const serverSpec: Record<string, unknown> = {\n command: config.command,\n ...(config.args ? { args: config.args } : {}),\n ...(config.env ? { env: config.env } : {}),\n ...(config.url ? { url: config.url } : {}),\n };\n args.push(\"--mcp-server\", `${name}=${JSON.stringify(serverSpec)}`);\n }\n }\n\n return args;\n }\n}\n","import type { ProcessManager } from \"@/process/process-manager.js\";\nimport type {\n PromptRequest,\n AgentMessage,\n AdapterCapabilities,\n CompatibilityResult,\n SessionInfo,\n SessionListOptions,\n IAgentAdapter,\n ModelInfo,\n BackendConfig,\n} from \"@/types/index.js\";\n\n/**\n * 简易语义版本范围匹配,支持 >=X.Y.Z 格式\n * @param version 当前版本号\n * @param range 版本范围表达式\n * @returns 是否满足范围要求\n */\nfunction satisfiesRange(version: string, range: string): boolean {\n const parseVersion = (v: string): [number, number, number] | null => {\n const match = /^v?(\\d+)\\.(\\d+)\\.(\\d+)/.exec(v.trim());\n if (!match) return null;\n return [Number(match[1]), Number(match[2]), Number(match[3])];\n };\n\n const trimmed = range.trim();\n\n // 处理 >=X.Y.Z 格式\n if (trimmed.startsWith(\">=\")) {\n const rangeVersion = parseVersion(trimmed.slice(2));\n const currentVersion = parseVersion(version);\n if (!rangeVersion || !currentVersion) return false;\n\n for (let i = 0; i < 3; i++) {\n if (currentVersion[i] > rangeVersion[i]) return true;\n if (currentVersion[i] < rangeVersion[i]) return false;\n }\n return true; // 版本相等\n }\n\n // 处理 <=X.Y.Z 格式\n if (trimmed.startsWith(\"<=\")) {\n const rangeVersion = parseVersion(trimmed.slice(2));\n const currentVersion = parseVersion(version);\n if (!rangeVersion || !currentVersion) return false;\n\n for (let i = 0; i < 3; i++) {\n if (currentVersion[i] < rangeVersion[i]) return true;\n if (currentVersion[i] > rangeVersion[i]) return false;\n }\n return true;\n }\n\n // 精确匹配\n const rangeVersion = parseVersion(trimmed);\n const currentVersion = parseVersion(version);\n if (!rangeVersion || !currentVersion) return false;\n return (\n currentVersion[0] === rangeVersion[0] &&\n currentVersion[1] === rangeVersion[1] &&\n currentVersion[2] === rangeVersion[2]\n );\n}\n\n/**\n * Agent 适配器抽象基类,实现 IAgentAdapter 接口的公共逻辑。\n * 子类需实现所有 abstract 方法以完成具体后端的适配。\n */\nexport abstract class AbstractAgentAdapter implements IAgentAdapter {\n abstract readonly backend: string;\n\n /** 活跃的 AbortController 映射,按 sessionId 索引 */\n protected readonly abortControllers = new Map<string, AbortController>();\n\n protected readonly processManager: ProcessManager;\n protected readonly config?: BackendConfig;\n\n constructor(processManager: ProcessManager, config?: BackendConfig) {\n this.processManager = processManager;\n this.config = config;\n }\n\n /**\n * 默认兼容性检查:获取当前版本并与 testedVersionRange 进行比较\n */\n async checkCompatibility(): Promise<CompatibilityResult> {\n const warnings: string[] = [];\n\n let version: string;\n try {\n version = await this.getVersion();\n } catch {\n return {\n version: \"unknown\",\n supported: false,\n warnings: [`无法获取 ${this.backend} 版本信息`],\n };\n }\n\n const capabilities = this.getCapabilities();\n const supported = satisfiesRange(version, capabilities.testedVersionRange);\n\n if (!supported) {\n warnings.push(\n `${this.backend} 版本 ${version} 不在测试范围 ${capabilities.testedVersionRange} 内,可能存在兼容性问题`,\n );\n }\n\n return { version, supported, warnings };\n }\n\n /**\n * 中止指定会话的执行\n * @param sessionId 会话标识\n */\n abort(sessionId: string): void {\n const controller = this.abortControllers.get(sessionId);\n if (controller) {\n controller.abort();\n this.abortControllers.delete(sessionId);\n }\n }\n\n /**\n * 创建并注册 AbortController\n * @param sessionId 会话标识\n * @returns AbortController 实例\n */\n protected createAbortController(sessionId: string): AbortController {\n // 如已有旧的 controller,先中止\n const existing = this.abortControllers.get(sessionId);\n if (existing) {\n existing.abort();\n }\n const controller = new AbortController();\n this.abortControllers.set(sessionId, controller);\n return controller;\n }\n\n /**\n * 清理指定会话的 AbortController\n * @param sessionId 会话标识\n */\n protected removeAbortController(sessionId: string): void {\n this.abortControllers.delete(sessionId);\n }\n\n abstract isAvailable(): Promise<boolean>;\n abstract getVersion(): Promise<string>;\n abstract getCapabilities(): AdapterCapabilities;\n abstract query(request: PromptRequest): AsyncGenerator<AgentMessage>;\n abstract listSessions(options?: SessionListOptions): Promise<SessionInfo[]>;\n abstract listModels(): Promise<ModelInfo[]>;\n abstract getSettings(): Promise<Record<string, unknown>>;\n abstract updateSettings(settings: Record<string, unknown>): Promise<void>;\n abstract dispose(): Promise<void>;\n}\n","/**\n * Claude CLI stream-json 事件基础接口\n */\ninterface ClaudeBaseEvent {\n type: string;\n /** 会话 ID */\n session_id?: string;\n}\n\n/**\n * 系统初始化事件 - 首个事件,包含模型和工具信息\n */\nexport interface ClaudeSystemEvent extends ClaudeBaseEvent {\n type: \"system\";\n subtype: \"init\";\n model?: string;\n tools?: string[];\n cwd?: string;\n}\n\n/**\n * 内容块类型\n */\nexport interface ClaudeTextBlock {\n type: \"text\";\n text: string;\n}\n\nexport interface ClaudeToolUseBlock {\n type: \"tool_use\";\n id: string;\n name: string;\n input: Record<string, unknown>;\n}\n\nexport interface ClaudeToolResultBlock {\n type: \"tool_result\";\n tool_use_id: string;\n content: string;\n}\n\nexport type ClaudeContentBlock =\n | ClaudeTextBlock\n | ClaudeToolUseBlock\n | ClaudeToolResultBlock;\n\n/**\n * 助手消息事件 - 包含完整的助手回复内容块\n */\nexport interface ClaudeAssistantEvent extends ClaudeBaseEvent {\n type: \"assistant\";\n message: {\n content: ClaudeContentBlock[];\n model?: string;\n stop_reason?: string;\n };\n}\n\n/**\n * 流式事件 - 包含增量内容(文本 delta 等)\n */\nexport interface ClaudeStreamEventWrapper extends ClaudeBaseEvent {\n type: \"stream_event\";\n event: {\n type?: string;\n index?: number;\n delta?: {\n type: \"text_delta\" | \"input_json_delta\";\n text?: string;\n partial_json?: string;\n };\n content_block?: ClaudeContentBlock;\n };\n}\n\n/**\n * 结果事件 - 最终结果,包含计费和统计信息\n */\nexport interface ClaudeResultEvent extends ClaudeBaseEvent {\n type: \"result\";\n result: string;\n cost_usd?: number;\n duration_ms?: number;\n duration_api_ms?: number;\n input_tokens?: number;\n output_tokens?: number;\n is_error?: boolean;\n num_turns?: number;\n session_id?: string;\n}\n\n/**\n * Claude CLI stream-json 事件联合类型(判别联合)\n */\nexport type ClaudeStreamEvent =\n | ClaudeSystemEvent\n | ClaudeAssistantEvent\n | ClaudeStreamEventWrapper\n | ClaudeResultEvent;\n\n/**\n * 类型守卫:检查是否为 ClaudeSystemEvent\n */\nexport function isSystemEvent(event: unknown): event is ClaudeSystemEvent {\n if (typeof event !== \"object\" || event === null) return false;\n return (event as Record<string, unknown>)[\"type\"] === \"system\";\n}\n\n/**\n * 类型守卫:检查是否为 ClaudeAssistantEvent\n */\nexport function isAssistantEvent(event: unknown): event is ClaudeAssistantEvent {\n if (typeof event !== \"object\" || event === null) return false;\n const obj = event as Record<string, unknown>;\n return obj[\"type\"] === \"assistant\" && typeof obj[\"message\"] === \"object\" && obj[\"message\"] !== null;\n}\n\n/**\n * 类型守卫:检查是否为 ClaudeStreamEventWrapper\n */\nexport function isStreamEvent(event: unknown): event is ClaudeStreamEventWrapper {\n if (typeof event !== \"object\" || event === null) return false;\n const obj = event as Record<string, unknown>;\n return obj[\"type\"] === \"stream_event\" && typeof obj[\"event\"] === \"object\" && obj[\"event\"] !== null;\n}\n\n/**\n * 类型守卫:检查是否为 ClaudeResultEvent\n */\nexport function isResultEvent(event: unknown): event is ClaudeResultEvent {\n if (typeof event !== \"object\" || event === null) return false;\n const obj = event as Record<string, unknown>;\n return obj[\"type\"] === \"result\" && \"result\" in obj;\n}\n","import type { AgentMessage } from \"@/types/index.js\";\nimport {\n isSystemEvent,\n isAssistantEvent,\n isStreamEvent,\n isResultEvent,\n type ClaudeContentBlock,\n} from \"./types.js\";\n\n/**\n * 将 Claude CLI stream-json 事件映射为统一的 AgentMessage 数组。\n * Claude CLI 的 assistant 事件可能包含多个内容块(文本 + 工具调用),\n * 本函数将它们拆分为独立的消息逐条返回,确保与 OpenCode 适配器行为一致。\n *\n * 对于不关注的事件类型返回空数组。\n *\n * @param event 解析后的 Claude 事件对象\n * @param sessionId 可选的会话 ID\n * @returns 统一消息数组\n */\nexport function mapClaudeEvent(\n event: Record<string, unknown>,\n sessionId?: string,\n): AgentMessage[] {\n const timestamp = Date.now();\n // Claude 事件可能携带 session_id,优先使用事件中的值\n const resolvedSessionId = (event.session_id as string | undefined) ?? sessionId;\n const baseFields = { timestamp, sessionId: resolvedSessionId, raw: event };\n\n if (isSystemEvent(event)) {\n return [{\n ...baseFields,\n type: \"system\",\n model: event.model,\n tools: event.tools,\n cwd: event.cwd,\n }];\n }\n\n if (isAssistantEvent(event)) {\n const content = event.message.content;\n return mapAssistantContent(content, baseFields);\n }\n\n // stream_event: Claude CLI 实际极少产生此类事件,但保留处理逻辑以备兼容\n if (isStreamEvent(event)) {\n const delta = event.event.delta;\n if (delta?.type === \"text_delta\" && delta.text) {\n return [{\n ...baseFields,\n type: \"stream_chunk\",\n text: delta.text,\n }];\n }\n return [];\n }\n\n if (isResultEvent(event)) {\n const usage = event.usage as Record<string, number> | undefined;\n return [{\n ...baseFields,\n type: \"result\",\n text: event.result,\n costUsd: event.total_cost_usd ?? event.cost_usd,\n durationMs: event.duration_ms,\n inputTokens: usage?.input_tokens ?? event.input_tokens,\n outputTokens: usage?.output_tokens ?? event.output_tokens,\n }];\n }\n\n // 未知事件类型,忽略\n return [];\n}\n\n/**\n * 将助手消息的内容块拆分为多条 AgentMessage。\n * 每个文本块生成一条 stream_chunk 消息(模拟增量流式),\n * 合并后的完整文本生成一条 assistant 消息,\n * 每个工具调用块生成独立的 tool_use 消息。\n * 这样对外统一表现为增量流式,与 OpenCode 适配器行为一致。\n */\nfunction mapAssistantContent(\n blocks: ClaudeContentBlock[],\n baseFields: { timestamp: number; sessionId?: string; raw: unknown },\n): AgentMessage[] {\n if (!blocks || blocks.length === 0) return [];\n\n const messages: AgentMessage[] = [];\n const textParts: string[] = [];\n\n for (const block of blocks) {\n if (block.type === \"text\" && block.text) {\n textParts.push(block.text);\n // 每个文本块作为 stream_chunk 发出,模拟增量流式\n messages.push({\n ...baseFields,\n type: \"stream_chunk\",\n text: block.text,\n });\n }\n }\n\n // 合并后的完整文本作为 assistant 消息发出(turn 完成标记)\n if (textParts.length > 0) {\n messages.push({\n ...baseFields,\n type: \"assistant\",\n text: textParts.join(\"\\n\"),\n turnComplete: true,\n });\n }\n\n // 每个工具调用块作为独立的 tool_use 消息发出\n for (const block of blocks) {\n if (block.type === \"tool_use\") {\n messages.push({\n ...baseFields,\n type: \"tool_use\",\n toolName: block.name,\n input: block.input,\n });\n }\n // tool_result 块映射为带 output 的 tool_use 消息\n if (block.type === \"tool_result\") {\n messages.push({\n ...baseFields,\n type: \"tool_use\",\n toolName: block.tool_use_id,\n input: {},\n output: block.content,\n });\n }\n }\n\n return messages;\n}\n","import { readFile, writeFile, mkdir } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { EphemeralProcess } from \"@/process/process-handle.js\";\nimport { AbstractAgentAdapter } from \"@/adapters/base.js\";\nimport type { ProcessManager } from \"@/process/process-manager.js\";\nimport type {\n AdapterCapabilities,\n CompatibilityResult,\n SessionInfo,\n SessionListOptions,\n PromptRequest,\n AgentMessage,\n ModelInfo,\n BackendConfig,\n} from \"@/types/index.js\";\nimport { OpenCodeApiClient } from \"./api-client.js\";\nimport { mapOpenCodeEventToMessage } from \"./message-mapper.js\";\n\n/** opencode serve 默认端口 */\nconst DEFAULT_SERVE_PORT = 39393;\n\n/** 等待 serve 进程就绪的最大时长(毫秒) */\nconst SERVE_READY_TIMEOUT_MS = 30_000;\n\n/** 等待 serve 进程就绪的轮询间隔(毫秒) */\nconst SERVE_POLL_INTERVAL_MS = 500;\n\n/** opencode 测试版本范围 */\nconst TESTED_VERSION_RANGE = \">=0.1.0\";\n\n/** 默认最大重启次数 */\nconst MAX_RESTARTS = 3;\n\n/** 默认重启间隔(毫秒) */\nconst RESTART_INTERVAL_MS = 2_000;\n\n/** 健康检查间隔(毫秒) */\nconst HEALTH_CHECK_INTERVAL_MS = 30_000;\n\n/**\n * OpenCode 适配器。\n * 通过 `opencode serve` 启动 HTTP 服务,使用 REST API + SSE 进行交互。\n */\nexport class OpenCodeAdapter extends AbstractAgentAdapter {\n readonly backend = \"opencode\";\n\n private apiClient: OpenCodeApiClient | null = null;\n private servePort: number;\n /** 远程服务器 URL(提供时跳过自启 serve) */\n private remoteServerUrl?: string;\n /** API Key(用于 Basic Auth) */\n private apiKey?: string;\n\n /**\n * @param processManager 进程管理器实例\n * @param config 可选的后端配置\n * - serverUrl: 远程 OpenCode 服务地址,提供时跳过自启 serve\n * - apiKey: API Key,用于 Basic Auth 认证\n * - options.servePort: 本地 serve 端口(仅自启模式)\n */\n constructor(processManager: ProcessManager, config?: BackendConfig) {\n super(processManager, config);\n const opts = config?.options ?? {};\n // 优先从顶级字段读取,向后兼容 options 中的值\n this.remoteServerUrl = config?.serverUrl ?? (opts.serverUrl as string | undefined);\n this.apiKey = config?.apiKey ?? (opts.apiKey as string | undefined);\n this.servePort = (opts.servePort as number) ?? DEFAULT_SERVE_PORT;\n }\n\n /**\n * 检查 opencode 命令是否可用\n */\n async isAvailable(): Promise<boolean> {\n // 远程模式:通过健康检查判断\n if (this.remoteServerUrl) {\n try {\n const client = new OpenCodeApiClient(this.remoteServerUrl, this.apiKey);\n return await client.healthCheck();\n } catch {\n return false;\n }\n }\n // 本地模式:检查命令是否存在\n try {\n const proc = new EphemeralProcess();\n const result = await proc.execute({\n command: \"opencode\",\n args: [\"--version\"],\n timeoutMs: 10_000,\n });\n return result.exitCode === 0;\n } catch {\n return false;\n }\n }\n\n /**\n * 获取 opencode 版本号\n */\n async getVersion(): Promise<string> {\n const proc = new EphemeralProcess();\n const result = await proc.execute({\n command: \"opencode\",\n args: [\"version\"],\n timeoutMs: 10_000,\n });\n\n if (result.exitCode !== 0) {\n throw new Error(`Failed to get opencode version: ${result.stderr}`);\n }\n\n return result.stdout.trim();\n }\n\n /**\n * 获取适配器能力声明\n */\n getCapabilities(): AdapterCapabilities {\n return {\n features: new Set([\n \"streaming\",\n \"session-resume\",\n \"system-prompt\",\n \"serve-mode\",\n ]),\n streamingMode: \"delta\",\n outputFormats: [\"text\"],\n testedVersionRange: TESTED_VERSION_RANGE,\n };\n }\n\n /**\n * 执行查询:启动 serve 进程(如未启动),创建/恢复会话,发送消息并流式返回结果\n * @param request 请求参数\n * @yields AgentMessage 统一消息流\n */\n async *query(request: PromptRequest): AsyncGenerator<AgentMessage> {\n // 确保 serve 进程已启动\n const client = await this.ensureServeRunning();\n\n // 创建或恢复会话\n let sessionId: string;\n if (request.resume) {\n sessionId = request.resume;\n } else {\n const session = await client.createSession(request.cwd);\n sessionId = session.id;\n }\n\n // 复用基类的 AbortController 管理\n const controller = this.createAbortController(sessionId);\n\n try {\n // 发送消息\n await client.sendMessage(sessionId, request.prompt);\n\n // 流式读取事件\n for await (const event of client.streamEvents(\n sessionId,\n controller.signal,\n )) {\n const message = mapOpenCodeEventToMessage(event);\n if (message) {\n yield message;\n }\n }\n } finally {\n this.removeAbortController(sessionId);\n }\n }\n\n /**\n * 列出历史会话\n * @param options 查询选项\n */\n async listSessions(options?: SessionListOptions): Promise<SessionInfo[]> {\n const client = await this.ensureServeRunning();\n const sessions = await client.listSessions();\n\n let filtered = sessions;\n\n if (options?.cwd) {\n filtered = filtered.filter((s) => s.cwd === options.cwd);\n }\n\n if (options?.limit !== undefined && options.limit > 0) {\n filtered = filtered.slice(0, options.limit);\n }\n\n return filtered.map((s) => ({\n sessionId: s.id,\n backend: this.backend,\n summary: s.title,\n lastModified: s.updatedAt,\n cwd: s.cwd,\n }));\n }\n\n /**\n * 获取 OpenCode 可用模型列表(通过 `opencode models` 命令)\n */\n async listModels(): Promise<ModelInfo[]> {\n try {\n const proc = new EphemeralProcess();\n const result = await proc.execute({\n command: \"opencode\",\n args: [\"models\"],\n timeoutMs: 15_000,\n });\n\n if (result.exitCode !== 0) return [];\n\n const lines = result.stdout.trim().split(\"\\n\").filter(Boolean);\n return lines.map((line) => {\n const trimmed = line.trim();\n const slashIndex = trimmed.indexOf(\"/\");\n if (slashIndex >= 0) {\n return {\n id: trimmed,\n name: trimmed.slice(slashIndex + 1),\n provider: trimmed.slice(0, slashIndex),\n };\n }\n return { id: trimmed, name: trimmed };\n });\n } catch {\n return [];\n }\n }\n\n /**\n * 读取 opencode 配置文件\n */\n async getSettings(): Promise<Record<string, unknown>> {\n const configPath = this.getConfigPath();\n try {\n const content = await readFile(configPath, \"utf-8\");\n return JSON.parse(content) as Record<string, unknown>;\n } catch {\n return {};\n }\n }\n\n /**\n * 更新 opencode 配置文件(读取-合并-写入)\n * @param settings 要合并的配置项\n */\n async updateSettings(settings: Record<string, unknown>): Promise<void> {\n const configPath = this.getConfigPath();\n const configDir = join(homedir(), \".config\", \"opencode\");\n\n let existing: Record<string, unknown>;\n try {\n const content = await readFile(configPath, \"utf-8\");\n existing = JSON.parse(content) as Record<string, unknown>;\n } catch {\n existing = {};\n }\n\n const merged = { ...existing, ...settings };\n\n await mkdir(configDir, { recursive: true });\n await writeFile(configPath, JSON.stringify(merged, null, 2), \"utf-8\");\n }\n\n /**\n * 释放资源:停止 serve 进程,中止所有活跃流\n */\n async dispose(): Promise<void> {\n // 中止所有活跃会话(复用基类的 abortControllers)\n for (const [sessionId] of this.abortControllers) {\n this.abort(sessionId);\n }\n\n // 停止持久进程\n const persistent = this.processManager.getPersistent(this.backend);\n if (persistent) {\n await persistent.stop();\n }\n\n this.apiClient = null;\n }\n\n /**\n * 确保 opencode serve 进程已启动并可用\n * @returns 可用的 API 客户端\n */\n private async ensureServeRunning(): Promise<OpenCodeApiClient> {\n if (this.apiClient) {\n const healthy = await this.apiClient.healthCheck();\n if (healthy) return this.apiClient;\n }\n\n // 远程模式:直连远程服务器,不自启 serve\n if (this.remoteServerUrl) {\n const client = new OpenCodeApiClient(this.remoteServerUrl, this.apiKey);\n const healthy = await client.healthCheck();\n if (!healthy) {\n throw new Error(\n `无法连接远程 OpenCode 服务: ${this.remoteServerUrl}`,\n );\n }\n this.apiClient = client;\n return client;\n }\n\n // 本地模式:自启 serve\n const client = new OpenCodeApiClient(\n `http://localhost:${this.servePort}`,\n this.apiKey,\n );\n\n // 检查是否已有 serve 进程在运行\n const alreadyRunning = await client.healthCheck();\n if (alreadyRunning) {\n this.apiClient = client;\n return client;\n }\n\n // 启动 serve 进程\n await this.processManager.startPersistent(this.backend, {\n command: \"opencode\",\n args: [\"serve\", \"--port\", String(this.servePort)],\n maxRestarts: MAX_RESTARTS,\n restartIntervalMs: RESTART_INTERVAL_MS,\n healthCheckIntervalMs: HEALTH_CHECK_INTERVAL_MS,\n healthCheckFn: () => client.healthCheck().then((ok) => {\n if (!ok) throw new Error(\"Health check failed\");\n return ok;\n }),\n });\n\n // 等待 serve 进程就绪\n await this.waitForServeReady(client);\n\n this.apiClient = client;\n return client;\n }\n\n /**\n * 轮询等待 serve 服务可达\n * @param client API 客户端\n */\n private async waitForServeReady(client: OpenCodeApiClient): Promise<void> {\n const deadline = Date.now() + SERVE_READY_TIMEOUT_MS;\n\n while (Date.now() < deadline) {\n const healthy = await client.healthCheck();\n if (healthy) return;\n\n await this.delay(SERVE_POLL_INTERVAL_MS);\n }\n\n throw new Error(\n `opencode serve did not become ready within ${SERVE_READY_TIMEOUT_MS}ms`,\n );\n }\n\n /**\n * 延迟指定毫秒\n * @param ms 毫秒数\n */\n private delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n /**\n * 获取 opencode 配置文件路径\n */\n private getConfigPath(): string {\n return join(homedir(), \".config\", \"opencode\", \"config.json\");\n }\n}\n","/**\n * OpenCode API 会话对象\n */\nexport interface OpenCodeSession {\n id: string;\n title?: string;\n cwd?: string;\n createdAt: number;\n updatedAt: number;\n}\n\n/**\n * 创建会话请求参数\n */\nexport interface CreateSessionRequest {\n cwd?: string;\n}\n\n/**\n * 创建会话响应\n */\nexport interface CreateSessionResponse {\n id: string;\n}\n\n/**\n * 会话列表响应\n */\nexport interface ListSessionsResponse {\n sessions: OpenCodeSession[];\n}\n\n/**\n * 发送消息请求参数\n */\nexport interface SendMessageRequest {\n content: string;\n}\n\n/**\n * SSE 事件类型\n */\nexport type OpenCodeEventType =\n | \"session.created\"\n | \"message.start\"\n | \"message.delta\"\n | \"message.complete\"\n | \"tool_use.start\"\n | \"tool_use.delta\"\n | \"tool_use.complete\"\n | \"error\"\n | \"done\";\n\n/**\n * SSE 事件基础结构\n */\ninterface BaseOpenCodeEvent {\n type: OpenCodeEventType;\n sessionId: string;\n timestamp: number;\n}\n\n/**\n * 会话创建事件\n */\nexport interface SessionCreatedEvent extends BaseOpenCodeEvent {\n type: \"session.created\";\n model?: string;\n tools?: string[];\n cwd?: string;\n}\n\n/**\n * 消息开始事件\n */\nexport interface MessageStartEvent extends BaseOpenCodeEvent {\n type: \"message.start\";\n}\n\n/**\n * 消息增量文本事件\n */\nexport interface MessageDeltaEvent extends BaseOpenCodeEvent {\n type: \"message.delta\";\n text: string;\n}\n\n/**\n * 消息完成事件\n */\nexport interface MessageCompleteEvent extends BaseOpenCodeEvent {\n type: \"message.complete\";\n text: string;\n durationMs?: number;\n costUsd?: number;\n inputTokens?: number;\n outputTokens?: number;\n}\n\n/**\n * 工具调用开始事件\n */\nexport interface ToolUseStartEvent extends BaseOpenCodeEvent {\n type: \"tool_use.start\";\n toolName: string;\n input: Record<string, unknown>;\n}\n\n/**\n * 工具调用增量事件\n */\nexport interface ToolUseDeltaEvent extends BaseOpenCodeEvent {\n type: \"tool_use.delta\";\n toolName: string;\n output: string;\n}\n\n/**\n * 工具调用完成事件\n */\nexport interface ToolUseCompleteEvent extends BaseOpenCodeEvent {\n type: \"tool_use.complete\";\n toolName: string;\n input: Record<string, unknown>;\n output: string;\n}\n\n/**\n * 错误事件\n */\nexport interface ErrorEvent extends BaseOpenCodeEvent {\n type: \"error\";\n message: string;\n code?: string;\n}\n\n/**\n * 完成事件\n */\nexport interface DoneEvent extends BaseOpenCodeEvent {\n type: \"done\";\n}\n\n/**\n * 所有 SSE 事件联合类型\n */\nexport type OpenCodeEvent =\n | SessionCreatedEvent\n | MessageStartEvent\n | MessageDeltaEvent\n | MessageCompleteEvent\n | ToolUseStartEvent\n | ToolUseDeltaEvent\n | ToolUseCompleteEvent\n | ErrorEvent\n | DoneEvent;\n\n/**\n * OpenCode 配置文件结构\n */\nexport interface OpenCodeConfig {\n model?: string;\n provider?: string;\n systemPrompt?: string;\n [key: string]: unknown;\n}\n\n/**\n * API 客户端错误\n */\nexport class OpenCodeApiError extends Error {\n readonly statusCode: number;\n readonly responseBody: string;\n\n constructor(statusCode: number, responseBody: string) {\n super(`OpenCode API error (${statusCode}): ${responseBody}`);\n this.name = \"OpenCodeApiError\";\n this.statusCode = statusCode;\n this.responseBody = responseBody;\n }\n}\n","import type {\n OpenCodeSession,\n OpenCodeEvent,\n CreateSessionResponse,\n ListSessionsResponse,\n OpenCodeApiError as OpenCodeApiErrorType,\n} from \"./types.js\";\nimport { OpenCodeApiError } from \"./types.js\";\n\n/** SSE 重连等待时长(毫秒) */\nconst SSE_RECONNECT_DELAY_MS = 1_000;\n\n/** 默认请求超时时长(毫秒) */\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\n/**\n * OpenCode HTTP API 客户端。\n * 与 `opencode serve` HTTP 服务进行通信。\n */\nexport class OpenCodeApiClient {\n private readonly baseUrl: string;\n private readonly apiKey?: string;\n\n /**\n * @param baseUrl opencode serve 服务的基础 URL,例如 http://localhost:39393\n * @param apiKey 可选的 API Key,用于 Basic Auth 认证(username: opencode, password: apiKey)\n */\n constructor(baseUrl: string, apiKey?: string) {\n // 移除末尾斜杠\n this.baseUrl = baseUrl.replace(/\\/+$/, \"\");\n this.apiKey = apiKey;\n }\n\n /**\n * 创建新会话\n * @param cwd 可选的工作目录\n * @returns 包含会话 ID 的对象\n */\n async createSession(cwd?: string): Promise<CreateSessionResponse> {\n const body: Record<string, unknown> = {};\n if (cwd) {\n body.cwd = cwd;\n }\n\n const response = await this.request<CreateSessionResponse>(\n \"/api/session\",\n {\n method: \"POST\",\n body: JSON.stringify(body),\n },\n );\n return response;\n }\n\n /**\n * 获取所有会话列表\n * @returns 会话数组\n */\n async listSessions(): Promise<OpenCodeSession[]> {\n const response = await this.request<ListSessionsResponse>(\n \"/api/sessions\",\n { method: \"GET\" },\n );\n return response.sessions;\n }\n\n /**\n * 向指定会话发送消息\n * @param sessionId 会话 ID\n * @param content 消息内容\n */\n async sendMessage(sessionId: string, content: string): Promise<void> {\n await this.request<unknown>(\n `/api/session/${encodeURIComponent(sessionId)}/message`,\n {\n method: \"POST\",\n body: JSON.stringify({ content }),\n },\n );\n }\n\n /**\n * 以 SSE 流式方式订阅会话事件\n * @param sessionId 会话 ID\n * @param abortSignal 可选的中止信号\n * @yields OpenCode SSE 事件\n */\n async *streamEvents(\n sessionId: string,\n abortSignal?: AbortSignal,\n ): AsyncGenerator<OpenCodeEvent> {\n const url = `${this.baseUrl}/api/session/${encodeURIComponent(sessionId)}/events`;\n\n const response = await fetch(url, {\n method: \"GET\",\n headers: {\n Accept: \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n ...this.buildAuthHeaders(),\n },\n signal: abortSignal,\n });\n\n if (!response.ok) {\n const body = await response.text().catch(() => \"\");\n throw new OpenCodeApiError(response.status, body);\n }\n\n if (!response.body) {\n throw new Error(\"Response body is null, SSE streaming unavailable\");\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n\n // SSE 协议:事件由双换行分隔\n const parts = buffer.split(\"\\n\\n\");\n // 最后一段可能是不完整的,保留在 buffer 中\n buffer = parts.pop() ?? \"\";\n\n for (const part of parts) {\n const event = this.parseSseEvent(part);\n if (event) {\n yield event;\n // 收到 done 事件则终止流\n if (event.type === \"done\") {\n return;\n }\n }\n }\n }\n\n // 处理 buffer 中可能残留的最后一个事件\n if (buffer.trim()) {\n const event = this.parseSseEvent(buffer);\n if (event) {\n yield event;\n }\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n /**\n * 健康检查:验证 opencode serve 服务是否可达\n * @returns 服务是否健康\n */\n async healthCheck(): Promise<boolean> {\n try {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), 5_000);\n\n const response = await fetch(`${this.baseUrl}/api/sessions`, {\n method: \"GET\",\n headers: this.buildAuthHeaders(),\n signal: controller.signal,\n });\n\n clearTimeout(timer);\n return response.ok;\n } catch {\n return false;\n }\n }\n\n /**\n * 解析单个 SSE 事件文本块\n * @param raw 原始 SSE 文本块\n * @returns 解析后的事件对象,解析失败返回 null\n */\n private parseSseEvent(raw: string): OpenCodeEvent | null {\n const lines = raw.split(\"\\n\");\n let data = \"\";\n\n for (const line of lines) {\n // 忽略注释行\n if (line.startsWith(\":\")) continue;\n\n if (line.startsWith(\"data: \")) {\n data += line.slice(6);\n } else if (line.startsWith(\"data:\")) {\n data += line.slice(5);\n }\n }\n\n if (!data) return null;\n\n try {\n return JSON.parse(data) as OpenCodeEvent;\n } catch {\n return null;\n }\n }\n\n /**\n * 发送 HTTP 请求的通用方法\n * @param path API 路径\n * @param init fetch 请求选项\n * @returns 解析后的 JSON 响应\n */\n /**\n * 构建包含认证信息的请求 headers\n */\n private buildAuthHeaders(): Record<string, string> {\n const headers: Record<string, string> = {};\n if (this.apiKey) {\n const credentials = Buffer.from(`opencode:${this.apiKey}`).toString(\"base64\");\n headers[\"Authorization\"] = `Basic ${credentials}`;\n }\n return headers;\n }\n\n private async request<T>(path: string, init: RequestInit): Promise<T> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), DEFAULT_TIMEOUT_MS);\n\n try {\n const response = await fetch(`${this.baseUrl}${path}`, {\n ...init,\n headers: {\n \"Content-Type\": \"application/json\",\n ...this.buildAuthHeaders(),\n ...init.headers,\n },\n signal: controller.signal,\n });\n\n if (!response.ok) {\n const body = await response.text().catch(() => \"\");\n throw new OpenCodeApiError(response.status, body);\n }\n\n const text = await response.text();\n if (!text) return {} as T;\n return JSON.parse(text) as T;\n } finally {\n clearTimeout(timer);\n }\n }\n}\n","import type { AgentMessage } from \"@/types/index.js\";\nimport type { OpenCodeEvent } from \"./types.js\";\n\n/**\n * 将 OpenCode SSE 事件映射为统一的 AgentMessage 格式\n * @param event OpenCode SSE 事件\n * @returns 对应的 AgentMessage,无法映射时返回 null\n */\nexport function mapOpenCodeEventToMessage(\n event: OpenCodeEvent,\n): AgentMessage | null {\n const base = {\n timestamp: event.timestamp ?? Date.now(),\n sessionId: event.sessionId,\n raw: event,\n };\n\n switch (event.type) {\n case \"session.created\":\n return {\n ...base,\n type: \"system\",\n model: event.model,\n tools: event.tools,\n cwd: event.cwd,\n };\n\n case \"message.delta\":\n return {\n ...base,\n type: \"stream_chunk\",\n text: event.text,\n };\n\n case \"message.complete\":\n return {\n ...base,\n type: \"result\",\n text: event.text,\n durationMs: event.durationMs,\n costUsd: event.costUsd,\n inputTokens: event.inputTokens,\n outputTokens: event.outputTokens,\n };\n\n case \"tool_use.start\":\n return {\n ...base,\n type: \"tool_use\",\n toolName: event.toolName,\n input: event.input,\n };\n\n case \"tool_use.complete\":\n return {\n ...base,\n type: \"tool_use\",\n toolName: event.toolName,\n input: event.input,\n output: event.output,\n };\n\n case \"error\":\n return {\n ...base,\n type: \"error\",\n message: event.message,\n code: event.code,\n };\n\n // message.start / tool_use.delta / done 事件不需要映射为独立消息\n case \"message.start\":\n case \"tool_use.delta\":\n case \"done\":\n return null;\n\n default:\n return null;\n }\n}\n","import type { AgentMessage, PromptRequest } from \"@/types/common.js\";\nimport type { IAgentAdapter } from \"@/types/adapter.js\";\nimport { SessionNotFoundError } from \"@/errors/index.js\";\n\n/**\n * 便捷的多轮对话封装。\n *\n * 底层仍是 per-turn spawn + --resume,但对调用方透明:\n * ```ts\n * const session = porygon.session({ systemPrompt: '...' });\n * for await (const msg of session.send('Hello')) { ... }\n * for await (const msg of session.send('继续')) { ... } // 自动 resume\n * session.close();\n * ```\n */\nexport class InteractiveSession {\n readonly initialSessionId: string;\n private resolvedSessionId?: string;\n private adapter: IAgentAdapter;\n private baseRequest: Omit<PromptRequest, \"prompt\">;\n private firstSent = false;\n private closed = false;\n\n constructor(\n initialSessionId: string,\n adapter: IAgentAdapter,\n baseRequest: Omit<PromptRequest, \"prompt\">,\n ) {\n this.initialSessionId = initialSessionId;\n this.adapter = adapter;\n this.baseRequest = baseRequest;\n }\n\n /** 当前生效的 sessionId(首次 send 后反映 CLI 返回的真实 ID) */\n get sessionId(): string {\n return this.resolvedSessionId ?? this.initialSessionId;\n }\n\n /** 会话是否仍然活跃 */\n get isActive(): boolean {\n return !this.closed;\n }\n\n /**\n * 发送一条消息,返回流式响应。\n * 首次调用使用 initialSessionId,后续自动附加 resume。\n */\n async *send(prompt: string): AsyncGenerator<AgentMessage> {\n if (this.closed) {\n throw new SessionNotFoundError(this.sessionId);\n }\n\n const request: PromptRequest = {\n ...this.baseRequest,\n prompt,\n ...(this.firstSent ? { resume: this.sessionId } : {}),\n };\n\n for await (const msg of this.adapter.query(request)) {\n if (!this.firstSent && msg.sessionId) {\n this.resolvedSessionId = msg.sessionId;\n }\n yield msg;\n }\n this.firstSent = true;\n }\n\n /** 关闭会话(仅清理内部状态,无进程需要释放) */\n close(): void {\n this.closed = true;\n }\n}\n","import type { InterceptorFn, InterceptorContext } from \"./interceptor.js\";\n\n/**\n * 防护拦截器触发时的处理动作\n */\nexport type GuardAction = \"reject\" | \"redact\";\n\n/**\n * 防护拦截器配置选项\n */\nexport interface GuardOptions {\n /**\n * 输入侧:阻止用户通过 prompt 注入攻击套取系统提示词或绕过规则。\n * 匹配到任一模式时触发防护。\n * @example [/忽略.*指令/, /重复.*系统提示/, /ignore.*instructions/i]\n */\n blockedPatterns?: RegExp[];\n\n /**\n * 输出侧:防止模型在回复中泄露系统提示词内容。\n * 提供需要保护的关键词列表,若输出中包含这些关键词则触发防护。\n * @example [\"内部密钥\", \"SECRET_TOKEN\"]\n */\n sensitiveKeywords?: string[];\n\n /**\n * 触发防护时的处理动作:\n * - \"reject\": 拒绝消息,抛出 InterceptorRejectedError(默认)\n * - \"redact\": 替换匹配内容为 [REDACTED],允许消息继续传递\n */\n action?: GuardAction;\n\n /**\n * 自定义判定函数,在内置规则之后执行。\n * 返回 true 表示触发防护,返回 false 或 undefined 表示放行。\n */\n customCheck?: (text: string, context: InterceptorContext) => boolean | undefined;\n\n /**\n * 仅对指定后端生效,不设则对所有后端生效\n */\n backends?: string[];\n}\n\n/** 内置的常见 prompt 注入模式(中英文) */\nconst BUILTIN_INPUT_PATTERNS: RegExp[] = [\n // 中文\n /忽略.{0,10}(之前|上面|以上|所有).{0,10}(指令|规则|提示|约束)/i,\n /重复.{0,10}(系统|完整).{0,10}(提示|指令|prompt)/i,\n /输出.{0,10}(系统|完整).{0,10}(提示|指令|prompt)/i,\n /告诉我.{0,10}(系统|你的).{0,10}(提示|指令|prompt)/i,\n /显示.{0,10}(系统|隐藏|完整).{0,10}(提示|指令|prompt)/i,\n /你的(系统|初始).{0,10}(提示|指令|设定)/i,\n // English\n /ignore.{0,15}(previous|above|all|prior).{0,15}(instructions?|rules?|prompts?|constraints?)/i,\n /repeat.{0,15}(system|full|entire|complete).{0,15}(prompt|instructions?|message)/i,\n /reveal.{0,15}(system|hidden|full).{0,15}(prompt|instructions?)/i,\n /show.{0,15}(system|hidden|full).{0,15}(prompt|instructions?)/i,\n /what.{0,15}(is|are).{0,15}(your|the).{0,15}(system|initial).{0,15}(prompt|instructions?)/i,\n /print.{0,15}(system|full|entire).{0,15}(prompt|instructions?|message)/i,\n /disregard.{0,15}(previous|above|all|prior).{0,15}(instructions?|rules?)/i,\n];\n\n/**\n * 创建输入防护拦截器。\n * 检测并阻止常见的 prompt 注入攻击,防止用户套取系统提示词或绕过规则。\n *\n * @param options 防护配置选项\n * @returns 可注册到 `porygon.use(\"input\", ...)` 的拦截器函数\n *\n * @example\n * ```ts\n * // 使用内置规则\n * porygon.use(\"input\", createInputGuard());\n *\n * // 自定义阻止模式\n * porygon.use(\"input\", createInputGuard({\n * blockedPatterns: [/我是管理员/, /sudo mode/i],\n * action: \"reject\",\n * }));\n * ```\n */\nexport function createInputGuard(options?: GuardOptions): InterceptorFn {\n const patterns = [\n ...BUILTIN_INPUT_PATTERNS,\n ...(options?.blockedPatterns ?? []),\n ];\n const action = options?.action ?? \"reject\";\n const backends = options?.backends;\n\n return (text: string, context: InterceptorContext) => {\n // 后端过滤\n if (backends && !backends.includes(context.backend)) {\n return undefined;\n }\n\n // 模式匹配\n for (const pattern of patterns) {\n if (pattern.test(text)) {\n if (action === \"reject\") {\n return false;\n }\n // redact: 替换匹配内容\n return text.replace(pattern, \"[REDACTED]\");\n }\n }\n\n // 自定义检查\n if (options?.customCheck?.(text, context)) {\n if (action === \"reject\") {\n return false;\n }\n return \"[REDACTED]\";\n }\n\n return undefined;\n };\n}\n\n/**\n * 创建输出防护拦截器。\n * 检测模型输出中是否包含敏感关键词,防止系统提示词内容泄露。\n *\n * @param options 防护配置选项\n * @returns 可注册到 `porygon.use(\"output\", ...)` 的拦截器函数\n *\n * @example\n * ```ts\n * porygon.use(\"output\", createOutputGuard({\n * sensitiveKeywords: [\"内部API密钥\", \"sk-xxxx\"],\n * action: \"redact\",\n * }));\n * ```\n */\nexport function createOutputGuard(options?: GuardOptions): InterceptorFn {\n const keywords = options?.sensitiveKeywords ?? [];\n const action = options?.action ?? \"redact\";\n const backends = options?.backends;\n\n return (text: string, context: InterceptorContext) => {\n // 后端过滤\n if (backends && !backends.includes(context.backend)) {\n return undefined;\n }\n\n // 关键词检测\n let matched = false;\n let result = text;\n\n for (const keyword of keywords) {\n if (text.includes(keyword)) {\n matched = true;\n if (action === \"redact\") {\n // 全局替换所有出现的关键词\n result = result.split(keyword).join(\"[REDACTED]\");\n }\n }\n }\n\n // 自定义检查\n if (!matched && options?.customCheck?.(text, context)) {\n matched = true;\n if (action === \"redact\") {\n result = \"[REDACTED]\";\n }\n }\n\n if (!matched) {\n return undefined;\n }\n\n if (action === \"reject\") {\n return false;\n }\n\n return result;\n };\n}\n"],"mappings":";AAAA,SAAS,gBAAAA,qBAAoB;;;ACEtB,IAAM,iBACK;AAAA,EAChB,gBAAgB;AAAA,EAChB,UAAU,CAAC;AAAA,EACX,UAAU;AAAA,IACR,WAAW;AAAA;AAAA,IACX,UAAU;AAAA,EACZ;AAAA,EACA,OAAO;AACT;;;ACXA,SAAS,SAAS;;;ACGX,IAAM,eAAN,cAA2B,MAAM;AAAA,EAC7B;AAAA,EAET,YAAY,MAAc,SAAiB,SAAwB;AACjE,UAAM,SAAS,OAAO;AACtB,SAAK,OAAO;AACZ,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,uBAAN,cAAmC,aAAa;AAAA,EACrD,YAAY,SAAiB,SAAwB;AACnD,UAAM,qBAAqB,sBAAsB,OAAO,IAAI,OAAO;AACnE,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,2BAAN,cAAuC,aAAa;AAAA,EACzD,YAAY,SAAiB,SAAwB;AACnD,UAAM,yBAAyB,0BAA0B,OAAO,IAAI,OAAO;AAC3E,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,2BAAN,cAAuC,aAAa;AAAA,EACzD,YAAY,SAAiB,SAAiB,SAAwB;AACpE;AAAA,MACE;AAAA,MACA,yBAAyB,OAAO,YAAY,OAAO;AAAA,MACnD;AAAA,IACF;AACA,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,uBAAN,cAAmC,aAAa;AAAA,EACrD,YAAY,WAAmB,SAAwB;AACrD,UAAM,qBAAqB,sBAAsB,SAAS,IAAI,OAAO;AACrE,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,2BAAN,cAAuC,aAAa;AAAA,EACzD,YAAY,QAAgB,SAAwB;AAClD,UAAM,wBAAwB,yBAAyB,MAAM,IAAI,OAAO;AACxE,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,sBAAN,cAAkC,aAAa;AAAA,EACpD,YAAY,SAAiB,SAAwB;AACnD,UAAM,yBAAyB,SAAS,OAAO;AAC/C,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,oBAAN,cAAgC,aAAa;AAAA,EAClD,YAAY,WAAmB,SAAwB;AACrD,UAAM,iBAAiB,yBAAyB,SAAS,MAAM,OAAO;AACtE,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,wBAAN,cAAoC,aAAa;AAAA,EACtD,YAAY,SAAiB,SAAwB;AACnD,UAAM,2BAA2B,SAAS,OAAO;AACjD,SAAK,OAAO;AAAA,EACd;AACF;;;ADhEO,IAAM,oBAAoB,EAAE,OAAO;AAAA,EACxC,KAAK,EAAE,OAAO,EAAE,IAAI;AAAA,EACpB,SAAS,EAAE,OAAO,EAAE,SAAS;AAC/B,CAAC;AAKM,IAAM,sBAAsB,EAAE,OAAO;AAAA,EAC1C,OAAO,EAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,oBAAoB,EAAE,OAAO,EAAE,SAAS;AAAA,EACxC,OAAO,kBAAkB,SAAS;AAAA,EAClC,KAAK,EAAE,OAAO,EAAE,SAAS;AAAA,EACzB,WAAW,EAAE,OAAO,EAAE,SAAS;AAAA,EAC/B,QAAQ,EAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,aAAa,EAAE,QAAQ,EAAE,SAAS;AAAA,EAClC,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,EAC7B,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC,EAAE,SAAS;AACtD,CAAC;AAKM,IAAM,sBAAsB,EAAE,OAAO;AAAA,EAC1C,gBAAgB,EAAE,OAAO,EAAE,SAAS;AAAA,EACpC,UAAU,EAAE,OAAO,EAAE,OAAO,GAAG,mBAAmB,EAAE,SAAS;AAAA,EAC7D,UAAU,EACP,OAAO;AAAA,IACN,oBAAoB,EAAE,OAAO,EAAE,SAAS;AAAA,IACxC,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,IAC1C,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS;AAAA,EACjD,CAAC,EACA,SAAS;AAAA,EACZ,OAAO,kBAAkB,SAAS;AACpC,CAAC;AAQM,SAAS,eAAe,QAAgC;AAC7D,QAAM,SAAS,oBAAoB,UAAU,MAAM;AACnD,MAAI,CAAC,OAAO,SAAS;AACnB,UAAM,SAAS,OAAO,MAAM,OAAO,IAAI,CAAC,WAAW;AAAA,MACjD,MAAM,MAAM,KAAK,KAAK,GAAG;AAAA,MACzB,SAAS,MAAM;AAAA,IACjB,EAAE;AACF,UAAM,IAAI;AAAA,MACR,yCAAW,OAAO,IAAI,CAAC,MAAM,GAAG,EAAE,IAAI,KAAK,EAAE,OAAO,EAAE,EAAE,KAAK,IAAI,CAAC;AAAA,IACpE;AAAA,EACF;AACA,SAAO,OAAO;AAChB;;;AEtDA,SAAS,cAAc,OAAkD;AACvE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAQA,SAAS,UACP,QACA,QACG;AACH,QAAM,SAAS,EAAE,GAAG,OAAO;AAE3B,aAAW,OAAO,OAAO,KAAK,MAAM,GAAG;AACrC,UAAM,YAAY,OAAO,GAA0B;AACnD,UAAM,YAAY,OAAO,GAAG;AAE5B,QAAI,cAAc,QAAW;AAC3B;AAAA,IACF;AAEA,QAAI,cAAc,SAAS,KAAK,cAAc,SAAS,GAAG;AACxD,aAAO,GAAG,IAAI;AAAA,QACZ;AAAA,QACA;AAAA,MACF;AAAA,IACF,OAAO;AACL,aAAO,GAAG,IAAI;AAAA,IAChB;AAAA,EACF;AAEA,SAAO;AACT;AAKA,SAAS,mBAA2C;AAClD,QAAM,SAAiC,CAAC;AAExC,QAAM,iBAAiB,QAAQ,IAAI,yBAAyB;AAC5D,MAAI,gBAAgB;AAClB,WAAO,iBAAiB;AAAA,EAC1B;AAEA,QAAM,WAAW,QAAQ,IAAI,mBAAmB;AAChD,MAAI,UAAU;AACZ,WAAO,QAAQ;AAAA,MACb,KAAK;AAAA,MACL,SAAS,QAAQ,IAAI,wBAAwB;AAAA,IAC/C;AAAA,EACF;AAEA,SAAO;AACT;AAUO,IAAM,eAAN,MAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOxB,OAAO,KAAK,YAAoD;AAE9D,QAAI,SAAkC,EAAE,GAAG,eAAe;AAG1D,UAAM,eAAe,iBAAiB;AACtC,aAAS,UAAU,QAAQ,YAAY;AAGvC,QAAI,YAAY;AACd,eAAS,UAAU,QAAQ,UAAU;AAAA,IACvC;AAGA,WAAO,eAAe,MAAM;AAAA,EAC9B;AACF;;;ACvEO,IAAM,qBAAN,MAAyB;AAAA,EACtB,oBAAqC,CAAC;AAAA,EACtC,qBAAsC,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQ/C,IAAI,WAAiC,IAA+B;AAClE,UAAM,OACJ,cAAc,UAAU,KAAK,oBAAoB,KAAK;AACxD,SAAK,KAAK,EAAE;AAEZ,WAAO,MAAM;AACX,YAAM,MAAM,KAAK,QAAQ,EAAE;AAC3B,UAAI,QAAQ,IAAI;AACd,aAAK,OAAO,KAAK,CAAC;AAAA,MACpB;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,aACJ,MACA,SACiB;AACjB,WAAO,KAAK,YAAY,MAAM,SAAS,SAAS,KAAK,iBAAiB;AAAA,EACxE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,cACJ,MACA,SACiB;AACjB,WAAO,KAAK,YAAY,MAAM,UAAU,SAAS,KAAK,kBAAkB;AAAA,EAC1E;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,YACZ,MACA,WACA,SACA,cACiB;AACjB,UAAM,cAAkC,EAAE,GAAG,SAAS,UAAU;AAChE,QAAI,UAAU;AAEd,eAAW,MAAM,cAAc;AAC7B,YAAM,SAAS,MAAM,GAAG,SAAS,WAAW;AAE5C,UAAI,WAAW,OAAO;AACpB,cAAM,IAAI,yBAAyB,SAAS;AAAA,MAC9C;AAEA,UAAI,OAAO,WAAW,UAAU;AAC9B,kBAAU;AAAA,MACZ;AAAA,IAEF;AAEA,WAAO;AAAA,EACT;AACF;;;ACxGA,SAAS,aAAgC;AACzC,SAAS,oBAAoB;AAC7B,SAAS,uBAAuB;AAQhC,IAAM,kBAAkB;AAMjB,IAAM,mBAAN,MAAuB;AAAA,EACpB,eAAoC;AAAA,EACpC,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQlB,MAAM,QACJ,SACA,aACwB;AACxB,WAAO,IAAI,QAAuB,CAAC,SAAS,WAAW;AACrD,UAAI,aAAa,SAAS;AACxB,eAAO,IAAI,MAAM,8BAA8B,CAAC;AAChD;AAAA,MACF;AAEA,WAAK,UAAU;AACf,YAAM,QAAQ,MAAM,QAAQ,SAAS,QAAQ,MAAM;AAAA,QACjD,KAAK,QAAQ;AAAA,QACb,KAAK,QAAQ,MAAM,EAAE,GAAG,QAAQ,KAAK,GAAG,QAAQ,IAAI,IAAI;AAAA,QACxD,OAAO,CAAC,QAAQ,QAAQ,MAAM;AAAA,MAChC,CAAC;AACD,WAAK,eAAe;AAEpB,YAAM,eAAyB,CAAC;AAChC,YAAM,eAAyB,CAAC;AAEhC,YAAM,QAAQ,GAAG,QAAQ,CAAC,UAAkB;AAC1C,qBAAa,KAAK,KAAK;AAAA,MACzB,CAAC;AAED,YAAM,QAAQ,GAAG,QAAQ,CAAC,UAAkB;AAC1C,qBAAa,KAAK,KAAK;AAAA,MACzB,CAAC;AAED,UAAI;AACJ,UAAI,QAAQ,cAAc,UAAa,QAAQ,YAAY,GAAG;AAC5D,uBAAe,WAAW,MAAM;AAC9B,eAAK,UAAU;AACf,iBAAO,IAAI,MAAM,2BAA2B,QAAQ,SAAS,IAAI,CAAC;AAAA,QACpE,GAAG,QAAQ,SAAS;AAAA,MACtB;AAEA,YAAM,UAAU,MAAY;AAC1B,aAAK,UAAU;AACf,eAAO,IAAI,MAAM,iBAAiB,CAAC;AAAA,MACrC;AACA,mBAAa,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;AAE9D,YAAM,GAAG,SAAS,CAAC,QAAe;AAChC,YAAI,aAAc,cAAa,YAAY;AAC3C,qBAAa,oBAAoB,SAAS,OAAO;AACjD,aAAK,eAAe;AACpB,eAAO,GAAG;AAAA,MACZ,CAAC;AAED,YAAM,GAAG,SAAS,CAAC,MAAqB,WAAkC;AACxE,YAAI,aAAc,cAAa,YAAY;AAC3C,qBAAa,oBAAoB,SAAS,OAAO;AACjD,aAAK,eAAe;AACpB,gBAAQ;AAAA,UACN,UAAU;AAAA,UACV;AAAA,UACA,QAAQ,OAAO,OAAO,YAAY,EAAE,SAAS,OAAO;AAAA,UACpD,QAAQ,OAAO,OAAO,YAAY,EAAE,SAAS,OAAO;AAAA,QACtD,CAAC;AAAA,MACH,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,OAAO,iBACL,SACA,aACwB;AACxB,QAAI,aAAa,SAAS;AACxB,YAAM,IAAI,MAAM,8BAA8B;AAAA,IAChD;AAEA,SAAK,UAAU;AACf,UAAM,WAAW,QAAQ,cAAc;AACvC,UAAM,QAAQ,MAAM,QAAQ,SAAS,QAAQ,MAAM;AAAA,MACjD,KAAK,QAAQ;AAAA,MACb,KAAK,QAAQ,OAAO;AAAA,MACpB,OAAO,CAAC,WAAW,SAAS,UAAU,QAAQ,MAAM;AAAA,IACtD,CAAC;AACD,SAAK,eAAe;AAGpB,QAAI,YAAY,MAAM,OAAO;AAC3B,YAAM,MAAM,MAAM,QAAQ,WAAW,MAAM;AACzC,cAAM,MAAO,IAAI;AAAA,MACnB,CAAC;AAAA,IACH;AAEA,QAAI;AACJ,QAAI,QAAQ,cAAc,UAAa,QAAQ,YAAY,GAAG;AAC5D,qBAAe,WAAW,MAAM;AAC9B,aAAK,UAAU;AAAA,MACjB,GAAG,QAAQ,SAAS;AAAA,IACtB;AAEA,UAAM,UAAU,MAAY;AAC1B,WAAK,UAAU;AAAA,IACjB;AACA,iBAAa,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;AAG9D,UAAM,eAAyB,CAAC;AAChC,UAAM,QAAQ,GAAG,QAAQ,CAAC,UAAkB;AAC1C,mBAAa,KAAK,KAAK;AAAA,IACzB,CAAC;AAGD,QAAI,WAA0B;AAC9B,UAAM,cAAc,IAAI,QAAc,CAAC,YAAY;AACjD,YAAM,GAAG,SAAS,CAAC,SAAS;AAC1B,mBAAW;AACX,gBAAQ;AAAA,MACV,CAAC;AAAA,IACH,CAAC;AAGD,UAAM,KAAK,gBAAgB,EAAE,OAAO,MAAM,OAAQ,CAAC;AACnD,QAAI,eAAe;AAEnB,QAAI;AACF,uBAAiB,QAAQ,IAAI;AAC3B;AACA,cAAM;AAAA,MACR;AAGA,YAAM;AAGN,UAAI,aAAa,KAAK,iBAAiB,KAAK,CAAC,KAAK,SAAS;AACzD,cAAM,SAAS,OAAO,OAAO,YAAY,EAAE,SAAS,OAAO,EAAE,KAAK;AAClE,cAAM,IAAI;AAAA,UACR,UAAU,4BAA4B,QAAQ;AAAA,QAChD;AAAA,MACF;AAAA,IACF,UAAE;AACA,UAAI,aAAc,cAAa,YAAY;AAC3C,mBAAa,oBAAoB,SAAS,OAAO;AACjD,SAAG,MAAM;AACT,WAAK,eAAe;AAAA,IACtB;AAAA,EACF;AAAA;AAAA,EAGA,IAAI,MAA0B;AAC5B,WAAO,KAAK,cAAc;AAAA,EAC5B;AAAA;AAAA,EAGA,YAAkB;AAChB,QAAI,CAAC,KAAK,gBAAgB,KAAK,QAAS;AACxC,SAAK,UAAU;AACf,SAAK,aAAa,KAAK,SAAS;AAChC,UAAM,MAAM,KAAK;AACjB,eAAW,MAAM;AACf,UAAI,CAAC,IAAI,QAAQ;AACf,YAAI,KAAK,SAAS;AAAA,MACpB;AAAA,IACF,GAAG,eAAe;AAAA,EACpB;AACF;AAMO,IAAM,oBAAN,cAAgC,aAAa;AAAA,EAC1C,UAA+B;AAAA,EAC/B,eAAe;AAAA,EACf,UAAU;AAAA,EACV,mBAA0D;AAAA,EACjD;AAAA,EAEjB,YAAY,SAAmC;AAC7C,UAAM;AACN,SAAK,UAAU;AAAA,EACjB;AAAA;AAAA,EAGA,MAAM,QAAuB;AAC3B,SAAK,UAAU;AAEf,UAAM,QAAQ,MAAM,KAAK,QAAQ,SAAS,KAAK,QAAQ,MAAM;AAAA,MAC3D,KAAK,KAAK,QAAQ;AAAA,MAClB,KAAK,KAAK,QAAQ,MACd,EAAE,GAAG,QAAQ,KAAK,GAAG,KAAK,QAAQ,IAAI,IACtC;AAAA,MACJ,OAAO,CAAC,QAAQ,QAAQ,MAAM;AAAA,IAChC,CAAC;AACD,SAAK,UAAU;AAEf,UAAM,GAAG,SAAS,CAAC,QAAe;AAChC,WAAK,KAAK,SAAS,GAAG;AAAA,IACxB,CAAC;AAED,UAAM,GAAG,QAAQ,CAAC,SAAwB;AACxC,WAAK,UAAU;AACf,WAAK,gBAAgB;AACrB,WAAK,YAAY,IAAI;AAAA,IACvB,CAAC;AAGD,QAAI,KAAK,QAAQ,iBAAiB,KAAK,QAAQ,wBAAwB,GAAG;AACxE,WAAK,mBAAmB,YAAY,MAAM;AACxC,aAAK,QAAQ,cAAe,EAAE,MAAM,CAAC,QAAiB;AACpD,eAAK,KAAK,qBAAqB,GAAG;AAAA,QACpC,CAAC;AAAA,MACH,GAAG,KAAK,QAAQ,qBAAqB;AAAA,IACvC;AAEA,SAAK,KAAK,WAAW,MAAM,GAAG;AAAA,EAChC;AAAA;AAAA,EAGQ,YAAY,MAA2B;AAC7C,QAAI,KAAK,QAAS;AAElB,SAAK,KAAK,QAAQ,IAAI;AAEtB,QAAI,KAAK,eAAe,KAAK,QAAQ,aAAa;AAChD,YAAM,QACJ,KAAK,QAAQ,oBAAoB,KAAK,IAAI,GAAG,KAAK,YAAY;AAChE,WAAK;AACL,WAAK,KAAK,WAAW,KAAK,YAAY;AAEtC,iBAAW,MAAM;AACf,YAAI,CAAC,KAAK,SAAS;AACjB,eAAK,MAAM,EAAE,MAAM,CAAC,QAAiB;AACnC,iBAAK,KAAK,SAAS,GAAG;AAAA,UACxB,CAAC;AAAA,QACH;AAAA,MACF,GAAG,KAAK;AAAA,IACV,OAAO;AACL,WAAK;AAAA,QACH;AAAA,QACA,IAAI;AAAA,UACF,iBAAiB,KAAK,QAAQ,WAAW,+BAA+B,IAAI;AAAA,QAC9E;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGQ,kBAAwB;AAC9B,QAAI,KAAK,kBAAkB;AACzB,oBAAc,KAAK,gBAAgB;AACnC,WAAK,mBAAmB;AAAA,IAC1B;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,OAAsB;AAC1B,SAAK,UAAU;AACf,SAAK,gBAAgB;AAErB,QAAI,KAAK,SAAS;AAChB,YAAM,QAAQ,KAAK;AACnB,YAAM,KAAK,SAAS;AAEpB,YAAM,IAAI,QAAc,CAAC,YAAY;AACnC,cAAM,QAAQ,WAAW,MAAM;AAC7B,cAAI,CAAC,MAAM,QAAQ;AACjB,kBAAM,KAAK,SAAS;AAAA,UACtB;AACA,kBAAQ;AAAA,QACV,GAAG,eAAe;AAElB,cAAM,GAAG,QAAQ,MAAM;AACrB,uBAAa,KAAK;AAClB,kBAAQ;AAAA,QACV,CAAC;AAAA,MACH,CAAC;AAED,WAAK,UAAU;AAAA,IACjB;AAAA,EACF;AAAA;AAAA,EAGA,IAAI,MAA0B;AAC5B,WAAO,KAAK,SAAS;AAAA,EACvB;AAAA;AAAA,EAGA,IAAI,YAAqB;AACvB,WAAO,KAAK,YAAY,QAAQ,CAAC,KAAK,QAAQ;AAAA,EAChD;AACF;;;ACtTO,IAAM,iBAAN,MAAM,gBAAe;AAAA,EACT,YAAY,oBAAI,IAA8B;AAAA,EAC9C,aAAa,oBAAI,IAA+B;AAAA;AAAA,EAGjE,OAAe,oBAAoB;AAAA;AAAA,EAEnC,OAAwB,YAAY,oBAAI,IAAoB;AAAA,EAE5D,cAAc;AACZ,oBAAe,UAAU,IAAI,IAAI;AACjC,oBAAe,gBAAgB;AAAA,EACjC;AAAA;AAAA,EAGA,OAAe,kBAAwB;AACrC,QAAI,gBAAe,kBAAmB;AACtC,oBAAe,oBAAoB;AAEnC,UAAM,UAAU,MAAY;AAC1B,iBAAW,YAAY,gBAAe,WAAW;AAC/C,iBAAS,iBAAiB;AAAA,MAC5B;AAAA,IACF;AAEA,YAAQ,GAAG,QAAQ,OAAO;AAI1B,YAAQ,GAAG,WAAW,OAAO;AAC7B,YAAQ,GAAG,UAAU,OAAO;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,gBAAgB,WAAqC;AACnD,UAAM,OAAO,IAAI,iBAAiB;AAClC,SAAK,UAAU,IAAI,WAAW,IAAI;AAClC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,gBAAgB,WAAyB;AACvC,SAAK,UAAU,OAAO,SAAS;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,gBACJ,SACA,SAC4B;AAC5B,UAAM,WAAW,KAAK,WAAW,IAAI,OAAO;AAC5C,QAAI,UAAU,UAAW,QAAO;AAEhC,UAAM,OAAO,IAAI,kBAAkB,OAAO;AAC1C,SAAK,WAAW,IAAI,SAAS,IAAI;AACjC,UAAM,KAAK,MAAM;AACjB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,cAAc,SAAgD;AAC5D,WAAO,KAAK,WAAW,IAAI,OAAO;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAa,WAAiD;AAC5D,WAAO,KAAK,UAAU,IAAI,SAAS;AAAA,EACrC;AAAA;AAAA,EAGA,MAAM,eAA8B;AAClC,UAAM,WAA4B,CAAC;AAEnC,eAAW,CAAC,EAAE,IAAI,KAAK,KAAK,WAAW;AACrC,WAAK,UAAU;AAAA,IACjB;AAEA,eAAW,CAAC,EAAE,IAAI,KAAK,KAAK,YAAY;AACtC,eAAS,KAAK,KAAK,KAAK,CAAC;AAAA,IAC3B;AAEA,SAAK,UAAU,MAAM;AACrB,UAAM,QAAQ,WAAW,QAAQ;AACjC,SAAK,WAAW,MAAM;AAAA,EACxB;AAAA;AAAA,EAGQ,mBAAyB;AAC/B,eAAW,CAAC,EAAE,IAAI,KAAK,KAAK,WAAW;AACrC,WAAK,UAAU;AAAA,IACjB;AAEA,eAAW,CAAC,EAAE,IAAI,KAAK,KAAK,YAAY;AACtC,YAAM,MAAM,KAAK;AACjB,UAAI,KAAK;AACP,YAAI;AACF,kBAAQ,KAAK,KAAK,SAAS;AAAA,QAC7B,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,UAAgB;AACd,oBAAe,UAAU,OAAO,IAAI;AAAA,EACtC;AACF;;;AC/HO,IAAM,iBAAN,MAAqB;AAAA,EAClB,QAAQ,oBAAI,IAAyB;AAAA,EACrC,WAAW,oBAAI,IAA2B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOlD,gBAAgB,SAAiB,SAA8B;AAC7D,SAAK,SAAS,IAAI,SAAS,OAAO;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,kBAAkB,SAAuB;AACvC,SAAK,SAAS,OAAO,OAAO;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,WAAW,SAAgC;AACjD,UAAM,UAAU,KAAK,SAAS,IAAI,OAAO;AACzC,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,qBAAqB,OAAO;AAAA,IACxC;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,KAAK,SAAiB,SAAsD;AAChF,UAAM,UAAU,KAAK,WAAW,OAAO;AACvC,UAAM,WAAW,MAAM,QAAQ,aAAa,OAAO;AACnD,eAAW,WAAW,UAAU;AAC9B,WAAK,MAAM,IAAI,QAAQ,WAAW,OAAO;AAAA,IAC3C;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAI,WAA4C;AAC9C,WAAO,KAAK,MAAM,IAAI,SAAS;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,OACL,SACA,WACA,QAC8B;AAC9B,UAAM,UAAU,KAAK,WAAW,OAAO;AACvC,WAAO,QAAQ,MAAM,EAAE,QAAQ,QAAQ,UAAU,CAAC;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,WAAyB;AAC7B,SAAK,MAAM,OAAO,SAAS;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA,EAKA,aAAmB;AACjB,SAAK,MAAM,MAAM;AAAA,EACnB;AACF;;;AC5FA,SAAS,UAAU,iBAAiB;AACpC,SAAS,eAAe;AACxB,SAAS,YAAY;AACrB,SAAS,kBAAkB;;;ACgB3B,SAAS,eAAe,SAAiB,OAAwB;AAC/D,QAAM,eAAe,CAAC,MAA+C;AACnE,UAAM,QAAQ,yBAAyB,KAAK,EAAE,KAAK,CAAC;AACpD,QAAI,CAAC,MAAO,QAAO;AACnB,WAAO,CAAC,OAAO,MAAM,CAAC,CAAC,GAAG,OAAO,MAAM,CAAC,CAAC,GAAG,OAAO,MAAM,CAAC,CAAC,CAAC;AAAA,EAC9D;AAEA,QAAM,UAAU,MAAM,KAAK;AAG3B,MAAI,QAAQ,WAAW,IAAI,GAAG;AAC5B,UAAMC,gBAAe,aAAa,QAAQ,MAAM,CAAC,CAAC;AAClD,UAAMC,kBAAiB,aAAa,OAAO;AAC3C,QAAI,CAACD,iBAAgB,CAACC,gBAAgB,QAAO;AAE7C,aAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,UAAIA,gBAAe,CAAC,IAAID,cAAa,CAAC,EAAG,QAAO;AAChD,UAAIC,gBAAe,CAAC,IAAID,cAAa,CAAC,EAAG,QAAO;AAAA,IAClD;AACA,WAAO;AAAA,EACT;AAGA,MAAI,QAAQ,WAAW,IAAI,GAAG;AAC5B,UAAMA,gBAAe,aAAa,QAAQ,MAAM,CAAC,CAAC;AAClD,UAAMC,kBAAiB,aAAa,OAAO;AAC3C,QAAI,CAACD,iBAAgB,CAACC,gBAAgB,QAAO;AAE7C,aAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,UAAIA,gBAAe,CAAC,IAAID,cAAa,CAAC,EAAG,QAAO;AAChD,UAAIC,gBAAe,CAAC,IAAID,cAAa,CAAC,EAAG,QAAO;AAAA,IAClD;AACA,WAAO;AAAA,EACT;AAGA,QAAM,eAAe,aAAa,OAAO;AACzC,QAAM,iBAAiB,aAAa,OAAO;AAC3C,MAAI,CAAC,gBAAgB,CAAC,eAAgB,QAAO;AAC7C,SACE,eAAe,CAAC,MAAM,aAAa,CAAC,KACpC,eAAe,CAAC,MAAM,aAAa,CAAC,KACpC,eAAe,CAAC,MAAM,aAAa,CAAC;AAExC;AAMO,IAAe,uBAAf,MAA6D;AAAA;AAAA,EAI/C,mBAAmB,oBAAI,IAA6B;AAAA,EAEpD;AAAA,EACA;AAAA,EAEnB,YAAY,gBAAgC,QAAwB;AAClE,SAAK,iBAAiB;AACtB,SAAK,SAAS;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,qBAAmD;AACvD,UAAM,WAAqB,CAAC;AAE5B,QAAI;AACJ,QAAI;AACF,gBAAU,MAAM,KAAK,WAAW;AAAA,IAClC,QAAQ;AACN,aAAO;AAAA,QACL,SAAS;AAAA,QACT,WAAW;AAAA,QACX,UAAU,CAAC,4BAAQ,KAAK,OAAO,2BAAO;AAAA,MACxC;AAAA,IACF;AAEA,UAAM,eAAe,KAAK,gBAAgB;AAC1C,UAAM,YAAY,eAAe,SAAS,aAAa,kBAAkB;AAEzE,QAAI,CAAC,WAAW;AACd,eAAS;AAAA,QACP,GAAG,KAAK,OAAO,iBAAO,OAAO,yCAAW,aAAa,kBAAkB;AAAA,MACzE;AAAA,IACF;AAEA,WAAO,EAAE,SAAS,WAAW,SAAS;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,WAAyB;AAC7B,UAAM,aAAa,KAAK,iBAAiB,IAAI,SAAS;AACtD,QAAI,YAAY;AACd,iBAAW,MAAM;AACjB,WAAK,iBAAiB,OAAO,SAAS;AAAA,IACxC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOU,sBAAsB,WAAoC;AAElE,UAAM,WAAW,KAAK,iBAAiB,IAAI,SAAS;AACpD,QAAI,UAAU;AACZ,eAAS,MAAM;AAAA,IACjB;AACA,UAAM,aAAa,IAAI,gBAAgB;AACvC,SAAK,iBAAiB,IAAI,WAAW,UAAU;AAC/C,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMU,sBAAsB,WAAyB;AACvD,SAAK,iBAAiB,OAAO,SAAS;AAAA,EACxC;AAWF;;;ACtDO,SAAS,cAAc,OAA4C;AACxE,MAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;AACxD,SAAQ,MAAkC,MAAM,MAAM;AACxD;AAKO,SAAS,iBAAiB,OAA+C;AAC9E,MAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;AACxD,QAAM,MAAM;AACZ,SAAO,IAAI,MAAM,MAAM,eAAe,OAAO,IAAI,SAAS,MAAM,YAAY,IAAI,SAAS,MAAM;AACjG;AAKO,SAAS,cAAc,OAAmD;AAC/E,MAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;AACxD,QAAM,MAAM;AACZ,SAAO,IAAI,MAAM,MAAM,kBAAkB,OAAO,IAAI,OAAO,MAAM,YAAY,IAAI,OAAO,MAAM;AAChG;AAKO,SAAS,cAAc,OAA4C;AACxE,MAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;AACxD,QAAM,MAAM;AACZ,SAAO,IAAI,MAAM,MAAM,YAAY,YAAY;AACjD;;;ACjHO,SAAS,eACd,OACA,WACgB;AAChB,QAAM,YAAY,KAAK,IAAI;AAE3B,QAAM,oBAAqB,MAAM,cAAqC;AACtE,QAAM,aAAa,EAAE,WAAW,WAAW,mBAAmB,KAAK,MAAM;AAEzE,MAAI,cAAc,KAAK,GAAG;AACxB,WAAO,CAAC;AAAA,MACN,GAAG;AAAA,MACH,MAAM;AAAA,MACN,OAAO,MAAM;AAAA,MACb,OAAO,MAAM;AAAA,MACb,KAAK,MAAM;AAAA,IACb,CAAC;AAAA,EACH;AAEA,MAAI,iBAAiB,KAAK,GAAG;AAC3B,UAAM,UAAU,MAAM,QAAQ;AAC9B,WAAO,oBAAoB,SAAS,UAAU;AAAA,EAChD;AAGA,MAAI,cAAc,KAAK,GAAG;AACxB,UAAM,QAAQ,MAAM,MAAM;AAC1B,QAAI,OAAO,SAAS,gBAAgB,MAAM,MAAM;AAC9C,aAAO,CAAC;AAAA,QACN,GAAG;AAAA,QACH,MAAM;AAAA,QACN,MAAM,MAAM;AAAA,MACd,CAAC;AAAA,IACH;AACA,WAAO,CAAC;AAAA,EACV;AAEA,MAAI,cAAc,KAAK,GAAG;AACxB,UAAM,QAAQ,MAAM;AACpB,WAAO,CAAC;AAAA,MACN,GAAG;AAAA,MACH,MAAM;AAAA,MACN,MAAM,MAAM;AAAA,MACZ,SAAS,MAAM,kBAAkB,MAAM;AAAA,MACvC,YAAY,MAAM;AAAA,MAClB,aAAa,OAAO,gBAAgB,MAAM;AAAA,MAC1C,cAAc,OAAO,iBAAiB,MAAM;AAAA,IAC9C,CAAC;AAAA,EACH;AAGA,SAAO,CAAC;AACV;AASA,SAAS,oBACP,QACA,YACgB;AAChB,MAAI,CAAC,UAAU,OAAO,WAAW,EAAG,QAAO,CAAC;AAE5C,QAAM,WAA2B,CAAC;AAClC,QAAM,YAAsB,CAAC;AAE7B,aAAW,SAAS,QAAQ;AAC1B,QAAI,MAAM,SAAS,UAAU,MAAM,MAAM;AACvC,gBAAU,KAAK,MAAM,IAAI;AAEzB,eAAS,KAAK;AAAA,QACZ,GAAG;AAAA,QACH,MAAM;AAAA,QACN,MAAM,MAAM;AAAA,MACd,CAAC;AAAA,IACH;AAAA,EACF;AAGA,MAAI,UAAU,SAAS,GAAG;AACxB,aAAS,KAAK;AAAA,MACZ,GAAG;AAAA,MACH,MAAM;AAAA,MACN,MAAM,UAAU,KAAK,IAAI;AAAA,MACzB,cAAc;AAAA,IAChB,CAAC;AAAA,EACH;AAGA,aAAW,SAAS,QAAQ;AAC1B,QAAI,MAAM,SAAS,YAAY;AAC7B,eAAS,KAAK;AAAA,QACZ,GAAG;AAAA,QACH,MAAM;AAAA,QACN,UAAU,MAAM;AAAA,QAChB,OAAO,MAAM;AAAA,MACf,CAAC;AAAA,IACH;AAEA,QAAI,MAAM,SAAS,eAAe;AAChC,eAAS,KAAK;AAAA,QACZ,GAAG;AAAA,QACH,MAAM;AAAA,QACN,UAAU,MAAM;AAAA,QAChB,OAAO,CAAC;AAAA,QACR,QAAQ,MAAM;AAAA,MAChB,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AACT;;;AHtHA,IAAM,uBAAuB,KAAK,QAAQ,GAAG,WAAW,eAAe;AAGvE,IAAM,gBAA6B;AAAA,EACjC,EAAE,IAAI,UAAU,MAAM,UAAU,UAAU,YAAY;AAAA,EACtD,EAAE,IAAI,QAAQ,MAAM,QAAQ,UAAU,YAAY;AAAA,EAClD,EAAE,IAAI,SAAS,MAAM,SAAS,UAAU,YAAY;AACtD;AAMO,IAAM,gBAAN,cAA4B,qBAAqB;AAAA,EAC7C,UAAU;AAAA;AAAA,EAGnB,IAAY,aAAqB;AAC/B,WAAO,KAAK,QAAQ,WAAW;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,cAAgC;AACpC,QAAI;AACF,YAAM,OAAO,IAAI,iBAAiB;AAClC,YAAM,SAAS,MAAM,KAAK,QAAQ;AAAA,QAChC,SAAS;AAAA,QACT,MAAM,CAAC,KAAK,UAAU;AAAA,MACxB,CAAC;AACD,aAAO,OAAO,aAAa;AAAA,IAC7B,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAA8B;AAClC,UAAM,OAAO,IAAI,iBAAiB;AAClC,UAAM,SAAS,MAAM,KAAK,QAAQ;AAAA,MAChC,SAAS,KAAK;AAAA,MACd,MAAM,CAAC,WAAW;AAAA,IACpB,CAAC;AAED,QAAI,OAAO,aAAa,GAAG;AACzB,YAAM,IAAI,MAAM,iDAAmB,OAAO,MAAM,EAAE;AAAA,IACpD;AAGA,UAAM,SAAS,OAAO,OAAO,KAAK;AAClC,UAAM,QAAQ,kBAAkB,KAAK,MAAM;AAC3C,QAAI,CAAC,OAAO;AACV,YAAM,IAAI,MAAM,uDAAoB,MAAM,EAAE;AAAA,IAC9C;AAEA,WAAO,MAAM,CAAC;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKA,kBAAuC;AACrC,WAAO;AAAA,MACL,UAAU,oBAAI,IAAI;AAAA,QAChB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAAA,MACD,eAAe;AAAA,MACf,eAAe,CAAC,QAAQ,QAAQ,aAAa;AAAA,MAC7C,oBAAoB;AAAA,IACtB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO,MAAM,SAAsD;AACjE,UAAM,YAAY,QAAQ,UAAU,WAAW;AAC/C,UAAM,aAAa,KAAK,sBAAsB,SAAS;AACvD,UAAM,OAAO,KAAK,eAAe,gBAAgB,SAAS;AAE1D,QAAI;AACF,YAAM,OAAO,KAAK,UAAU,OAAO;AACnC,YAAM,MAAM,QAAQ,OAAO,KAAK,QAAQ;AAGxC,YAAM,WAAmC,CAAC;AAC1C,iBAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,QAAQ,GAAG,GAAG;AAChD,YAAI,MAAM,gBAAgB,MAAM,QAAW;AACzC,mBAAS,CAAC,IAAI;AAAA,QAChB;AAAA,MACF;AAGA,YAAM,WAAW,KAAK,QAAQ,OAAO;AACrC,UAAI,UAAU;AACZ,aAAK,cAAc,UAAU,UAAU,KAAK,QAAQ,OAAO,OAAO;AAAA,MACpE;AAGA,UAAI,QAAQ,SAAS;AACnB,mBAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,QAAQ,OAAO,GAAG;AACpD,cAAI,EAAG,UAAS,CAAC,IAAI;AAAA,QACvB;AAAA,MACF;AAGA,YAAM,YAAY,KAAK,eAAe,OAAO;AAE7C,YAAM,gBAAgB;AAAA,QACpB,SAAS,KAAK;AAAA,QACd;AAAA,QACA,GAAI,MAAM,EAAE,IAAI,IAAI,CAAC;AAAA,QACrB,KAAK;AAAA,QACL,WAAW,QAAQ;AAAA,QACnB;AAAA,MACF;AAGA,YAAM,SAAS,CAAC,KAAK,YAAY,GAAG,KAAK,IAAI,OAAK,SAAS,KAAK,CAAC,IAAI,KAAK,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,GAAG;AACrG,YAAM,WAAW,MAAM,MAAM,KAAK,UAAU,GAAG,CAAC,OAAO,MAAM,KAAK;AAGlE,YAAM;AAAA,QACJ,MAAM;AAAA,QACN,WAAW,KAAK,IAAI;AAAA,QACpB;AAAA,QACA;AAAA,QACA,KAAK,EAAE,eAAe,SAAS;AAAA,MACjC;AAEA,uBAAiB,QAAQ,KAAK;AAAA,QAC5B;AAAA,QACA,WAAW;AAAA,MACb,GAAG;AACD,cAAM,UAAU,KAAK,KAAK;AAC1B,YAAI,CAAC,QAAS;AAEd,YAAI;AACJ,YAAI;AACF,mBAAS,KAAK,MAAM,OAAO;AAAA,QAC7B,QAAQ;AAGN;AAAA,QACF;AAEA,cAAM,WAAW,eAAe,QAAQ,SAAS;AACjD,mBAAW,WAAW,UAAU;AAC9B,gBAAM;AAAA,QACR;AAAA,MACF;AAAA,IACF,UAAE;AACA,WAAK,sBAAsB,SAAS;AACpC,WAAK,eAAe,gBAAgB,SAAS;AAAA,IAC/C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,aAAa,SAAsD;AACvE,UAAM,OAAO,IAAI,iBAAiB;AAClC,UAAM,OAAO,CAAC,YAAY,QAAQ,YAAY,MAAM;AAEpD,QAAI,SAAS,OAAO;AAClB,WAAK,KAAK,WAAW,OAAO,QAAQ,KAAK,CAAC;AAAA,IAC5C;AAEA,UAAM,SAAS,MAAM,KAAK,QAAQ;AAAA,MAChC,SAAS,KAAK;AAAA,MACd;AAAA,MACA,KAAK,SAAS;AAAA,IAChB,CAAC;AAED,QAAI,OAAO,aAAa,GAAG;AACzB,YAAM,IAAI,MAAM,6DAAqB,OAAO,MAAM,EAAE;AAAA,IACtD;AAEA,UAAM,SAAS,OAAO,OAAO,KAAK;AAClC,QAAI,CAAC,OAAQ,QAAO,CAAC;AAErB,QAAI;AACJ,QAAI;AACF,oBAAc,KAAK,MAAM,MAAM;AAAA,IACjC,QAAQ;AACN,YAAM,IAAI,MAAM,6DAAqB,OAAO,MAAM,GAAG,GAAG,CAAC,EAAE;AAAA,IAC7D;AAEA,QAAI,CAAC,MAAM,QAAQ,WAAW,EAAG,QAAO,CAAC;AAEzC,WAAO,YAAY,IAAI,CAAC,YAAqB;AAC3C,YAAM,IAAI;AACV,aAAO;AAAA,QACL,WAAW,OAAO,EAAE,IAAI,KAAK,EAAE,YAAY,KAAK,EAAE;AAAA,QAClD,SAAS,KAAK;AAAA,QACd,SAAS,OAAO,EAAE,SAAS,MAAM,WAAW,EAAE,SAAS,IAAI;AAAA,QAC3D,cACE,OAAO,EAAE,eAAe,MAAM,WAC1B,EAAE,eAAe,IACjB,OAAO,EAAE,eAAe,MAAM,WAC5B,IAAI,KAAK,EAAE,eAAe,CAAC,EAAE,QAAQ,IACrC,KAAK,IAAI;AAAA,QACjB,KAAK,OAAO,EAAE,KAAK,MAAM,WAAW,EAAE,KAAK,IAAI;AAAA,QAC/C,UAAU;AAAA,MACZ;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,aAAmC;AACvC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,cAAgD;AACpD,QAAI;AACF,YAAM,UAAU,MAAM,SAAS,sBAAsB,OAAO;AAC5D,YAAM,SAAkB,KAAK,MAAM,OAAO;AAC1C,UAAI,OAAO,WAAW,YAAY,WAAW,MAAM;AACjD,eAAO;AAAA,MACT;AACA,aAAO,CAAC;AAAA,IACV,QAAQ;AACN,aAAO,CAAC;AAAA,IACV;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,eAAe,UAAkD;AACrE,UAAM,UAAU,MAAM,KAAK,YAAY;AACvC,UAAM,SAAS,EAAE,GAAG,SAAS,GAAG,SAAS;AACzC,UAAM;AAAA,MACJ;AAAA,MACA,KAAK,UAAU,QAAQ,MAAM,CAAC;AAAA,MAC9B;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAAyB;AAE7B,eAAW,CAAC,SAAS,KAAK,KAAK,kBAAkB;AAC/C,WAAK,MAAM,SAAS;AAAA,IACtB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,cAAc,KAA6B,UAAkB,SAAwB;AAC3F,QAAI,YAAY,IAAI;AACpB,QAAI,aAAa,IAAI;AACrB,QAAI,YAAY,IAAI;AACpB,QAAI,aAAa,IAAI;AACrB,QAAI,WAAW,IAAI;AACnB,QAAI,WAAW,IAAI;AACnB,QAAI,SAAS;AACX,UAAI,UAAU,IAAI;AAClB,UAAI,UAAU,IAAI;AAAA,IACpB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,eAAe,SAAgC;AACrD,WAAO,QAAQ;AAAA,EACjB;AAAA,EAEQ,UAAU,SAAkC;AAClD,UAAM,OAAiB;AAAA,MACrB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAGA,QAAI,QAAQ,QAAQ;AAClB,WAAK,KAAK,YAAY,QAAQ,MAAM;AAAA,IACtC;AAGA,UAAM,QAAQ,QAAQ,SAAS,KAAK,QAAQ;AAC5C,QAAI,OAAO;AACT,WAAK,KAAK,WAAW,KAAK;AAAA,IAC5B;AAIA,QAAI,QAAQ,cAAc;AACxB,WAAK,KAAK,mBAAmB,QAAQ,YAAY;AAAA,IACnD;AAEA,UAAM,eACJ,QAAQ,sBAAsB,KAAK,QAAQ;AAC7C,QAAI,cAAc;AAChB,WAAK,KAAK,0BAA0B,YAAY;AAAA,IAClD;AAGA,QAAI,QAAQ,gBAAgB,QAAQ,aAAa,SAAS,GAAG;AAC3D,iBAAW,QAAQ,QAAQ,cAAc;AACvC,aAAK,KAAK,kBAAkB,IAAI;AAAA,MAClC;AAAA,IACF;AAEA,QAAI,QAAQ,mBAAmB,QAAQ,gBAAgB,SAAS,GAAG;AACjE,iBAAW,QAAQ,QAAQ,iBAAiB;AAC1C,aAAK,KAAK,qBAAqB,IAAI;AAAA,MACrC;AAAA,IACF;AAGA,QAAI,QAAQ,aAAa,QAAW;AAClC,WAAK,KAAK,eAAe,OAAO,QAAQ,QAAQ,CAAC;AAAA,IACnD;AAKA,UAAM,cAAc,KAAK,QAAQ;AACjC,UAAM,YAAY,gBAAgB,SAC7B,QAAQ,gBAAgB,8BACxB,KAAK,QAAQ,SAAS;AAC3B,QAAI,WAAW;AACb,WAAK,KAAK,gCAAgC;AAAA,IAC5C;AAGA,QAAI,QAAQ,YAAY;AACtB,iBAAW,CAAC,MAAM,MAAM,KAAK,OAAO,QAAQ,QAAQ,UAAU,GAAG;AAC/D,cAAM,aAAsC;AAAA,UAC1C,SAAS,OAAO;AAAA,UAChB,GAAI,OAAO,OAAO,EAAE,MAAM,OAAO,KAAK,IAAI,CAAC;AAAA,UAC3C,GAAI,OAAO,MAAM,EAAE,KAAK,OAAO,IAAI,IAAI,CAAC;AAAA,UACxC,GAAI,OAAO,MAAM,EAAE,KAAK,OAAO,IAAI,IAAI,CAAC;AAAA,QAC1C;AACA,aAAK,KAAK,gBAAgB,GAAG,IAAI,IAAI,KAAK,UAAU,UAAU,CAAC,EAAE;AAAA,MACnE;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AACF;;;AInYA,SAAS,YAAAE,WAAU,aAAAC,YAAW,aAAa;AAC3C,SAAS,WAAAC,gBAAe;AACxB,SAAS,QAAAC,aAAY;;;ACwKd,IAAM,mBAAN,cAA+B,MAAM;AAAA,EACjC;AAAA,EACA;AAAA,EAET,YAAY,YAAoB,cAAsB;AACpD,UAAM,uBAAuB,UAAU,MAAM,YAAY,EAAE;AAC3D,SAAK,OAAO;AACZ,SAAK,aAAa;AAClB,SAAK,eAAe;AAAA,EACtB;AACF;;;ACvKA,IAAM,qBAAqB;AAMpB,IAAM,oBAAN,MAAwB;AAAA,EACZ;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMjB,YAAY,SAAiB,QAAiB;AAE5C,SAAK,UAAU,QAAQ,QAAQ,QAAQ,EAAE;AACzC,SAAK,SAAS;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,cAAc,KAA8C;AAChE,UAAM,OAAgC,CAAC;AACvC,QAAI,KAAK;AACP,WAAK,MAAM;AAAA,IACb;AAEA,UAAM,WAAW,MAAM,KAAK;AAAA,MAC1B;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,MAAM,KAAK,UAAU,IAAI;AAAA,MAC3B;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,eAA2C;AAC/C,UAAM,WAAW,MAAM,KAAK;AAAA,MAC1B;AAAA,MACA,EAAE,QAAQ,MAAM;AAAA,IAClB;AACA,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,YAAY,WAAmB,SAAgC;AACnE,UAAM,KAAK;AAAA,MACT,gBAAgB,mBAAmB,SAAS,CAAC;AAAA,MAC7C;AAAA,QACE,QAAQ;AAAA,QACR,MAAM,KAAK,UAAU,EAAE,QAAQ,CAAC;AAAA,MAClC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,aACL,WACA,aAC+B;AAC/B,UAAM,MAAM,GAAG,KAAK,OAAO,gBAAgB,mBAAmB,SAAS,CAAC;AAExE,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,QAAQ;AAAA,QACR,iBAAiB;AAAA,QACjB,GAAG,KAAK,iBAAiB;AAAA,MAC3B;AAAA,MACA,QAAQ;AAAA,IACV,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,OAAO,MAAM,SAAS,KAAK,EAAE,MAAM,MAAM,EAAE;AACjD,YAAM,IAAI,iBAAiB,SAAS,QAAQ,IAAI;AAAA,IAClD;AAEA,QAAI,CAAC,SAAS,MAAM;AAClB,YAAM,IAAI,MAAM,kDAAkD;AAAA,IACpE;AAEA,UAAM,SAAS,SAAS,KAAK,UAAU;AACvC,UAAM,UAAU,IAAI,YAAY;AAChC,QAAI,SAAS;AAEb,QAAI;AACF,aAAO,MAAM;AACX,cAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,YAAI,KAAM;AAEV,kBAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;AAGhD,cAAM,QAAQ,OAAO,MAAM,MAAM;AAEjC,iBAAS,MAAM,IAAI,KAAK;AAExB,mBAAW,QAAQ,OAAO;AACxB,gBAAM,QAAQ,KAAK,cAAc,IAAI;AACrC,cAAI,OAAO;AACT,kBAAM;AAEN,gBAAI,MAAM,SAAS,QAAQ;AACzB;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAGA,UAAI,OAAO,KAAK,GAAG;AACjB,cAAM,QAAQ,KAAK,cAAc,MAAM;AACvC,YAAI,OAAO;AACT,gBAAM;AAAA,QACR;AAAA,MACF;AAAA,IACF,UAAE;AACA,aAAO,YAAY;AAAA,IACrB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,cAAgC;AACpC,QAAI;AACF,YAAM,aAAa,IAAI,gBAAgB;AACvC,YAAM,QAAQ,WAAW,MAAM,WAAW,MAAM,GAAG,GAAK;AAExD,YAAM,WAAW,MAAM,MAAM,GAAG,KAAK,OAAO,iBAAiB;AAAA,QAC3D,QAAQ;AAAA,QACR,SAAS,KAAK,iBAAiB;AAAA,QAC/B,QAAQ,WAAW;AAAA,MACrB,CAAC;AAED,mBAAa,KAAK;AAClB,aAAO,SAAS;AAAA,IAClB,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,cAAc,KAAmC;AACvD,UAAM,QAAQ,IAAI,MAAM,IAAI;AAC5B,QAAI,OAAO;AAEX,eAAW,QAAQ,OAAO;AAExB,UAAI,KAAK,WAAW,GAAG,EAAG;AAE1B,UAAI,KAAK,WAAW,QAAQ,GAAG;AAC7B,gBAAQ,KAAK,MAAM,CAAC;AAAA,MACtB,WAAW,KAAK,WAAW,OAAO,GAAG;AACnC,gBAAQ,KAAK,MAAM,CAAC;AAAA,MACtB;AAAA,IACF;AAEA,QAAI,CAAC,KAAM,QAAO;AAElB,QAAI;AACF,aAAO,KAAK,MAAM,IAAI;AAAA,IACxB,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWQ,mBAA2C;AACjD,UAAM,UAAkC,CAAC;AACzC,QAAI,KAAK,QAAQ;AACf,YAAM,cAAc,OAAO,KAAK,YAAY,KAAK,MAAM,EAAE,EAAE,SAAS,QAAQ;AAC5E,cAAQ,eAAe,IAAI,SAAS,WAAW;AAAA,IACjD;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,QAAW,MAAc,MAA+B;AACpE,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,QAAQ,WAAW,MAAM,WAAW,MAAM,GAAG,kBAAkB;AAErE,QAAI;AACF,YAAM,WAAW,MAAM,MAAM,GAAG,KAAK,OAAO,GAAG,IAAI,IAAI;AAAA,QACrD,GAAG;AAAA,QACH,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,GAAG,KAAK,iBAAiB;AAAA,UACzB,GAAG,KAAK;AAAA,QACV;AAAA,QACA,QAAQ,WAAW;AAAA,MACrB,CAAC;AAED,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,OAAO,MAAM,SAAS,KAAK,EAAE,MAAM,MAAM,EAAE;AACjD,cAAM,IAAI,iBAAiB,SAAS,QAAQ,IAAI;AAAA,MAClD;AAEA,YAAM,OAAO,MAAM,SAAS,KAAK;AACjC,UAAI,CAAC,KAAM,QAAO,CAAC;AACnB,aAAO,KAAK,MAAM,IAAI;AAAA,IACxB,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF;AACF;;;AChPO,SAAS,0BACd,OACqB;AACrB,QAAM,OAAO;AAAA,IACX,WAAW,MAAM,aAAa,KAAK,IAAI;AAAA,IACvC,WAAW,MAAM;AAAA,IACjB,KAAK;AAAA,EACP;AAEA,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,MAAM;AAAA,QACN,OAAO,MAAM;AAAA,QACb,OAAO,MAAM;AAAA,QACb,KAAK,MAAM;AAAA,MACb;AAAA,IAEF,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,MAAM;AAAA,QACN,MAAM,MAAM;AAAA,MACd;AAAA,IAEF,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,MAAM;AAAA,QACN,MAAM,MAAM;AAAA,QACZ,YAAY,MAAM;AAAA,QAClB,SAAS,MAAM;AAAA,QACf,aAAa,MAAM;AAAA,QACnB,cAAc,MAAM;AAAA,MACtB;AAAA,IAEF,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,MAAM;AAAA,QACN,UAAU,MAAM;AAAA,QAChB,OAAO,MAAM;AAAA,MACf;AAAA,IAEF,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,MAAM;AAAA,QACN,UAAU,MAAM;AAAA,QAChB,OAAO,MAAM;AAAA,QACb,QAAQ,MAAM;AAAA,MAChB;AAAA,IAEF,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,MAAM;AAAA,QACN,SAAS,MAAM;AAAA,QACf,MAAM,MAAM;AAAA,MACd;AAAA;AAAA,IAGF,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IAET;AACE,aAAO;AAAA,EACX;AACF;;;AH3DA,IAAM,qBAAqB;AAG3B,IAAM,yBAAyB;AAG/B,IAAM,yBAAyB;AAG/B,IAAM,uBAAuB;AAG7B,IAAM,eAAe;AAGrB,IAAM,sBAAsB;AAG5B,IAAM,2BAA2B;AAM1B,IAAM,kBAAN,cAA8B,qBAAqB;AAAA,EAC/C,UAAU;AAAA,EAEX,YAAsC;AAAA,EACtC;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASR,YAAY,gBAAgC,QAAwB;AAClE,UAAM,gBAAgB,MAAM;AAC5B,UAAM,OAAO,QAAQ,WAAW,CAAC;AAEjC,SAAK,kBAAkB,QAAQ,aAAc,KAAK;AAClD,SAAK,SAAS,QAAQ,UAAW,KAAK;AACtC,SAAK,YAAa,KAAK,aAAwB;AAAA,EACjD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,cAAgC;AAEpC,QAAI,KAAK,iBAAiB;AACxB,UAAI;AACF,cAAM,SAAS,IAAI,kBAAkB,KAAK,iBAAiB,KAAK,MAAM;AACtE,eAAO,MAAM,OAAO,YAAY;AAAA,MAClC,QAAQ;AACN,eAAO;AAAA,MACT;AAAA,IACF;AAEA,QAAI;AACF,YAAM,OAAO,IAAI,iBAAiB;AAClC,YAAM,SAAS,MAAM,KAAK,QAAQ;AAAA,QAChC,SAAS;AAAA,QACT,MAAM,CAAC,WAAW;AAAA,QAClB,WAAW;AAAA,MACb,CAAC;AACD,aAAO,OAAO,aAAa;AAAA,IAC7B,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAA8B;AAClC,UAAM,OAAO,IAAI,iBAAiB;AAClC,UAAM,SAAS,MAAM,KAAK,QAAQ;AAAA,MAChC,SAAS;AAAA,MACT,MAAM,CAAC,SAAS;AAAA,MAChB,WAAW;AAAA,IACb,CAAC;AAED,QAAI,OAAO,aAAa,GAAG;AACzB,YAAM,IAAI,MAAM,mCAAmC,OAAO,MAAM,EAAE;AAAA,IACpE;AAEA,WAAO,OAAO,OAAO,KAAK;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAKA,kBAAuC;AACrC,WAAO;AAAA,MACL,UAAU,oBAAI,IAAI;AAAA,QAChB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAAA,MACD,eAAe;AAAA,MACf,eAAe,CAAC,MAAM;AAAA,MACtB,oBAAoB;AAAA,IACtB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,OAAO,MAAM,SAAsD;AAEjE,UAAM,SAAS,MAAM,KAAK,mBAAmB;AAG7C,QAAI;AACJ,QAAI,QAAQ,QAAQ;AAClB,kBAAY,QAAQ;AAAA,IACtB,OAAO;AACL,YAAM,UAAU,MAAM,OAAO,cAAc,QAAQ,GAAG;AACtD,kBAAY,QAAQ;AAAA,IACtB;AAGA,UAAM,aAAa,KAAK,sBAAsB,SAAS;AAEvD,QAAI;AAEF,YAAM,OAAO,YAAY,WAAW,QAAQ,MAAM;AAGlD,uBAAiB,SAAS,OAAO;AAAA,QAC/B;AAAA,QACA,WAAW;AAAA,MACb,GAAG;AACD,cAAM,UAAU,0BAA0B,KAAK;AAC/C,YAAI,SAAS;AACX,gBAAM;AAAA,QACR;AAAA,MACF;AAAA,IACF,UAAE;AACA,WAAK,sBAAsB,SAAS;AAAA,IACtC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,aAAa,SAAsD;AACvE,UAAM,SAAS,MAAM,KAAK,mBAAmB;AAC7C,UAAM,WAAW,MAAM,OAAO,aAAa;AAE3C,QAAI,WAAW;AAEf,QAAI,SAAS,KAAK;AAChB,iBAAW,SAAS,OAAO,CAAC,MAAM,EAAE,QAAQ,QAAQ,GAAG;AAAA,IACzD;AAEA,QAAI,SAAS,UAAU,UAAa,QAAQ,QAAQ,GAAG;AACrD,iBAAW,SAAS,MAAM,GAAG,QAAQ,KAAK;AAAA,IAC5C;AAEA,WAAO,SAAS,IAAI,CAAC,OAAO;AAAA,MAC1B,WAAW,EAAE;AAAA,MACb,SAAS,KAAK;AAAA,MACd,SAAS,EAAE;AAAA,MACX,cAAc,EAAE;AAAA,MAChB,KAAK,EAAE;AAAA,IACT,EAAE;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAAmC;AACvC,QAAI;AACF,YAAM,OAAO,IAAI,iBAAiB;AAClC,YAAM,SAAS,MAAM,KAAK,QAAQ;AAAA,QAChC,SAAS;AAAA,QACT,MAAM,CAAC,QAAQ;AAAA,QACf,WAAW;AAAA,MACb,CAAC;AAED,UAAI,OAAO,aAAa,EAAG,QAAO,CAAC;AAEnC,YAAM,QAAQ,OAAO,OAAO,KAAK,EAAE,MAAM,IAAI,EAAE,OAAO,OAAO;AAC7D,aAAO,MAAM,IAAI,CAAC,SAAS;AACzB,cAAM,UAAU,KAAK,KAAK;AAC1B,cAAM,aAAa,QAAQ,QAAQ,GAAG;AACtC,YAAI,cAAc,GAAG;AACnB,iBAAO;AAAA,YACL,IAAI;AAAA,YACJ,MAAM,QAAQ,MAAM,aAAa,CAAC;AAAA,YAClC,UAAU,QAAQ,MAAM,GAAG,UAAU;AAAA,UACvC;AAAA,QACF;AACA,eAAO,EAAE,IAAI,SAAS,MAAM,QAAQ;AAAA,MACtC,CAAC;AAAA,IACH,QAAQ;AACN,aAAO,CAAC;AAAA,IACV;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,cAAgD;AACpD,UAAM,aAAa,KAAK,cAAc;AACtC,QAAI;AACF,YAAM,UAAU,MAAMC,UAAS,YAAY,OAAO;AAClD,aAAO,KAAK,MAAM,OAAO;AAAA,IAC3B,QAAQ;AACN,aAAO,CAAC;AAAA,IACV;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,eAAe,UAAkD;AACrE,UAAM,aAAa,KAAK,cAAc;AACtC,UAAM,YAAYC,MAAKC,SAAQ,GAAG,WAAW,UAAU;AAEvD,QAAI;AACJ,QAAI;AACF,YAAM,UAAU,MAAMF,UAAS,YAAY,OAAO;AAClD,iBAAW,KAAK,MAAM,OAAO;AAAA,IAC/B,QAAQ;AACN,iBAAW,CAAC;AAAA,IACd;AAEA,UAAM,SAAS,EAAE,GAAG,UAAU,GAAG,SAAS;AAE1C,UAAM,MAAM,WAAW,EAAE,WAAW,KAAK,CAAC;AAC1C,UAAMG,WAAU,YAAY,KAAK,UAAU,QAAQ,MAAM,CAAC,GAAG,OAAO;AAAA,EACtE;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAAyB;AAE7B,eAAW,CAAC,SAAS,KAAK,KAAK,kBAAkB;AAC/C,WAAK,MAAM,SAAS;AAAA,IACtB;AAGA,UAAM,aAAa,KAAK,eAAe,cAAc,KAAK,OAAO;AACjE,QAAI,YAAY;AACd,YAAM,WAAW,KAAK;AAAA,IACxB;AAEA,SAAK,YAAY;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,qBAAiD;AAC7D,QAAI,KAAK,WAAW;AAClB,YAAM,UAAU,MAAM,KAAK,UAAU,YAAY;AACjD,UAAI,QAAS,QAAO,KAAK;AAAA,IAC3B;AAGA,QAAI,KAAK,iBAAiB;AACxB,YAAMC,UAAS,IAAI,kBAAkB,KAAK,iBAAiB,KAAK,MAAM;AACtE,YAAM,UAAU,MAAMA,QAAO,YAAY;AACzC,UAAI,CAAC,SAAS;AACZ,cAAM,IAAI;AAAA,UACR,+DAAuB,KAAK,eAAe;AAAA,QAC7C;AAAA,MACF;AACA,WAAK,YAAYA;AACjB,aAAOA;AAAA,IACT;AAGA,UAAM,SAAS,IAAI;AAAA,MACjB,oBAAoB,KAAK,SAAS;AAAA,MAClC,KAAK;AAAA,IACP;AAGA,UAAM,iBAAiB,MAAM,OAAO,YAAY;AAChD,QAAI,gBAAgB;AAClB,WAAK,YAAY;AACjB,aAAO;AAAA,IACT;AAGA,UAAM,KAAK,eAAe,gBAAgB,KAAK,SAAS;AAAA,MACtD,SAAS;AAAA,MACT,MAAM,CAAC,SAAS,UAAU,OAAO,KAAK,SAAS,CAAC;AAAA,MAChD,aAAa;AAAA,MACb,mBAAmB;AAAA,MACnB,uBAAuB;AAAA,MACvB,eAAe,MAAM,OAAO,YAAY,EAAE,KAAK,CAAC,OAAO;AACrD,YAAI,CAAC,GAAI,OAAM,IAAI,MAAM,qBAAqB;AAC9C,eAAO;AAAA,MACT,CAAC;AAAA,IACH,CAAC;AAGD,UAAM,KAAK,kBAAkB,MAAM;AAEnC,SAAK,YAAY;AACjB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,kBAAkB,QAA0C;AACxE,UAAM,WAAW,KAAK,IAAI,IAAI;AAE9B,WAAO,KAAK,IAAI,IAAI,UAAU;AAC5B,YAAM,UAAU,MAAM,OAAO,YAAY;AACzC,UAAI,QAAS;AAEb,YAAM,KAAK,MAAM,sBAAsB;AAAA,IACzC;AAEA,UAAM,IAAI;AAAA,MACR,8CAA8C,sBAAsB;AAAA,IACtE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,MAAM,IAA2B;AACvC,WAAO,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA,EAKQ,gBAAwB;AAC9B,WAAOH,MAAKC,SAAQ,GAAG,WAAW,YAAY,aAAa;AAAA,EAC7D;AACF;;;AItWO,IAAM,qBAAN,MAAyB;AAAA,EACrB;AAAA,EACD;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ,SAAS;AAAA,EAEjB,YACE,kBACA,SACA,aACA;AACA,SAAK,mBAAmB;AACxB,SAAK,UAAU;AACf,SAAK,cAAc;AAAA,EACrB;AAAA;AAAA,EAGA,IAAI,YAAoB;AACtB,WAAO,KAAK,qBAAqB,KAAK;AAAA,EACxC;AAAA;AAAA,EAGA,IAAI,WAAoB;AACtB,WAAO,CAAC,KAAK;AAAA,EACf;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO,KAAK,QAA8C;AACxD,QAAI,KAAK,QAAQ;AACf,YAAM,IAAI,qBAAqB,KAAK,SAAS;AAAA,IAC/C;AAEA,UAAM,UAAyB;AAAA,MAC7B,GAAG,KAAK;AAAA,MACR;AAAA,MACA,GAAI,KAAK,YAAY,EAAE,QAAQ,KAAK,UAAU,IAAI,CAAC;AAAA,IACrD;AAEA,qBAAiB,OAAO,KAAK,QAAQ,MAAM,OAAO,GAAG;AACnD,UAAI,CAAC,KAAK,aAAa,IAAI,WAAW;AACpC,aAAK,oBAAoB,IAAI;AAAA,MAC/B;AACA,YAAM;AAAA,IACR;AACA,SAAK,YAAY;AAAA,EACnB;AAAA;AAAA,EAGA,QAAc;AACZ,SAAK,SAAS;AAAA,EAChB;AACF;;;AjBnBO,IAAM,UAAN,cAAsBG,cAAa;AAAA,EAChC;AAAA,EACA,WAAW,oBAAI,IAA2B;AAAA,EAC1C;AAAA,EACA;AAAA,EACA;AAAA,EAER,YAAY,QAAiC;AAC3C,UAAM;AACN,SAAK,SAAS,aAAa,KAAK,MAAM;AACtC,SAAK,eAAe,IAAI,mBAAmB;AAC3C,SAAK,iBAAiB,IAAI,eAAe;AACzC,SAAK,iBAAiB,IAAI,eAAe;AAEzC,SAAK,wBAAwB;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA,EAKQ,0BAAgC;AACtC,UAAM,eAAe,KAAK,OAAO,WAAW,QAAQ;AAEpD,UAAM,qBAAqB;AAAA,MACzB,GAAG;AAAA,MACH,OAAO,cAAc,SAAS,KAAK,OAAO;AAAA,IAC5C;AACA,UAAM,gBAAgB,IAAI,cAAc,KAAK,gBAAgB,kBAAkB;AAC/E,SAAK,gBAAgB,aAAa;AAElC,UAAM,iBAAiB,KAAK,OAAO,WAAW,UAAU;AACxD,UAAM,uBAAuB;AAAA,MAC3B,GAAG;AAAA,MACH,OAAO,gBAAgB,SAAS,KAAK,OAAO;AAAA,IAC9C;AACA,UAAM,kBAAkB,IAAI,gBAAgB,KAAK,gBAAgB,oBAAoB;AACrF,SAAK,gBAAgB,eAAe;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,gBAAgB,SAA8B;AAC5C,SAAK,SAAS,IAAI,QAAQ,SAAS,OAAO;AAC1C,SAAK,eAAe,gBAAgB,QAAQ,SAAS,OAAO;AAAA,EAC9D;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,WAAW,SAAiC;AAClD,UAAM,OAAO,WAAW,KAAK,OAAO,kBAAkB;AACtD,UAAM,UAAU,KAAK,SAAS,IAAI,IAAI;AACtC,QAAI,CAAC,QAAS,OAAM,IAAI,qBAAqB,IAAI;AACjD,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,MAAM,SAAsD;AACjE,UAAM,UAAU,KAAK,WAAW,QAAQ,OAAO;AAC/C,UAAM,cAAc,QAAQ;AAE5B,UAAM,gBAAgB,KAAK,aAAa,SAAS,WAAW;AAG5D,UAAM,kBAAkB,MAAM,KAAK,aAAa;AAAA,MAC9C,cAAc;AAAA,MACd,EAAE,SAAS,aAAa,WAAW,cAAc,OAAO;AAAA,IAC1D;AACA,kBAAc,SAAS;AAEvB,qBAAiB,WAAW,QAAQ,MAAM,aAAa,GAAG;AAExD,UAAI,QAAQ,SAAS,eAAe,QAAQ,SAAS,UAAU;AAC7D,cAAM,gBAAgB,MAAM,KAAK,aAAa;AAAA,UAC5C,QAAQ;AAAA,UACR;AAAA,YACE,SAAS;AAAA,YACT,WAAW,QAAQ;AAAA,YACnB,aAAa,QAAQ;AAAA,UACvB;AAAA,QACF;AACA,cAAM,EAAE,GAAG,SAAS,MAAM,cAAc;AAAA,MAC1C,OAAO;AACL,cAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,IAAI,SAAyC;AACjD,QAAI,aAAa;AACjB,qBAAiB,OAAO,KAAK,MAAM,OAAO,GAAG;AAC3C,UAAI,IAAI,SAAS,UAAU;AACzB,qBAAa,IAAI;AAAA,MACnB,WAAW,IAAI,SAAS,aAAa;AACnC,qBAAa,IAAI;AAAA,MACnB;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,QAAQ,SAA6D;AACnE,UAAM,UAAU,SAAS,WAAW,KAAK,OAAO,kBAAkB;AAClE,UAAM,UAAU,KAAK,WAAW,OAAO;AACvC,UAAM,SAAS,KAAK,aAAa,EAAE,GAAG,SAAS,QAAQ,GAAG,GAAG,OAAO;AACpE,UAAM,EAAE,QAAQ,GAAG,GAAG,YAAY,IAAI;AACtC,WAAO,IAAI;AAAA,MACT,OAAO,WAAW;AAAA,MAClB;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,IAAI,WAAiC,IAA+B;AAClE,WAAO,KAAK,aAAa,IAAI,WAAW,EAAE;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,gBAAgB,SAAuC;AACrD,WAAO,KAAK,WAAW,OAAO,EAAE,gBAAgB;AAAA,EAClD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,WAAW,SAAwC;AACvD,WAAO,KAAK,WAAW,OAAO,EAAE,WAAW;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,aAAa,SAA6C;AAC9D,UAAM,UAAU,KAAK,WAAW,OAAO;AACvC,QAAI;AACF,YAAM,YAAY,MAAM,QAAQ,YAAY;AAC5C,UAAI,CAAC,WAAW;AACd,eAAO,EAAE,WAAW,MAAM;AAAA,MAC5B;AACA,YAAM,SAAS,MAAM,QAAQ,mBAAmB;AAChD,YAAM,SAA4B;AAAA,QAChC,WAAW;AAAA,QACX,SAAS,OAAO;AAAA,QAChB,WAAW,OAAO;AAAA,MACpB;AACA,UAAI,OAAO,SAAS,SAAS,GAAG;AAC9B,eAAO,WAAW,OAAO;AAAA,MAC3B;AACA,UAAI,CAAC,OAAO,WAAW;AACrB,aAAK,KAAK,mBAAmB,SAAS,OAAO,SAAS,KAAK,IAAI,CAAC;AAAA,MAClE;AACA,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,aAAO;AAAA,QACL,WAAW;AAAA,QACX,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,MACxD;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,cAA0D;AAC9D,UAAM,UAAU,MAAM,KAAK,KAAK,SAAS,KAAK,CAAC;AAC/C,UAAM,SAAS,QAAQ,IAAI,OAAO,SAAS;AACzC,YAAM,SAAS,MAAM,KAAK,aAAa,IAAI;AAC3C,aAAO,CAAC,MAAM,MAAM;AAAA,IACtB,CAAC;AAED,UAAM,UAAU,MAAM,QAAQ,WAAW,MAAM;AAC/C,UAAM,UAA6C,CAAC;AAEpD,eAAW,QAAQ,SAAS;AAC1B,UAAI,KAAK,WAAW,aAAa;AAC/B,cAAM,CAAC,MAAM,MAAM,IAAI,KAAK;AAC5B,gBAAQ,IAAI,IAAI;AAAA,MAClB;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,SACJ,SACA,aACkC;AAClC,UAAM,UAAU,KAAK,WAAW,OAAO;AACvC,QAAI,aAAa;AACf,YAAM,QAAQ,eAAe,WAAW;AAAA,IAC1C;AACA,WAAO,QAAQ,YAAY;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,aACJ,SACA,SACwB;AACxB,UAAM,OAAO,WAAW,KAAK,OAAO,kBAAkB;AACtD,WAAO,KAAK,eAAe,KAAK,MAAM,OAAO;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,SAAiB,WAAyB;AAC9C,SAAK,WAAW,OAAO,EAAE,MAAM,SAAS;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAAyB;AAC7B,UAAM,WAA4B,CAAC;AACnC,eAAW,CAAC,EAAE,OAAO,KAAK,KAAK,UAAU;AACvC,eAAS,KAAK,QAAQ,QAAQ,CAAC;AAAA,IACjC;AACA,UAAM,QAAQ,WAAW,QAAQ;AACjC,UAAM,KAAK,eAAe,aAAa;AACvC,SAAK,SAAS,MAAM;AACpB,SAAK,eAAe,WAAW;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBQ,aACN,SACA,SACe;AACf,UAAM,gBAAgB,KAAK,OAAO,WAAW,OAAO;AACpD,UAAM,WAAW,KAAK,OAAO;AAE7B,UAAM,cAAwB,CAAC;AAC/B,QAAI,UAAU,oBAAoB;AAChC,kBAAY,KAAK,SAAS,kBAAkB;AAAA,IAC9C;AACA,QAAI,eAAe,oBAAoB;AACrC,kBAAY,KAAK,cAAc,kBAAkB;AAAA,IACnD;AACA,QAAI,QAAQ,oBAAoB;AAC9B,kBAAY,KAAK,QAAQ,kBAAkB;AAAA,IAC7C;AAEA,WAAO;AAAA,MACL,GAAG;AAAA,MACH,OAAO,QAAQ,SAAS,eAAe;AAAA,MACvC,WAAW,QAAQ,aAAa,UAAU;AAAA,MAC1C,UAAU,QAAQ,YAAY,UAAU;AAAA,MACxC,KAAK,QAAQ,OAAO,eAAe;AAAA,MACnC,oBAAoB,QAAQ,eACxB,SACA,YAAY,SAAS,IACnB,YAAY,KAAK,IAAI,IACrB;AAAA,IACR;AAAA,EACF;AACF;AAOO,SAAS,cAAc,QAA0C;AACtE,SAAO,IAAI,QAAQ,MAAM;AAC3B;;;AkBtUA,IAAM,yBAAmC;AAAA;AAAA,EAEvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAqBO,SAAS,iBAAiB,SAAuC;AACtE,QAAM,WAAW;AAAA,IACf,GAAG;AAAA,IACH,GAAI,SAAS,mBAAmB,CAAC;AAAA,EACnC;AACA,QAAM,SAAS,SAAS,UAAU;AAClC,QAAM,WAAW,SAAS;AAE1B,SAAO,CAAC,MAAc,YAAgC;AAEpD,QAAI,YAAY,CAAC,SAAS,SAAS,QAAQ,OAAO,GAAG;AACnD,aAAO;AAAA,IACT;AAGA,eAAW,WAAW,UAAU;AAC9B,UAAI,QAAQ,KAAK,IAAI,GAAG;AACtB,YAAI,WAAW,UAAU;AACvB,iBAAO;AAAA,QACT;AAEA,eAAO,KAAK,QAAQ,SAAS,YAAY;AAAA,MAC3C;AAAA,IACF;AAGA,QAAI,SAAS,cAAc,MAAM,OAAO,GAAG;AACzC,UAAI,WAAW,UAAU;AACvB,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AACF;AAiBO,SAAS,kBAAkB,SAAuC;AACvE,QAAM,WAAW,SAAS,qBAAqB,CAAC;AAChD,QAAM,SAAS,SAAS,UAAU;AAClC,QAAM,WAAW,SAAS;AAE1B,SAAO,CAAC,MAAc,YAAgC;AAEpD,QAAI,YAAY,CAAC,SAAS,SAAS,QAAQ,OAAO,GAAG;AACnD,aAAO;AAAA,IACT;AAGA,QAAI,UAAU;AACd,QAAI,SAAS;AAEb,eAAW,WAAW,UAAU;AAC9B,UAAI,KAAK,SAAS,OAAO,GAAG;AAC1B,kBAAU;AACV,YAAI,WAAW,UAAU;AAEvB,mBAAS,OAAO,MAAM,OAAO,EAAE,KAAK,YAAY;AAAA,QAClD;AAAA,MACF;AAAA,IACF;AAGA,QAAI,CAAC,WAAW,SAAS,cAAc,MAAM,OAAO,GAAG;AACrD,gBAAU;AACV,UAAI,WAAW,UAAU;AACvB,iBAAS;AAAA,MACX;AAAA,IACF;AAEA,QAAI,CAAC,SAAS;AACZ,aAAO;AAAA,IACT;AAEA,QAAI,WAAW,UAAU;AACvB,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AACF;","names":["EventEmitter","rangeVersion","currentVersion","readFile","writeFile","homedir","join","readFile","join","homedir","writeFile","client","EventEmitter"]}
|