agentdev 0.1.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/LICENSE +21 -0
- package/README.md +384 -0
- package/dist/BasicAgent-UDSHJE5H.js +12 -0
- package/dist/BasicAgent-UDSHJE5H.js.map +1 -0
- package/dist/ExplorerAgent-X6QECX65.js +12 -0
- package/dist/ExplorerAgent-X6QECX65.js.map +1 -0
- package/dist/chunk-3BPSNNK3.js +926 -0
- package/dist/chunk-3BPSNNK3.js.map +1 -0
- package/dist/chunk-BDS2QGZ5.js +22 -0
- package/dist/chunk-BDS2QGZ5.js.map +1 -0
- package/dist/chunk-BVF7RUXV.js +136 -0
- package/dist/chunk-BVF7RUXV.js.map +1 -0
- package/dist/chunk-DI5EGMGG.js +87 -0
- package/dist/chunk-DI5EGMGG.js.map +1 -0
- package/dist/chunk-FZGM6EMW.js +7578 -0
- package/dist/chunk-FZGM6EMW.js.map +1 -0
- package/dist/chunk-N7J76R5P.js +7659 -0
- package/dist/chunk-N7J76R5P.js.map +1 -0
- package/dist/chunk-TSASFMRF.js +12 -0
- package/dist/chunk-TSASFMRF.js.map +1 -0
- package/dist/chunk-XAJ6L4GA.js +98 -0
- package/dist/chunk-XAJ6L4GA.js.map +1 -0
- package/dist/cli/server.cmd +2 -0
- package/dist/cli/server.d.ts +1 -0
- package/dist/cli/server.js +46 -0
- package/dist/cli/server.js.map +1 -0
- package/dist/cli/viewer.cmd +2 -0
- package/dist/cli/viewer.d.ts +1 -0
- package/dist/cli/viewer.js +45 -0
- package/dist/cli/viewer.js.map +1 -0
- package/dist/index.d.ts +3836 -0
- package/dist/index.js +273 -0
- package/dist/index.js.map +1 -0
- package/dist/notification-3VEAP7YF.js +89 -0
- package/dist/notification-3VEAP7YF.js.map +1 -0
- package/dist/resolver-5H6QIGVA.js +8 -0
- package/dist/resolver-5H6QIGVA.js.map +1 -0
- package/package.json +74 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/debug-transport.ts","../src/core/debug-capabilities.ts","../src/core/debug-hub.ts","../src/core/claw-debug-client.ts"],"sourcesContent":["export type DebugTransportMode = 'viewer-worker' | 'claw';\n\nexport function resolveDebugTransportMode(): DebugTransportMode {\n return process.env.AGENTDEV_DEBUG_TRANSPORT === 'claw' ? 'claw' : 'viewer-worker';\n}\n\nexport function getClawRuntimeUrl(): string {\n return process.env.AGENTDEV_CLAW_RUNTIME_URL || 'http://127.0.0.1:3030';\n}\n","import { getClawRuntimeUrl, resolveDebugTransportMode, type DebugTransportMode } from './debug-transport.js';\n\nexport interface DebugCapabilities {\n transportMode: DebugTransportMode;\n interactiveInput: boolean;\n runtimeUrl: string | null;\n viewerCompatibleApi: boolean;\n debuggerMcpMetadata: boolean;\n}\n\nexport function getDebugCapabilities(): DebugCapabilities {\n const transportMode = resolveDebugTransportMode();\n const isClaw = transportMode === 'claw';\n\n return {\n transportMode,\n interactiveInput: true,\n runtimeUrl: isClaw ? getClawRuntimeUrl() : null,\n viewerCompatibleApi: isClaw,\n debuggerMcpMetadata: isClaw,\n };\n}\n","/**\r\n * DebugHub - 全局多 Agent 调试中心\r\n *\r\n * 职责:\r\n * - 管理所有 Agent 的注册和注销\r\n * - 连接到独立的 Viewer Worker UDS 服务器\r\n * - 路由 Agent 消息到 Worker\r\n *\r\n * 设计原则:\r\n * - 单例模式,全局唯一\r\n * - 轻量:只做路由,不存储消息\r\n * - 直观:API 简单明了\r\n */\r\n\r\nimport { connect, Socket } from 'net';\r\nimport {\r\n getDefaultUDSPath,\r\n type Message,\r\n type Tool,\r\n type AgentInfo,\r\n type DebugHubIPCMessage,\r\n type Notification,\r\n type RequestInputMsg,\r\n type HookInspectorSnapshot,\r\n type AgentOverviewSnapshot,\r\n type UserInputRequest,\r\n type UserInputResponse,\r\n type UserInputAction,\r\n} from './types.js';\r\nimport { ClawDebugClient } from './claw-debug-client.js';\r\nimport { getClawRuntimeUrl, resolveDebugTransportMode } from './debug-transport.js';\r\nimport { getDebugCapabilities, type DebugCapabilities } from './debug-capabilities.js';\r\n\r\n// 前向声明 Agent 类型(避免循环依赖)\r\ntype Agent = any;\r\n\r\n/**\r\n * Hub 内部存储的 Agent 数据\r\n */\r\ninterface AgentData {\r\n info: AgentInfo;\r\n agent: Agent;\r\n}\r\n\r\nexport class DebugHub {\r\n private static instance: DebugHub;\r\n private readonly transportMode: 'viewer-worker' | 'claw';\r\n private readonly clawClient?: ClawDebugClient;\r\n\r\n // ========== 状态 ==========\r\n private agents: Map<string, AgentData> = new Map();\r\n private currentAgentId: string | null = null;\r\n private nextId: number = 1;\r\n private readonly processId: string; // 进程唯一标识\r\n\r\n // 输入请求回调映射:requestId → resolver\r\n private pendingInputRequests = new Map<string, (response: UserInputResponse) => void>();\r\n\r\n // 活跃的输入请求元数据(用于重连恢复):agentId → requestInfo\r\n private activeInputRequests = new Map<string, {\r\n requestId: string;\r\n prompt: string;\r\n placeholder?: string;\r\n initialValue?: string;\r\n actions?: UserInputAction[];\r\n timestamp: number;\r\n }>();\r\n\r\n // UDS 客户端连接\r\n private udsClient?: Socket;\r\n private udsPath: string;\r\n private workerPort: number | null = null;\r\n private clientReady: boolean = false;\r\n\r\n // 注册锁(防止并发竞争)\r\n private registrationLock: boolean = false;\r\n\r\n // 待发送的消息队列(连接建立前)\r\n private messageQueue: DebugHubIPCMessage[] = [];\r\n\r\n // 重连机制\r\n private reconnectTimer?: NodeJS.Timeout;\r\n private reconnectAttempts: number = 0;\r\n private readonly MAX_RECONNECT_ATTEMPTS = 10;\r\n private readonly RECONNECT_DELAY = 2000;\r\n\r\n // 缓存每个 Agent 的 featureTemplates(用于重连后重新注册)\r\n private agentFeatureTemplates: Map<string, Record<string, string>> = new Map();\r\n\r\n // ========== 单例 ==========\r\n private constructor() {\r\n this.udsPath = process.env.AGENTDEV_UDS_PATH || getDefaultUDSPath();\r\n // 使用进程 PID 作为唯一标识,确保多进程环境下 Agent ID 不冲突\r\n this.processId = String(process.pid);\r\n this.transportMode = resolveDebugTransportMode();\r\n if (this.transportMode === 'claw') {\r\n this.clawClient = new ClawDebugClient({\r\n processId: this.processId,\r\n projectRoot: process.cwd(),\r\n });\r\n }\r\n }\r\n\r\n static getInstance(): DebugHub {\r\n if (!DebugHub.instance) {\r\n DebugHub.instance = new DebugHub();\r\n }\r\n return DebugHub.instance;\r\n }\r\n\r\n // ========== 公开 API ==========\r\n\r\n /**\r\n * 启动调试服务器\r\n * @param port HTTP 端口(默认 2026,仅用于显示)\r\n * @param openBrowser 是否自动打开浏览器(默认 true,已废弃参数)\r\n */\r\n async start(port: number = 2026, openBrowser: boolean = true): Promise<void> {\r\n if (this.transportMode === 'claw') {\r\n this.workerPort = port;\r\n try {\r\n await this.clawClient?.ping();\r\n this.clientReady = true;\r\n console.log(`[DebugHub] 已连接到 Claw runtime: ${getClawRuntimeUrl()}`);\r\n } catch (err) {\r\n console.warn(`[DebugHub] 无法连接到 Claw runtime: ${(err as Error).message}`);\r\n console.warn('[DebugHub] 调试功能将被禁用。请先启动 AgentDevClaw runtime。');\r\n this.clientReady = false;\r\n }\r\n return;\r\n }\r\n\r\n if (this.udsClient) {\r\n console.log(`[DebugHub] 已连接到 ViewerWorker`);\r\n return;\r\n }\r\n\r\n this.workerPort = port; // 保留用于信息显示\r\n this.openBrowser = openBrowser; // 保存浏览器打开设置\r\n \r\n try {\r\n await this.connectToWorker();\r\n console.log(`[DebugHub] 调试服务器已连接: http://localhost:${port}`);\r\n } catch (err) {\r\n // 连接失败,尝试自动启动 ViewerWorker\r\n console.log(`[DebugHub] ViewerWorker 未运行,正在自动启动...`);\r\n try {\r\n await this.spawnViewerWorker();\r\n // 等待服务器启动\r\n await new Promise(resolve => setTimeout(resolve, 1000));\r\n // 再次尝试连接\r\n await this.connectToWorker();\r\n console.log(`[DebugHub] 调试服务器已连接: http://localhost:${port}`);\r\n } catch (spawnErr) {\r\n console.warn(`[DebugHub] 无法启动 ViewerWorker: ${(spawnErr as Error).message}`);\r\n console.warn(`[DebugHub] 调试功能将被禁用。请手动运行 'agentdev-viewer' 启动调试服务器。`);\r\n this.clientReady = false;\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * 自动启动 ViewerWorker 进程\r\n */\r\n private openBrowser: boolean = true;\r\n private viewerWorkerProcess?: ReturnType<typeof import('child_process').spawn>;\r\n\r\n private async spawnViewerWorker(): Promise<void> {\r\n const { spawn } = await import('child_process');\r\n const { existsSync } = await import('fs');\r\n const { fileURLToPath } = await import('url');\r\n const { dirname, join } = await import('path');\r\n\r\n // 查找 viewer.js 的路径\r\n let viewerPath: string;\r\n\r\n // 方式1: 优先使用 require.resolve(最可靠)\r\n try {\r\n const agentdevPath = require.resolve('agentdev/package.json');\r\n viewerPath = join(dirname(agentdevPath), 'dist', 'cli', 'viewer.js');\r\n } catch {\r\n // 方式2: 从当前模块解析\r\n try {\r\n const currentDir = dirname(fileURLToPath(import.meta.url));\r\n viewerPath = join(currentDir, '..', 'cli', 'viewer.js');\r\n } catch {\r\n // 方式3: 使用 bin 命令\r\n viewerPath = 'agentdev-viewer';\r\n }\r\n }\r\n\r\n // 验证文件存在\r\n if (viewerPath !== 'agentdev-viewer' && !existsSync(viewerPath)) {\r\n // 回退到 bin 命令\r\n viewerPath = 'agentdev-viewer';\r\n }\r\n\r\n return new Promise((resolve, reject) => {\r\n try {\r\n // 设置环境变量\r\n const env = {\r\n ...process.env,\r\n AGENTDEV_PORT: String(this.workerPort || 2026),\r\n AGENTDEV_OPEN_BROWSER: this.openBrowser ? 'true' : 'false',\r\n AGENTDEV_UDS_PATH: this.udsPath,\r\n };\r\n\r\n console.log(`[DebugHub] 启动 ViewerWorker: ${viewerPath}`);\r\n\r\n // 如果是 bin 命令,直接运行命令;否则用 node 执行\r\n const isBinCommand = viewerPath === 'agentdev-viewer' || viewerPath === 'agentdev-server';\r\n const command = isBinCommand ? viewerPath : 'node';\r\n const args = isBinCommand ? [] : [viewerPath];\r\n\r\n this.viewerWorkerProcess = spawn(command, args, {\r\n env,\r\n stdio: ['ignore', 'pipe', 'pipe'],\r\n detached: false,\r\n shell: isBinCommand, // bin 命令需要 shell 来解析\r\n });\r\n\r\n this.viewerWorkerProcess.on('error', (err: Error) => {\r\n console.error('[DebugHub] ViewerWorker 进程错误:', err.message);\r\n reject(err);\r\n });\r\n\r\n // 输出 ViewerWorker 的日志\r\n this.viewerWorkerProcess.stdout?.on('data', (data: Buffer) => {\r\n const lines = data.toString().trim().split('\\n');\r\n for (const line of lines) {\r\n console.log(`[ViewerWorker] ${line}`);\r\n }\r\n });\r\n\r\n this.viewerWorkerProcess.stderr?.on('data', (data: Buffer) => {\r\n const lines = data.toString().trim().split('\\n');\r\n for (const line of lines) {\r\n console.error(`[ViewerWorker] ${line}`);\r\n }\r\n });\r\n\r\n // 给进程一点时间启动\r\n setTimeout(() => {\r\n if (this.viewerWorkerProcess && !this.viewerWorkerProcess.killed) {\r\n resolve();\r\n } else {\r\n reject(new Error('ViewerWorker 进程启动失败'));\r\n }\r\n }, 500);\r\n } catch (err) {\r\n reject(err);\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * 停止调试服务器\r\n */\r\n stop(): void {\r\n if (this.transportMode === 'claw') {\r\n this.clientReady = false;\r\n return;\r\n }\r\n\r\n // 停止重连定时器\r\n if (this.reconnectTimer) {\r\n clearTimeout(this.reconnectTimer);\r\n this.reconnectTimer = undefined;\r\n }\r\n\r\n if (this.udsClient) {\r\n this.sendToWorker({ type: 'stop' });\r\n this.udsClient.end();\r\n this.udsClient = undefined;\r\n this.clientReady = false;\r\n }\r\n }\r\n\r\n /**\r\n * 手动重连(可选)\r\n * 如果已经连接,则不执行任何操作\r\n */\r\n async reconnect(): Promise<void> {\r\n if (this.transportMode === 'claw') {\r\n await this.start(this.workerPort ?? 2026, false);\r\n if (!this.clientReady) {\r\n throw new Error('Claw runtime reconnect failed');\r\n }\r\n return;\r\n }\r\n\r\n if (this.clientReady && this.udsClient) {\r\n console.log('[DebugHub] 已经连接,无需重连');\r\n return;\r\n }\r\n\r\n // 重置重连状态\r\n this.reconnectAttempts = 0;\r\n if (this.reconnectTimer) {\r\n clearTimeout(this.reconnectTimer);\r\n this.reconnectTimer = undefined;\r\n }\r\n\r\n try {\r\n await this.connectToWorker();\r\n console.log('[DebugHub] ✅ 手动重连成功');\r\n } catch (error) {\r\n console.error(`[DebugHub] 手动重连失败: ${(error as Error).message}`);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * 注册 Agent\r\n * @param agent Agent 实例\r\n * @param name 显示名称(可选,默认使用类名)\r\n * @param featureTemplates Feature 模板路径映射(可选)\r\n * @returns 分配的 agentId\r\n */\r\n registerAgent(\r\n agent: Agent,\r\n name?: string,\r\n featureTemplates?: Record<string, string>,\r\n hookInspector?: HookInspectorSnapshot,\r\n overview?: AgentOverviewSnapshot\r\n ): string {\r\n // 等待注册锁\r\n while (this.registrationLock) {\r\n // 简单的忙等待(实际场景中竞争很少)\r\n }\r\n this.registrationLock = true;\r\n\r\n try {\r\n const id = `agent-${this.nextId++}-${this.processId}`;\r\n const info: AgentInfo = {\r\n id,\r\n name: name || agent.constructor.name,\r\n registeredAt: Date.now(),\r\n };\r\n\r\n this.agents.set(id, { info, agent });\r\n\r\n // 缓存 featureTemplates(用于重连后重新注册)\r\n if (featureTemplates) {\r\n this.agentFeatureTemplates.set(id, featureTemplates);\r\n }\r\n\r\n // 首个注册的 Agent 自动成为当前 Agent\r\n if (this.agents.size === 1) {\r\n this.currentAgentId = id;\r\n }\r\n\r\n // 通知 Worker\r\n if (this.transportMode === 'claw') {\r\n void this.clawClient?.registerAgent({\r\n agentId: id,\r\n name: info.name,\r\n projectRoot: process.cwd(),\r\n featureTemplates,\r\n hookInspector,\r\n overview,\r\n }).catch(error => {\r\n console.error(`[DebugHub] Claw registerAgent 失败: ${(error as Error).message}`);\r\n });\r\n } else {\r\n this.sendToWorker({\r\n type: 'register-agent',\r\n agentId: id,\r\n name: info.name,\r\n createdAt: info.registeredAt,\r\n projectRoot: process.cwd(), // 传递项目根目录,用于模板文件加载\r\n featureTemplates, // 传递 Feature 模板路径映射\r\n hookInspector,\r\n overview,\r\n });\r\n }\r\n\r\n console.log(`[DebugHub] Agent 已注册: ${id} (${info.name})`);\r\n return id;\r\n } finally {\r\n this.registrationLock = false;\r\n }\r\n }\r\n\r\n /**\r\n * 注销 Agent\r\n * @param agentId Agent ID\r\n */\r\n unregisterAgent(agentId: string): void {\r\n const deleted = this.agents.delete(agentId);\r\n if (deleted) {\r\n if (this.transportMode === 'claw') {\r\n void this.clawClient?.unregisterAgent(agentId).catch(error => {\r\n console.error(`[DebugHub] Claw unregisterAgent 失败: ${(error as Error).message}`);\r\n });\r\n } else {\r\n this.sendToWorker({ type: 'unregister-agent', agentId });\r\n }\r\n console.log(`[DebugHub] Agent 已注销: ${agentId}`);\r\n\r\n // 如果注销的是当前 Agent,切换到另一个\r\n if (this.currentAgentId === agentId) {\r\n const remaining = Array.from(this.agents.keys());\r\n this.currentAgentId = remaining.length > 0 ? remaining[0] : null;\r\n if (this.currentAgentId) {\r\n if (this.transportMode === 'claw') {\r\n void this.clawClient?.selectAgent(this.currentAgentId).catch(error => {\r\n console.error(`[DebugHub] Claw selectAgent 失败: ${(error as Error).message}`);\r\n });\r\n } else if (this.transportMode === 'viewer-worker') {\r\n this.sendToWorker({\r\n type: 'set-current-agent',\r\n agentId: this.currentAgentId,\r\n });\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * 切换当前选中的 Agent\r\n * @param agentId Agent ID\r\n * @returns 是否成功\r\n */\r\n selectAgent(agentId: string): boolean {\r\n if (!this.agents.has(agentId)) {\r\n return false;\r\n }\r\n this.currentAgentId = agentId;\r\n if (this.transportMode === 'claw') {\r\n void this.clawClient?.selectAgent(agentId).catch(error => {\r\n console.error(`[DebugHub] Claw selectAgent 失败: ${(error as Error).message}`);\r\n });\r\n console.log(`[DebugHub] 当前 Agent 已切换: ${agentId}`);\r\n return true;\r\n }\r\n if (this.transportMode === 'viewer-worker') {\r\n this.sendToWorker({\r\n type: 'set-current-agent',\r\n agentId,\r\n });\r\n }\r\n console.log(`[DebugHub] 当前 Agent 已切换: ${agentId}`);\r\n return true;\r\n }\r\n\r\n /**\r\n * 推送 Agent 消息\r\n * @param agentId Agent ID\r\n * @param messages 消息数组\r\n */\r\n pushMessages(agentId: string, messages: Message[]): void {\r\n if (this.transportMode === 'claw') {\r\n void this.clawClient?.pushMessages(agentId, messages).catch(error => {\r\n console.error(`[DebugHub] Claw pushMessages 失败: ${(error as Error).message}`);\r\n });\r\n return;\r\n }\r\n\r\n this.sendToWorker({\r\n type: 'push-messages',\r\n agentId,\r\n messages,\r\n });\r\n }\r\n\r\n /**\r\n * 注册 Agent 工具\r\n * @param agentId Agent ID\r\n * @param tools 工具数组\r\n */\r\n registerAgentTools(agentId: string, tools: Tool[]): void {\r\n if (this.transportMode === 'claw') {\r\n void this.clawClient?.registerTools(agentId, tools).catch(error => {\r\n console.error(`[DebugHub] Claw registerTools 失败: ${(error as Error).message}`);\r\n });\r\n return;\r\n }\r\n\r\n this.sendToWorker({\r\n type: 'register-tools',\r\n agentId,\r\n tools,\r\n });\r\n }\r\n\r\n updateAgentInspector(agentId: string, hookInspector: HookInspectorSnapshot): void {\r\n if (this.transportMode === 'claw') {\r\n void this.clawClient?.updateInspector(agentId, hookInspector).catch(error => {\r\n console.error(`[DebugHub] Claw updateInspector 失败: ${(error as Error).message}`);\r\n });\r\n return;\r\n }\r\n\r\n this.sendToWorker({\r\n type: 'update-agent-inspector',\r\n agentId,\r\n hookInspector,\r\n });\r\n }\r\n\r\n updateAgentOverview(agentId: string, overview: AgentOverviewSnapshot): void {\r\n if (this.transportMode === 'claw') {\r\n void this.clawClient?.updateOverview(agentId, overview).catch(error => {\r\n console.error(`[DebugHub] Claw updateOverview 失败: ${(error as Error).message}`);\r\n });\r\n return;\r\n }\r\n\r\n this.sendToWorker({\r\n type: 'update-agent-overview',\r\n agentId,\r\n overview,\r\n });\r\n }\r\n\r\n /**\r\n * 获取所有已注册的 Agent 信息\r\n */\r\n getAgentList(): AgentInfo[] {\r\n return Array.from(this.agents.values()).map(v => v.info);\r\n }\r\n\r\n /**\r\n * 获取当前选中的 Agent ID\r\n */\r\n getCurrentAgentId(): string | null {\r\n return this.currentAgentId;\r\n }\r\n\r\n getTransportMode(): 'viewer-worker' | 'claw' {\r\n return this.transportMode;\r\n }\r\n\r\n getCapabilities(): DebugCapabilities {\r\n return getDebugCapabilities();\r\n }\r\n\r\n /**\r\n * 根据 Agent 实例获取其 ID\r\n */\r\n getAgentId(agent: Agent): string | undefined {\r\n for (const [id, data] of this.agents) {\r\n if (data.agent === agent) {\r\n return id;\r\n }\r\n }\r\n return undefined;\r\n }\r\n\r\n /**\r\n * 获取 Worker 端口\r\n */\r\n getPort(): number | null {\r\n return this.workerPort;\r\n }\r\n\r\n /**\r\n * 检查是否已连接到 ViewerWorker\r\n */\r\n isConnected(): boolean {\r\n if (this.transportMode === 'claw') {\r\n return this.clientReady;\r\n }\r\n return this.clientReady && !!this.udsClient;\r\n }\r\n\r\n /**\r\n * 推送通知\r\n * @param agentId Agent ID\r\n * @param notification 通知对象\r\n */\r\n pushNotification(agentId: string, notification: Notification): void {\r\n if (this.transportMode === 'claw') {\r\n void this.clawClient?.pushNotification(agentId, notification).catch(error => {\r\n console.error(`[DebugHub] Claw pushNotification 失败: ${(error as Error).message}`);\r\n });\r\n return;\r\n }\r\n\r\n this.sendToWorker({\r\n type: 'push-notification',\r\n agentId,\r\n notification,\r\n });\r\n }\r\n\r\n /**\r\n * 请求用户输入\r\n * @param agentId Agent ID\r\n * @param prompt 提示信息\r\n * @param timeout 超时时间(毫秒),默认 Infinity(无限等待)\r\n * @returns Promise<string> 用户输入内容\r\n */\r\n requestUserInput(agentId: string, prompt: string, timeout: number = Infinity): Promise<string> {\r\n return this.requestUserInputEvent(agentId, { prompt }, timeout).then((response) => {\r\n if (response.kind !== 'text') {\r\n throw new Error(`Expected text user input but received action '${response.actionId ?? 'unknown'}'`);\r\n }\r\n return response.text ?? '';\r\n });\r\n }\r\n\r\n requestUserInputEvent(\r\n agentId: string,\r\n request: UserInputRequest,\r\n timeout: number = Infinity,\r\n ): Promise<UserInputResponse> {\r\n if (this.transportMode === 'claw') {\r\n return this.clawClient?.requestUserInput(agentId, request, timeout)\r\n ?? Promise.reject(new Error('Claw client is not available'));\r\n }\r\n\r\n const requestId = `input-${agentId}-${Date.now()}-${Math.random().toString(36).slice(2)}`;\r\n\r\n return new Promise((resolve, reject) => {\r\n // 设置超时定时器(仅在 timeout 为有限数值时)\r\n let timer: NodeJS.Timeout | undefined;\r\n if (timeout !== Infinity) {\r\n timer = setTimeout(() => {\r\n this.pendingInputRequests.delete(requestId);\r\n this.activeInputRequests.delete(agentId); // 清除活跃请求记录\r\n reject(new Error(`User input timeout after ${timeout}ms`));\r\n }, timeout);\r\n }\r\n\r\n // 存储 resolve 函数\r\n this.pendingInputRequests.set(requestId, (response: UserInputResponse) => {\r\n if (timer) clearTimeout(timer);\r\n this.activeInputRequests.delete(agentId); // 清除活跃请求记录\r\n resolve(response);\r\n });\r\n\r\n // 记录活跃请求(用于重连恢复)\r\n this.activeInputRequests.set(agentId, {\r\n requestId,\r\n prompt: request.prompt,\r\n placeholder: request.placeholder,\r\n initialValue: request.initialValue,\r\n actions: request.actions,\r\n timestamp: Date.now(),\r\n });\r\n\r\n // 发送请求到 ViewerWorker\r\n this.sendToWorker({\r\n type: 'request-input',\r\n agentId,\r\n requestId,\r\n prompt: request.prompt,\r\n placeholder: request.placeholder,\r\n initialValue: request.initialValue,\r\n actions: request.actions,\r\n timeout,\r\n } as RequestInputMsg);\r\n });\r\n }\r\n\r\n // ========== 内部方法 ==========\r\n\r\n /**\r\n * 连接到 UDS 服务器\r\n */\r\n private async connectToWorker(): Promise<void> {\r\n return new Promise((resolve, reject) => {\r\n this.udsClient = connect(this.udsPath);\r\n\r\n this.udsClient.on('connect', () => {\r\n this.clientReady = true;\r\n this.reconnectAttempts = 0; // 重置重连计数\r\n console.log(`[DebugHub] 已连接到 ViewerWorker: ${this.udsPath}`);\r\n\r\n // 发送队列中的消息\r\n for (const msg of this.messageQueue) {\r\n this.sendViaUDS(msg);\r\n }\r\n this.messageQueue = [];\r\n\r\n // 关键:重新注册所有 Agent(用于重连后恢复状态)\r\n this.reregisterAllAgents();\r\n\r\n // 设置当前 Agent\r\n if (this.currentAgentId) {\r\n this.sendToWorker({\r\n type: 'set-current-agent',\r\n agentId: this.currentAgentId,\r\n });\r\n }\r\n\r\n resolve();\r\n });\r\n\r\n this.udsClient.on('data', (data: Buffer) => {\r\n const lines = data.toString().split('\\n');\r\n for (const line of lines) {\r\n if (!line.trim()) continue;\r\n try {\r\n const msg = JSON.parse(line);\r\n this.handleWorkerMessage(msg);\r\n } catch (err) {\r\n console.error('[DebugHub] Worker 消息解析失败:', err);\r\n }\r\n }\r\n });\r\n\r\n this.udsClient.on('error', (err: Error) => {\r\n reject(new Error(`连接 ViewerWorker 失败 (${this.udsPath}): ${err.message}\\n请先启动 ViewerWorker 服务器`));\r\n });\r\n\r\n this.udsClient.on('close', () => {\r\n this.clientReady = false;\r\n console.warn('[DebugHub] 与 ViewerWorker 的连接已断开');\r\n\r\n // 自动重连\r\n this.scheduleReconnect();\r\n });\r\n });\r\n }\r\n\r\n /**\r\n * 处理来自 Worker 的消息\r\n */\r\n private handleWorkerMessage(msg: any): void {\r\n switch (msg.type) {\r\n case 'agent-switched':\r\n console.log(`[DebugHub] 当前 Agent 已切换: ${msg.agentId}`);\r\n break;\r\n\r\n // 处理用户输入响应\r\n case 'input-response':\r\n const resolver = this.pendingInputRequests.get(msg.requestId);\r\n if (resolver) {\r\n resolver(msg.response ?? {\r\n kind: 'text',\r\n text: msg.input,\r\n });\r\n this.pendingInputRequests.delete(msg.requestId);\r\n } else {\r\n console.warn(`[DebugHub] 未知输入响应: ${msg.requestId}`);\r\n }\r\n break;\r\n }\r\n }\r\n\r\n /**\r\n * 重新注册所有 Agent(重连后调用)\r\n * 确保 ViewerWorker 能够恢复所有 Agent 的注册信息\r\n */\r\n private reregisterAllAgents(): void {\r\n if (this.transportMode === 'claw') {\r\n for (const [id, data] of this.agents) {\r\n const hookInspector = (data.agent as any).buildHookInspectorSnapshot?.()\r\n || (data.agent as any).hookInspector;\r\n const overview = (data.agent as any).buildOverviewSnapshot?.();\r\n const featureTemplates = this.agentFeatureTemplates.get(id) || {};\r\n\r\n void this.clawClient?.registerAgent({\r\n agentId: id,\r\n name: data.info.name,\r\n projectRoot: process.cwd(),\r\n featureTemplates,\r\n hookInspector,\r\n overview,\r\n }).then(async () => {\r\n const tools = (data.agent as any).tools;\r\n if (tools && typeof tools.getEntries === 'function') {\r\n const entries = tools.getEntries();\r\n const toolList = entries.map((e: any) => e.tool);\r\n if (toolList.length > 0) {\r\n await this.clawClient?.registerTools(id, toolList);\r\n }\r\n }\r\n\r\n const context = (data.agent as any).getContext?.();\r\n if (context && typeof context.getAll === 'function') {\r\n const messages = context.getAll();\r\n if (messages.length > 0) {\r\n await this.clawClient?.pushMessages(id, messages);\r\n }\r\n }\r\n }).catch(error => {\r\n console.error(`[DebugHub] Claw re-register 失败: ${(error as Error).message}`);\r\n });\r\n }\r\n return;\r\n }\r\n\r\n if (this.agents.size === 0) {\r\n return;\r\n }\r\n\r\n console.log(`[DebugHub] 重新注册 ${this.agents.size} 个 Agent...`);\r\n\r\n for (const [id, data] of this.agents) {\r\n // 获取最新的 hookInspector\r\n const hookInspector = (data.agent as any).buildHookInspectorSnapshot?.()\r\n || (data.agent as any).hookInspector;\r\n const overview = (data.agent as any).buildOverviewSnapshot?.();\r\n\r\n // 获取缓存的 featureTemplates\r\n const featureTemplates = this.agentFeatureTemplates.get(id) || {};\r\n\r\n // 获取活跃的输入请求(用于恢复输入框)\r\n const activeInputRequest = this.activeInputRequests.get(id);\r\n if (activeInputRequest) {\r\n console.log(`[DebugHub] 发现活跃输入请求: ${activeInputRequest.requestId}`);\r\n }\r\n\r\n this.sendToWorker({\r\n type: 'register-agent' as const,\r\n agentId: id,\r\n name: data.info.name,\r\n createdAt: data.info.registeredAt,\r\n projectRoot: process.cwd(),\r\n featureTemplates,\r\n hookInspector,\r\n overview,\r\n activeInputRequest, // 携带活跃输入请求\r\n });\r\n\r\n // 重新注册工具(如果有)\r\n const tools = (data.agent as any).tools;\r\n if (tools && typeof tools.getEntries === 'function') {\r\n const entries = tools.getEntries();\r\n const toolList = entries.map((e: any) => e.tool);\r\n if (toolList.length > 0) {\r\n this.sendToWorker({\r\n type: 'register-tools',\r\n agentId: id,\r\n tools: toolList,\r\n });\r\n }\r\n }\r\n\r\n // 重新发送对话记录(用于重连后恢复消息历史)\r\n const context = (data.agent as any).getContext?.();\r\n if (context && typeof context.getAll === 'function') {\r\n const messages = context.getAll();\r\n if (messages.length > 0) {\r\n this.sendToWorker({\r\n type: 'push-messages',\r\n agentId: id,\r\n messages,\r\n });\r\n console.log(`[DebugHub] 恢复 Agent ${id} 的 ${messages.length} 条消息`);\r\n }\r\n }\r\n }\r\n\r\n console.log(`[DebugHub] ✅ 重新注册完成`);\r\n }\r\n\r\n /**\r\n * 安排重连(指数退避)\r\n */\r\n private scheduleReconnect(): void {\r\n // 清除现有的定时器\r\n if (this.reconnectTimer) {\r\n clearTimeout(this.reconnectTimer);\r\n }\r\n\r\n // 检查是否达到最大重连次数\r\n if (this.reconnectAttempts >= this.MAX_RECONNECT_ATTEMPTS) {\r\n console.error(`[DebugHub] 达到最大重连次数 (${this.MAX_RECONNECT_ATTEMPTS}),停止重连`);\r\n return;\r\n }\r\n\r\n this.reconnectAttempts++;\r\n\r\n // 计算延迟时间(指数退避,最大 30 秒)\r\n const delay = Math.min(\r\n this.RECONNECT_DELAY * Math.pow(2, this.reconnectAttempts - 1),\r\n 30000\r\n );\r\n\r\n console.log(`[DebugHub] ${delay}ms 后尝试第 ${this.reconnectAttempts} 次重连...`);\r\n\r\n this.reconnectTimer = setTimeout(async () => {\r\n try {\r\n await this.connectToWorker();\r\n console.log('[DebugHub] ✅ 重连成功,调试功能已恢复');\r\n } catch (error) {\r\n console.error(`[DebugHub] 重连失败: ${(error as Error).message}`);\r\n // 继续尝试重连\r\n this.scheduleReconnect();\r\n }\r\n }, delay);\r\n }\r\n\r\n /**\r\n * 通过 UDS 发送消息\r\n */\r\n private sendViaUDS(msg: DebugHubIPCMessage): void {\r\n if (this.udsClient && this.clientReady) {\r\n this.udsClient.write(JSON.stringify(msg) + '\\n');\r\n }\r\n // 未连接时丢弃消息,不再队列(避免内存泄漏)\r\n }\r\n\r\n /**\r\n * 发送消息到 Worker\r\n */\r\n private sendToWorker(msg: DebugHubIPCMessage): void {\r\n if (!this.udsClient) {\r\n return;\r\n }\r\n this.sendViaUDS(msg);\r\n }\r\n}\r\n","import type {\n AgentOverviewSnapshot,\n HookInspectorSnapshot,\n Message,\n Notification,\n Tool,\n UserInputRequest,\n UserInputResponse,\n} from './types.js';\nimport { getClawRuntimeUrl } from './debug-transport.js';\n\ntype ClawEventKind =\n | 'message'\n | 'notification'\n | 'snapshot'\n | 'lifecycle'\n | 'tools'\n | 'input';\n\ninterface ClawSessionRegistration {\n sessionId: string;\n runtime: 'agentdev';\n agentName: string;\n projectRoot: string | null;\n metadata: Record<string, unknown>;\n state?: Record<string, unknown>;\n}\n\ninterface ClawEventInput {\n sessionId: string;\n kind: ClawEventKind;\n payload: Record<string, unknown>;\n}\n\nexport interface RegisterClawAgentInput {\n agentId: string;\n name: string;\n projectRoot?: string;\n featureTemplates?: Record<string, string>;\n hookInspector?: HookInspectorSnapshot;\n overview?: AgentOverviewSnapshot;\n}\n\nexport class ClawDebugClient {\n private readonly runtimeUrl: string;\n private readonly processId: string;\n private readonly projectRoot: string;\n private readonly sessionByAgentId = new Map<string, string>();\n private readonly pendingSessionByAgentId = new Map<string, Promise<string>>();\n\n constructor(options: { runtimeUrl?: string; processId?: string; projectRoot?: string } = {}) {\n this.runtimeUrl = (options.runtimeUrl ?? getClawRuntimeUrl()).replace(/\\/$/, '');\n this.processId = options.processId ?? String(process.pid);\n this.projectRoot = options.projectRoot ?? process.cwd();\n }\n\n async ping(): Promise<void> {\n await this.requestJson('/health');\n }\n\n async registerAgent(input: RegisterClawAgentInput): Promise<string> {\n const sessionId = `${this.processId}:${input.agentId}`;\n const existing = this.pendingSessionByAgentId.get(input.agentId);\n if (existing) {\n return existing;\n }\n\n const pending = (async () => {\n const registration: ClawSessionRegistration = {\n sessionId,\n runtime: 'agentdev',\n agentName: input.name,\n projectRoot: input.projectRoot ?? this.projectRoot,\n metadata: {\n adapter: 'agentdev-debug-hub',\n agentId: input.agentId,\n featureTemplates: input.featureTemplates ?? {},\n },\n state: {\n hookInspector: input.hookInspector ?? null,\n overview: input.overview ?? null,\n },\n };\n\n await this.requestJson('/api/sessions/register', {\n method: 'POST',\n body: JSON.stringify(registration),\n });\n\n this.sessionByAgentId.set(input.agentId, sessionId);\n\n await this.pushLifecycle(input.agentId, {\n phase: 'agent-registered',\n agentId: input.agentId,\n name: input.name,\n });\n\n return sessionId;\n })();\n\n this.pendingSessionByAgentId.set(input.agentId, pending);\n\n try {\n return await pending;\n } finally {\n this.pendingSessionByAgentId.delete(input.agentId);\n }\n }\n\n async unregisterAgent(agentId: string): Promise<void> {\n await this.pushLifecycle(agentId, {\n phase: 'agent-unregistered',\n agentId,\n });\n }\n\n async selectAgent(agentId: string): Promise<void> {\n const sessionId = await this.requireSessionId(agentId);\n await this.requestJson('/api/agents/current', {\n method: 'PUT',\n body: JSON.stringify({ agentId: sessionId }),\n });\n }\n\n async pushMessages(agentId: string, messages: Message[]): Promise<void> {\n await this.pushEvent(agentId, 'message', { messages });\n }\n\n async registerTools(agentId: string, tools: Tool[]): Promise<void> {\n await this.pushEvent(agentId, 'tools', { tools });\n }\n\n async updateInspector(agentId: string, hookInspector: HookInspectorSnapshot): Promise<void> {\n await this.pushEvent(agentId, 'snapshot', {\n scope: 'hookInspector',\n hookInspector,\n });\n }\n\n async updateOverview(agentId: string, overview: AgentOverviewSnapshot): Promise<void> {\n await this.pushEvent(agentId, 'snapshot', {\n scope: 'overview',\n overview,\n });\n }\n\n async pushNotification(agentId: string, notification: Notification): Promise<void> {\n await this.pushEvent(agentId, 'notification', { notification });\n }\n\n async requestUserInput(_agentId: string, request: UserInputRequest, timeout: number): Promise<UserInputResponse> {\n const agentId = _agentId;\n const requestId = `input-${agentId}-${Date.now()}-${Math.random().toString(36).slice(2)}`;\n await this.pushEvent(agentId, 'input', {\n requestId,\n request,\n timeout,\n status: 'pending',\n });\n\n const sessionId = await this.requireSessionId(agentId);\n const startedAt = Date.now();\n const pollIntervalMs = 400;\n\n while (true) {\n if (timeout !== Infinity && Date.now() - startedAt > timeout) {\n throw new Error(`User input timeout after ${timeout}ms`);\n }\n\n let response: Response;\n try {\n response = await fetch(\n `${this.runtimeUrl}/api/agents/${encodeURIComponent(sessionId)}/input-response?requestId=${encodeURIComponent(requestId)}`\n );\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Unable to reach Claw runtime at ${this.runtimeUrl} while waiting for user input: ${message}`);\n }\n\n if (response.ok) {\n const body = await response.json();\n return body.response;\n }\n\n if (response.status !== 404) {\n const text = await response.text();\n throw new Error(`Input bridge request failed: ${response.status} ${response.statusText} ${text}`);\n }\n\n await new Promise(resolve => setTimeout(resolve, pollIntervalMs));\n }\n }\n\n private async pushLifecycle(agentId: string, payload: Record<string, unknown>): Promise<void> {\n await this.pushEvent(agentId, 'lifecycle', payload);\n }\n\n private async pushEvent(agentId: string, kind: ClawEventKind, payload: Record<string, unknown>): Promise<void> {\n const sessionId = await this.requireSessionId(agentId);\n const event: ClawEventInput = {\n sessionId,\n kind,\n payload,\n };\n\n await this.requestJson('/api/events', {\n method: 'POST',\n body: JSON.stringify(event),\n });\n }\n\n private async requireSessionId(agentId: string): Promise<string> {\n const sessionId = this.sessionByAgentId.get(agentId);\n if (!sessionId) {\n const pending = this.pendingSessionByAgentId.get(agentId);\n if (pending) {\n return pending;\n }\n throw new Error(`No Claw session registered for agentId '${agentId}'`);\n }\n return sessionId;\n }\n\n private async requestJson(path: string, init?: RequestInit): Promise<any> {\n let response: Response;\n try {\n response = await fetch(`${this.runtimeUrl}${path}`, {\n ...init,\n headers: {\n 'content-type': 'application/json',\n ...(init?.headers ?? {}),\n },\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Unable to reach Claw runtime at ${this.runtimeUrl}: ${message}`);\n }\n\n if (!response.ok) {\n const body = await response.text();\n throw new Error(`Claw runtime request failed: ${response.status} ${response.statusText} ${body}`);\n }\n\n if (response.status === 204) {\n return null;\n }\n\n return response.json();\n }\n}\n"],"mappings":";;;;;;;;AAEO,SAAS,4BAAgD;AAC9D,SAAO,QAAQ,IAAI,6BAA6B,SAAS,SAAS;AACpE;AAEO,SAAS,oBAA4B;AAC1C,SAAO,QAAQ,IAAI,6BAA6B;AAClD;;;ACEO,SAAS,uBAA0C;AACxD,QAAM,gBAAgB,0BAA0B;AAChD,QAAM,SAAS,kBAAkB;AAEjC,SAAO;AAAA,IACL;AAAA,IACA,kBAAkB;AAAA,IAClB,YAAY,SAAS,kBAAkB,IAAI;AAAA,IAC3C,qBAAqB;AAAA,IACrB,qBAAqB;AAAA,EACvB;AACF;;;ACPA,SAAS,eAAuB;;;AC6BzB,IAAM,kBAAN,MAAsB;AAAA,EACV;AAAA,EACA;AAAA,EACA;AAAA,EACA,mBAAmB,oBAAI,IAAoB;AAAA,EAC3C,0BAA0B,oBAAI,IAA6B;AAAA,EAE5E,YAAY,UAA6E,CAAC,GAAG;AAC3F,SAAK,cAAc,QAAQ,cAAc,kBAAkB,GAAG,QAAQ,OAAO,EAAE;AAC/E,SAAK,YAAY,QAAQ,aAAa,OAAO,QAAQ,GAAG;AACxD,SAAK,cAAc,QAAQ,eAAe,QAAQ,IAAI;AAAA,EACxD;AAAA,EAEA,MAAM,OAAsB;AAC1B,UAAM,KAAK,YAAY,SAAS;AAAA,EAClC;AAAA,EAEA,MAAM,cAAc,OAAgD;AAClE,UAAM,YAAY,GAAG,KAAK,SAAS,IAAI,MAAM,OAAO;AACpD,UAAM,WAAW,KAAK,wBAAwB,IAAI,MAAM,OAAO;AAC/D,QAAI,UAAU;AACZ,aAAO;AAAA,IACT;AAEA,UAAM,WAAW,YAAY;AAC3B,YAAM,eAAwC;AAAA,QAC5C;AAAA,QACA,SAAS;AAAA,QACT,WAAW,MAAM;AAAA,QACjB,aAAa,MAAM,eAAe,KAAK;AAAA,QACvC,UAAU;AAAA,UACR,SAAS;AAAA,UACT,SAAS,MAAM;AAAA,UACf,kBAAkB,MAAM,oBAAoB,CAAC;AAAA,QAC/C;AAAA,QACA,OAAO;AAAA,UACL,eAAe,MAAM,iBAAiB;AAAA,UACtC,UAAU,MAAM,YAAY;AAAA,QAC9B;AAAA,MACF;AAEA,YAAM,KAAK,YAAY,0BAA0B;AAAA,QAC/C,QAAQ;AAAA,QACR,MAAM,KAAK,UAAU,YAAY;AAAA,MACnC,CAAC;AAED,WAAK,iBAAiB,IAAI,MAAM,SAAS,SAAS;AAElD,YAAM,KAAK,cAAc,MAAM,SAAS;AAAA,QACtC,OAAO;AAAA,QACP,SAAS,MAAM;AAAA,QACf,MAAM,MAAM;AAAA,MACd,CAAC;AAED,aAAO;AAAA,IACT,GAAG;AAEH,SAAK,wBAAwB,IAAI,MAAM,SAAS,OAAO;AAEvD,QAAI;AACF,aAAO,MAAM;AAAA,IACf,UAAE;AACA,WAAK,wBAAwB,OAAO,MAAM,OAAO;AAAA,IACnD;AAAA,EACF;AAAA,EAEA,MAAM,gBAAgB,SAAgC;AACpD,UAAM,KAAK,cAAc,SAAS;AAAA,MAChC,OAAO;AAAA,MACP;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,YAAY,SAAgC;AAChD,UAAM,YAAY,MAAM,KAAK,iBAAiB,OAAO;AACrD,UAAM,KAAK,YAAY,uBAAuB;AAAA,MAC5C,QAAQ;AAAA,MACR,MAAM,KAAK,UAAU,EAAE,SAAS,UAAU,CAAC;AAAA,IAC7C,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,aAAa,SAAiB,UAAoC;AACtE,UAAM,KAAK,UAAU,SAAS,WAAW,EAAE,SAAS,CAAC;AAAA,EACvD;AAAA,EAEA,MAAM,cAAc,SAAiB,OAA8B;AACjE,UAAM,KAAK,UAAU,SAAS,SAAS,EAAE,MAAM,CAAC;AAAA,EAClD;AAAA,EAEA,MAAM,gBAAgB,SAAiB,eAAqD;AAC1F,UAAM,KAAK,UAAU,SAAS,YAAY;AAAA,MACxC,OAAO;AAAA,MACP;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,eAAe,SAAiB,UAAgD;AACpF,UAAM,KAAK,UAAU,SAAS,YAAY;AAAA,MACxC,OAAO;AAAA,MACP;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,iBAAiB,SAAiB,cAA2C;AACjF,UAAM,KAAK,UAAU,SAAS,gBAAgB,EAAE,aAAa,CAAC;AAAA,EAChE;AAAA,EAEA,MAAM,iBAAiB,UAAkB,SAA2B,SAA6C;AAC/G,UAAM,UAAU;AAChB,UAAM,YAAY,SAAS,OAAO,IAAI,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC,CAAC;AACvF,UAAM,KAAK,UAAU,SAAS,SAAS;AAAA,MACrC;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,IACV,CAAC;AAED,UAAM,YAAY,MAAM,KAAK,iBAAiB,OAAO;AACrD,UAAM,YAAY,KAAK,IAAI;AAC3B,UAAM,iBAAiB;AAEvB,WAAO,MAAM;AACX,UAAI,YAAY,YAAY,KAAK,IAAI,IAAI,YAAY,SAAS;AAC5D,cAAM,IAAI,MAAM,4BAA4B,OAAO,IAAI;AAAA,MACzD;AAEA,UAAI;AACJ,UAAI;AACF,mBAAW,MAAM;AAAA,UACf,GAAG,KAAK,UAAU,eAAe,mBAAmB,SAAS,CAAC,6BAA6B,mBAAmB,SAAS,CAAC;AAAA,QAC1H;AAAA,MACF,SAAS,OAAO;AACd,cAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,cAAM,IAAI,MAAM,mCAAmC,KAAK,UAAU,kCAAkC,OAAO,EAAE;AAAA,MAC/G;AAEA,UAAI,SAAS,IAAI;AACf,cAAM,OAAO,MAAM,SAAS,KAAK;AACjC,eAAO,KAAK;AAAA,MACd;AAEA,UAAI,SAAS,WAAW,KAAK;AAC3B,cAAM,OAAO,MAAM,SAAS,KAAK;AACjC,cAAM,IAAI,MAAM,gCAAgC,SAAS,MAAM,IAAI,SAAS,UAAU,IAAI,IAAI,EAAE;AAAA,MAClG;AAEA,YAAM,IAAI,QAAQ,aAAW,WAAW,SAAS,cAAc,CAAC;AAAA,IAClE;AAAA,EACF;AAAA,EAEA,MAAc,cAAc,SAAiB,SAAiD;AAC5F,UAAM,KAAK,UAAU,SAAS,aAAa,OAAO;AAAA,EACpD;AAAA,EAEA,MAAc,UAAU,SAAiB,MAAqB,SAAiD;AAC7G,UAAM,YAAY,MAAM,KAAK,iBAAiB,OAAO;AACrD,UAAM,QAAwB;AAAA,MAC5B;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,UAAM,KAAK,YAAY,eAAe;AAAA,MACpC,QAAQ;AAAA,MACR,MAAM,KAAK,UAAU,KAAK;AAAA,IAC5B,CAAC;AAAA,EACH;AAAA,EAEA,MAAc,iBAAiB,SAAkC;AAC/D,UAAM,YAAY,KAAK,iBAAiB,IAAI,OAAO;AACnD,QAAI,CAAC,WAAW;AACd,YAAM,UAAU,KAAK,wBAAwB,IAAI,OAAO;AACxD,UAAI,SAAS;AACX,eAAO;AAAA,MACT;AACA,YAAM,IAAI,MAAM,2CAA2C,OAAO,GAAG;AAAA,IACvE;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,YAAY,MAAc,MAAkC;AACxE,QAAI;AACJ,QAAI;AACF,iBAAW,MAAM,MAAM,GAAG,KAAK,UAAU,GAAG,IAAI,IAAI;AAAA,QAClD,GAAG;AAAA,QACH,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,GAAI,MAAM,WAAW,CAAC;AAAA,QACxB;AAAA,MACF,CAAC;AAAA,IACH,SAAS,OAAO;AACd,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,YAAM,IAAI,MAAM,mCAAmC,KAAK,UAAU,KAAK,OAAO,EAAE;AAAA,IAClF;AAEA,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,OAAO,MAAM,SAAS,KAAK;AACjC,YAAM,IAAI,MAAM,gCAAgC,SAAS,MAAM,IAAI,SAAS,UAAU,IAAI,IAAI,EAAE;AAAA,IAClG;AAEA,QAAI,SAAS,WAAW,KAAK;AAC3B,aAAO;AAAA,IACT;AAEA,WAAO,SAAS,KAAK;AAAA,EACvB;AACF;;;AD7MO,IAAM,WAAN,MAAM,UAAS;AAAA,EACpB,OAAe;AAAA,EACE;AAAA,EACA;AAAA;AAAA,EAGT,SAAiC,oBAAI,IAAI;AAAA,EACzC,iBAAgC;AAAA,EAChC,SAAiB;AAAA,EACR;AAAA;AAAA;AAAA,EAGT,uBAAuB,oBAAI,IAAmD;AAAA;AAAA,EAG9E,sBAAsB,oBAAI,IAO/B;AAAA;AAAA,EAGK;AAAA,EACA;AAAA,EACA,aAA4B;AAAA,EAC5B,cAAuB;AAAA;AAAA,EAGvB,mBAA4B;AAAA;AAAA,EAG5B,eAAqC,CAAC;AAAA;AAAA,EAGtC;AAAA,EACA,oBAA4B;AAAA,EACnB,yBAAyB;AAAA,EACzB,kBAAkB;AAAA;AAAA,EAG3B,wBAA6D,oBAAI,IAAI;AAAA;AAAA,EAGrE,cAAc;AACpB,SAAK,UAAU,QAAQ,IAAI,qBAAqB,kBAAkB;AAElE,SAAK,YAAY,OAAO,QAAQ,GAAG;AACnC,SAAK,gBAAgB,0BAA0B;AAC/C,QAAI,KAAK,kBAAkB,QAAQ;AACjC,WAAK,aAAa,IAAI,gBAAgB;AAAA,QACpC,WAAW,KAAK;AAAA,QAChB,aAAa,QAAQ,IAAI;AAAA,MAC3B,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,OAAO,cAAwB;AAC7B,QAAI,CAAC,UAAS,UAAU;AACtB,gBAAS,WAAW,IAAI,UAAS;AAAA,IACnC;AACA,WAAO,UAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,MAAM,OAAe,MAAM,cAAuB,MAAqB;AAC3E,QAAI,KAAK,kBAAkB,QAAQ;AACjC,WAAK,aAAa;AAClB,UAAI;AACF,cAAM,KAAK,YAAY,KAAK;AAC5B,aAAK,cAAc;AACnB,gBAAQ,IAAI,qDAAiC,kBAAkB,CAAC,EAAE;AAAA,MACpE,SAAS,KAAK;AACZ,gBAAQ,KAAK,2DAAmC,IAAc,OAAO,EAAE;AACvE,gBAAQ,KAAK,sHAAgD;AAC7D,aAAK,cAAc;AAAA,MACrB;AACA;AAAA,IACF;AAEA,QAAI,KAAK,WAAW;AAClB,cAAQ,IAAI,kDAA8B;AAC1C;AAAA,IACF;AAEA,SAAK,aAAa;AAClB,SAAK,cAAc;AAEnB,QAAI;AACF,YAAM,KAAK,gBAAgB;AAC3B,cAAQ,IAAI,iFAAyC,IAAI,EAAE;AAAA,IAC7D,SAAS,KAAK;AAEZ,cAAQ,IAAI,yFAAuC;AACnD,UAAI;AACF,cAAM,KAAK,kBAAkB;AAE7B,cAAM,IAAI,QAAQ,aAAW,WAAW,SAAS,GAAI,CAAC;AAEtD,cAAM,KAAK,gBAAgB;AAC3B,gBAAQ,IAAI,iFAAyC,IAAI,EAAE;AAAA,MAC7D,SAAS,UAAU;AACjB,gBAAQ,KAAK,qDAAkC,SAAmB,OAAO,EAAE;AAC3E,gBAAQ,KAAK,oKAAsD;AACnE,aAAK,cAAc;AAAA,MACrB;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,cAAuB;AAAA,EACvB;AAAA,EAER,MAAc,oBAAmC;AAC/C,UAAM,EAAE,MAAM,IAAI,MAAM,OAAO,eAAe;AAC9C,UAAM,EAAE,WAAW,IAAI,MAAM,OAAO,IAAI;AACxC,UAAM,EAAE,cAAc,IAAI,MAAM,OAAO,KAAK;AAC5C,UAAM,EAAE,SAAS,KAAK,IAAI,MAAM,OAAO,MAAM;AAG7C,QAAI;AAGJ,QAAI;AACF,YAAM,eAAe,UAAQ,QAAQ,uBAAuB;AAC5D,mBAAa,KAAK,QAAQ,YAAY,GAAG,QAAQ,OAAO,WAAW;AAAA,IACrE,QAAQ;AAEN,UAAI;AACF,cAAM,aAAa,QAAQ,cAAc,YAAY,GAAG,CAAC;AACzD,qBAAa,KAAK,YAAY,MAAM,OAAO,WAAW;AAAA,MACxD,QAAQ;AAEN,qBAAa;AAAA,MACf;AAAA,IACF;AAGA,QAAI,eAAe,qBAAqB,CAAC,WAAW,UAAU,GAAG;AAE/D,mBAAa;AAAA,IACf;AAEA,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAI;AAEF,cAAM,MAAM;AAAA,UACV,GAAG,QAAQ;AAAA,UACX,eAAe,OAAO,KAAK,cAAc,IAAI;AAAA,UAC7C,uBAAuB,KAAK,cAAc,SAAS;AAAA,UACnD,mBAAmB,KAAK;AAAA,QAC1B;AAEA,gBAAQ,IAAI,yCAA+B,UAAU,EAAE;AAGvD,cAAM,eAAe,eAAe,qBAAqB,eAAe;AACxE,cAAM,UAAU,eAAe,aAAa;AAC5C,cAAM,OAAO,eAAe,CAAC,IAAI,CAAC,UAAU;AAE5C,aAAK,sBAAsB,MAAM,SAAS,MAAM;AAAA,UAC9C;AAAA,UACA,OAAO,CAAC,UAAU,QAAQ,MAAM;AAAA,UAChC,UAAU;AAAA,UACV,OAAO;AAAA;AAAA,QACT,CAAC;AAED,aAAK,oBAAoB,GAAG,SAAS,CAAC,QAAe;AACnD,kBAAQ,MAAM,qDAAiC,IAAI,OAAO;AAC1D,iBAAO,GAAG;AAAA,QACZ,CAAC;AAGD,aAAK,oBAAoB,QAAQ,GAAG,QAAQ,CAAC,SAAiB;AAC5D,gBAAM,QAAQ,KAAK,SAAS,EAAE,KAAK,EAAE,MAAM,IAAI;AAC/C,qBAAW,QAAQ,OAAO;AACxB,oBAAQ,IAAI,kBAAkB,IAAI,EAAE;AAAA,UACtC;AAAA,QACF,CAAC;AAED,aAAK,oBAAoB,QAAQ,GAAG,QAAQ,CAAC,SAAiB;AAC5D,gBAAM,QAAQ,KAAK,SAAS,EAAE,KAAK,EAAE,MAAM,IAAI;AAC/C,qBAAW,QAAQ,OAAO;AACxB,oBAAQ,MAAM,kBAAkB,IAAI,EAAE;AAAA,UACxC;AAAA,QACF,CAAC;AAGD,mBAAW,MAAM;AACf,cAAI,KAAK,uBAAuB,CAAC,KAAK,oBAAoB,QAAQ;AAChE,oBAAQ;AAAA,UACV,OAAO;AACL,mBAAO,IAAI,MAAM,mDAAqB,CAAC;AAAA,UACzC;AAAA,QACF,GAAG,GAAG;AAAA,MACR,SAAS,KAAK;AACZ,eAAO,GAAG;AAAA,MACZ;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,OAAa;AACX,QAAI,KAAK,kBAAkB,QAAQ;AACjC,WAAK,cAAc;AACnB;AAAA,IACF;AAGA,QAAI,KAAK,gBAAgB;AACvB,mBAAa,KAAK,cAAc;AAChC,WAAK,iBAAiB;AAAA,IACxB;AAEA,QAAI,KAAK,WAAW;AAClB,WAAK,aAAa,EAAE,MAAM,OAAO,CAAC;AAClC,WAAK,UAAU,IAAI;AACnB,WAAK,YAAY;AACjB,WAAK,cAAc;AAAA,IACrB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,YAA2B;AAC/B,QAAI,KAAK,kBAAkB,QAAQ;AACjC,YAAM,KAAK,MAAM,KAAK,cAAc,MAAM,KAAK;AAC/C,UAAI,CAAC,KAAK,aAAa;AACrB,cAAM,IAAI,MAAM,+BAA+B;AAAA,MACjD;AACA;AAAA,IACF;AAEA,QAAI,KAAK,eAAe,KAAK,WAAW;AACtC,cAAQ,IAAI,mEAAsB;AAClC;AAAA,IACF;AAGA,SAAK,oBAAoB;AACzB,QAAI,KAAK,gBAAgB;AACvB,mBAAa,KAAK,cAAc;AAChC,WAAK,iBAAiB;AAAA,IACxB;AAEA,QAAI;AACF,YAAM,KAAK,gBAAgB;AAC3B,cAAQ,IAAI,wDAAqB;AAAA,IACnC,SAAS,OAAO;AACd,cAAQ,MAAM,oDAAuB,MAAgB,OAAO,EAAE;AAC9D,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,cACE,OACA,MACA,kBACA,eACA,UACQ;AAER,WAAO,KAAK,kBAAkB;AAAA,IAE9B;AACA,SAAK,mBAAmB;AAExB,QAAI;AACF,YAAM,KAAK,SAAS,KAAK,QAAQ,IAAI,KAAK,SAAS;AACnD,YAAM,OAAkB;AAAA,QACtB;AAAA,QACA,MAAM,QAAQ,MAAM,YAAY;AAAA,QAChC,cAAc,KAAK,IAAI;AAAA,MACzB;AAEA,WAAK,OAAO,IAAI,IAAI,EAAE,MAAM,MAAM,CAAC;AAGnC,UAAI,kBAAkB;AACpB,aAAK,sBAAsB,IAAI,IAAI,gBAAgB;AAAA,MACrD;AAGA,UAAI,KAAK,OAAO,SAAS,GAAG;AAC1B,aAAK,iBAAiB;AAAA,MACxB;AAGA,UAAI,KAAK,kBAAkB,QAAQ;AACjC,aAAK,KAAK,YAAY,cAAc;AAAA,UAClC,SAAS;AAAA,UACT,MAAM,KAAK;AAAA,UACX,aAAa,QAAQ,IAAI;AAAA,UACzB;AAAA,UACA;AAAA,UACA;AAAA,QACF,CAAC,EAAE,MAAM,WAAS;AAChB,kBAAQ,MAAM,+CAAsC,MAAgB,OAAO,EAAE;AAAA,QAC/E,CAAC;AAAA,MACH,OAAO;AACL,aAAK,aAAa;AAAA,UAChB,MAAM;AAAA,UACN,SAAS;AAAA,UACT,MAAM,KAAK;AAAA,UACX,WAAW,KAAK;AAAA,UAChB,aAAa,QAAQ,IAAI;AAAA;AAAA,UACzB;AAAA;AAAA,UACA;AAAA,UACA;AAAA,QACF,CAAC;AAAA,MACH;AAEA,cAAQ,IAAI,wCAAyB,EAAE,KAAK,KAAK,IAAI,GAAG;AACxD,aAAO;AAAA,IACT,UAAE;AACA,WAAK,mBAAmB;AAAA,IAC1B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,gBAAgB,SAAuB;AACrC,UAAM,UAAU,KAAK,OAAO,OAAO,OAAO;AAC1C,QAAI,SAAS;AACX,UAAI,KAAK,kBAAkB,QAAQ;AACjC,aAAK,KAAK,YAAY,gBAAgB,OAAO,EAAE,MAAM,WAAS;AAC5D,kBAAQ,MAAM,iDAAwC,MAAgB,OAAO,EAAE;AAAA,QACjF,CAAC;AAAA,MACH,OAAO;AACL,aAAK,aAAa,EAAE,MAAM,oBAAoB,QAAQ,CAAC;AAAA,MACzD;AACA,cAAQ,IAAI,wCAAyB,OAAO,EAAE;AAG9C,UAAI,KAAK,mBAAmB,SAAS;AACnC,cAAM,YAAY,MAAM,KAAK,KAAK,OAAO,KAAK,CAAC;AAC/C,aAAK,iBAAiB,UAAU,SAAS,IAAI,UAAU,CAAC,IAAI;AAC5D,YAAI,KAAK,gBAAgB;AACvB,cAAI,KAAK,kBAAkB,QAAQ;AACjC,iBAAK,KAAK,YAAY,YAAY,KAAK,cAAc,EAAE,MAAM,WAAS;AACpE,sBAAQ,MAAM,6CAAoC,MAAgB,OAAO,EAAE;AAAA,YAC7E,CAAC;AAAA,UACH,WAAW,KAAK,kBAAkB,iBAAiB;AACjD,iBAAK,aAAa;AAAA,cAChB,MAAM;AAAA,cACN,SAAS,KAAK;AAAA,YAChB,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,YAAY,SAA0B;AACpC,QAAI,CAAC,KAAK,OAAO,IAAI,OAAO,GAAG;AAC7B,aAAO;AAAA,IACT;AACA,SAAK,iBAAiB;AACtB,QAAI,KAAK,kBAAkB,QAAQ;AACjC,WAAK,KAAK,YAAY,YAAY,OAAO,EAAE,MAAM,WAAS;AACxD,gBAAQ,MAAM,6CAAoC,MAAgB,OAAO,EAAE;AAAA,MAC7E,CAAC;AACD,cAAQ,IAAI,qDAA4B,OAAO,EAAE;AACjD,aAAO;AAAA,IACT;AACA,QAAI,KAAK,kBAAkB,iBAAiB;AAC1C,WAAK,aAAa;AAAA,QAChB,MAAM;AAAA,QACN;AAAA,MACF,CAAC;AAAA,IACH;AACA,YAAQ,IAAI,qDAA4B,OAAO,EAAE;AACjD,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,aAAa,SAAiB,UAA2B;AACvD,QAAI,KAAK,kBAAkB,QAAQ;AACjC,WAAK,KAAK,YAAY,aAAa,SAAS,QAAQ,EAAE,MAAM,WAAS;AACnE,gBAAQ,MAAM,8CAAqC,MAAgB,OAAO,EAAE;AAAA,MAC9E,CAAC;AACD;AAAA,IACF;AAEA,SAAK,aAAa;AAAA,MAChB,MAAM;AAAA,MACN;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,mBAAmB,SAAiB,OAAqB;AACvD,QAAI,KAAK,kBAAkB,QAAQ;AACjC,WAAK,KAAK,YAAY,cAAc,SAAS,KAAK,EAAE,MAAM,WAAS;AACjE,gBAAQ,MAAM,+CAAsC,MAAgB,OAAO,EAAE;AAAA,MAC/E,CAAC;AACD;AAAA,IACF;AAEA,SAAK,aAAa;AAAA,MAChB,MAAM;AAAA,MACN;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,qBAAqB,SAAiB,eAA4C;AAChF,QAAI,KAAK,kBAAkB,QAAQ;AACjC,WAAK,KAAK,YAAY,gBAAgB,SAAS,aAAa,EAAE,MAAM,WAAS;AAC3E,gBAAQ,MAAM,iDAAwC,MAAgB,OAAO,EAAE;AAAA,MACjF,CAAC;AACD;AAAA,IACF;AAEA,SAAK,aAAa;AAAA,MAChB,MAAM;AAAA,MACN;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,oBAAoB,SAAiB,UAAuC;AAC1E,QAAI,KAAK,kBAAkB,QAAQ;AACjC,WAAK,KAAK,YAAY,eAAe,SAAS,QAAQ,EAAE,MAAM,WAAS;AACrE,gBAAQ,MAAM,gDAAuC,MAAgB,OAAO,EAAE;AAAA,MAChF,CAAC;AACD;AAAA,IACF;AAEA,SAAK,aAAa;AAAA,MAChB,MAAM;AAAA,MACN;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,eAA4B;AAC1B,WAAO,MAAM,KAAK,KAAK,OAAO,OAAO,CAAC,EAAE,IAAI,OAAK,EAAE,IAAI;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA,EAKA,oBAAmC;AACjC,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,mBAA6C;AAC3C,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,kBAAqC;AACnC,WAAO,qBAAqB;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA,EAKA,WAAW,OAAkC;AAC3C,eAAW,CAAC,IAAI,IAAI,KAAK,KAAK,QAAQ;AACpC,UAAI,KAAK,UAAU,OAAO;AACxB,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,UAAyB;AACvB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,cAAuB;AACrB,QAAI,KAAK,kBAAkB,QAAQ;AACjC,aAAO,KAAK;AAAA,IACd;AACA,WAAO,KAAK,eAAe,CAAC,CAAC,KAAK;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,iBAAiB,SAAiB,cAAkC;AAClE,QAAI,KAAK,kBAAkB,QAAQ;AACjC,WAAK,KAAK,YAAY,iBAAiB,SAAS,YAAY,EAAE,MAAM,WAAS;AAC3E,gBAAQ,MAAM,kDAAyC,MAAgB,OAAO,EAAE;AAAA,MAClF,CAAC;AACD;AAAA,IACF;AAEA,SAAK,aAAa;AAAA,MAChB,MAAM;AAAA,MACN;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,iBAAiB,SAAiB,QAAgB,UAAkB,UAA2B;AAC7F,WAAO,KAAK,sBAAsB,SAAS,EAAE,OAAO,GAAG,OAAO,EAAE,KAAK,CAAC,aAAa;AACjF,UAAI,SAAS,SAAS,QAAQ;AAC5B,cAAM,IAAI,MAAM,iDAAiD,SAAS,YAAY,SAAS,GAAG;AAAA,MACpG;AACA,aAAO,SAAS,QAAQ;AAAA,IAC1B,CAAC;AAAA,EACH;AAAA,EAEA,sBACE,SACA,SACA,UAAkB,UACU;AAC5B,QAAI,KAAK,kBAAkB,QAAQ;AACjC,aAAO,KAAK,YAAY,iBAAiB,SAAS,SAAS,OAAO,KAC7D,QAAQ,OAAO,IAAI,MAAM,8BAA8B,CAAC;AAAA,IAC/D;AAEA,UAAM,YAAY,SAAS,OAAO,IAAI,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC,CAAC;AAEvF,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAEtC,UAAI;AACJ,UAAI,YAAY,UAAU;AACxB,gBAAQ,WAAW,MAAM;AACvB,eAAK,qBAAqB,OAAO,SAAS;AAC1C,eAAK,oBAAoB,OAAO,OAAO;AACvC,iBAAO,IAAI,MAAM,4BAA4B,OAAO,IAAI,CAAC;AAAA,QAC3D,GAAG,OAAO;AAAA,MACZ;AAGA,WAAK,qBAAqB,IAAI,WAAW,CAAC,aAAgC;AACxE,YAAI,MAAO,cAAa,KAAK;AAC7B,aAAK,oBAAoB,OAAO,OAAO;AACvC,gBAAQ,QAAQ;AAAA,MAClB,CAAC;AAGD,WAAK,oBAAoB,IAAI,SAAS;AAAA,QACpC;AAAA,QACA,QAAQ,QAAQ;AAAA,QAChB,aAAa,QAAQ;AAAA,QACrB,cAAc,QAAQ;AAAA,QACtB,SAAS,QAAQ;AAAA,QACjB,WAAW,KAAK,IAAI;AAAA,MACtB,CAAC;AAGD,WAAK,aAAa;AAAA,QAChB,MAAM;AAAA,QACN;AAAA,QACA;AAAA,QACA,QAAQ,QAAQ;AAAA,QAChB,aAAa,QAAQ;AAAA,QACrB,cAAc,QAAQ;AAAA,QACtB,SAAS,QAAQ;AAAA,QACjB;AAAA,MACF,CAAoB;AAAA,IACtB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,kBAAiC;AAC7C,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,WAAK,YAAY,QAAQ,KAAK,OAAO;AAErC,WAAK,UAAU,GAAG,WAAW,MAAM;AACjC,aAAK,cAAc;AACnB,aAAK,oBAAoB;AACzB,gBAAQ,IAAI,qDAAiC,KAAK,OAAO,EAAE;AAG3D,mBAAW,OAAO,KAAK,cAAc;AACnC,eAAK,WAAW,GAAG;AAAA,QACrB;AACA,aAAK,eAAe,CAAC;AAGrB,aAAK,oBAAoB;AAGzB,YAAI,KAAK,gBAAgB;AACvB,eAAK,aAAa;AAAA,YAChB,MAAM;AAAA,YACN,SAAS,KAAK;AAAA,UAChB,CAAC;AAAA,QACH;AAEA,gBAAQ;AAAA,MACV,CAAC;AAED,WAAK,UAAU,GAAG,QAAQ,CAAC,SAAiB;AAC1C,cAAM,QAAQ,KAAK,SAAS,EAAE,MAAM,IAAI;AACxC,mBAAW,QAAQ,OAAO;AACxB,cAAI,CAAC,KAAK,KAAK,EAAG;AAClB,cAAI;AACF,kBAAM,MAAM,KAAK,MAAM,IAAI;AAC3B,iBAAK,oBAAoB,GAAG;AAAA,UAC9B,SAAS,KAAK;AACZ,oBAAQ,MAAM,2DAA6B,GAAG;AAAA,UAChD;AAAA,QACF;AAAA,MACF,CAAC;AAED,WAAK,UAAU,GAAG,SAAS,CAAC,QAAe;AACzC,eAAO,IAAI,MAAM,2CAAuB,KAAK,OAAO,MAAM,IAAI,OAAO;AAAA,yDAAyB,CAAC;AAAA,MACjG,CAAC;AAED,WAAK,UAAU,GAAG,SAAS,MAAM;AAC/B,aAAK,cAAc;AACnB,gBAAQ,KAAK,qEAAkC;AAG/C,aAAK,kBAAkB;AAAA,MACzB,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKQ,oBAAoB,KAAgB;AAC1C,YAAQ,IAAI,MAAM;AAAA,MAChB,KAAK;AACH,gBAAQ,IAAI,qDAA4B,IAAI,OAAO,EAAE;AACrD;AAAA;AAAA,MAGF,KAAK;AACH,cAAM,WAAW,KAAK,qBAAqB,IAAI,IAAI,SAAS;AAC5D,YAAI,UAAU;AACZ,mBAAS,IAAI,YAAY;AAAA,YACvB,MAAM;AAAA,YACN,MAAM,IAAI;AAAA,UACZ,CAAC;AACD,eAAK,qBAAqB,OAAO,IAAI,SAAS;AAAA,QAChD,OAAO;AACL,kBAAQ,KAAK,oDAAsB,IAAI,SAAS,EAAE;AAAA,QACpD;AACA;AAAA,IACJ;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,sBAA4B;AAClC,QAAI,KAAK,kBAAkB,QAAQ;AACjC,iBAAW,CAAC,IAAI,IAAI,KAAK,KAAK,QAAQ;AACpC,cAAM,gBAAiB,KAAK,MAAc,6BAA6B,KACjE,KAAK,MAAc;AACzB,cAAM,WAAY,KAAK,MAAc,wBAAwB;AAC7D,cAAM,mBAAmB,KAAK,sBAAsB,IAAI,EAAE,KAAK,CAAC;AAEhE,aAAK,KAAK,YAAY,cAAc;AAAA,UAClC,SAAS;AAAA,UACT,MAAM,KAAK,KAAK;AAAA,UAChB,aAAa,QAAQ,IAAI;AAAA,UACzB;AAAA,UACA;AAAA,UACA;AAAA,QACF,CAAC,EAAE,KAAK,YAAY;AAClB,gBAAM,QAAS,KAAK,MAAc;AAClC,cAAI,SAAS,OAAO,MAAM,eAAe,YAAY;AACnD,kBAAM,UAAU,MAAM,WAAW;AACjC,kBAAM,WAAW,QAAQ,IAAI,CAAC,MAAW,EAAE,IAAI;AAC/C,gBAAI,SAAS,SAAS,GAAG;AACvB,oBAAM,KAAK,YAAY,cAAc,IAAI,QAAQ;AAAA,YACnD;AAAA,UACF;AAEA,gBAAM,UAAW,KAAK,MAAc,aAAa;AACjD,cAAI,WAAW,OAAO,QAAQ,WAAW,YAAY;AACnD,kBAAM,WAAW,QAAQ,OAAO;AAChC,gBAAI,SAAS,SAAS,GAAG;AACvB,oBAAM,KAAK,YAAY,aAAa,IAAI,QAAQ;AAAA,YAClD;AAAA,UACF;AAAA,QACF,CAAC,EAAE,MAAM,WAAS;AAChB,kBAAQ,MAAM,6CAAoC,MAAgB,OAAO,EAAE;AAAA,QAC7E,CAAC;AAAA,MACH;AACA;AAAA,IACF;AAEA,QAAI,KAAK,OAAO,SAAS,GAAG;AAC1B;AAAA,IACF;AAEA,YAAQ,IAAI,uCAAmB,KAAK,OAAO,IAAI,kBAAa;AAE5D,eAAW,CAAC,IAAI,IAAI,KAAK,KAAK,QAAQ;AAEpC,YAAM,gBAAiB,KAAK,MAAc,6BAA6B,KACjE,KAAK,MAAc;AACzB,YAAM,WAAY,KAAK,MAAc,wBAAwB;AAG7D,YAAM,mBAAmB,KAAK,sBAAsB,IAAI,EAAE,KAAK,CAAC;AAGhE,YAAM,qBAAqB,KAAK,oBAAoB,IAAI,EAAE;AAC1D,UAAI,oBAAoB;AACtB,gBAAQ,IAAI,gEAAwB,mBAAmB,SAAS,EAAE;AAAA,MACpE;AAEA,WAAK,aAAa;AAAA,QAChB,MAAM;AAAA,QACN,SAAS;AAAA,QACT,MAAM,KAAK,KAAK;AAAA,QAChB,WAAW,KAAK,KAAK;AAAA,QACrB,aAAa,QAAQ,IAAI;AAAA,QACzB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA;AAAA,MACF,CAAC;AAGD,YAAM,QAAS,KAAK,MAAc;AAClC,UAAI,SAAS,OAAO,MAAM,eAAe,YAAY;AACnD,cAAM,UAAU,MAAM,WAAW;AACjC,cAAM,WAAW,QAAQ,IAAI,CAAC,MAAW,EAAE,IAAI;AAC/C,YAAI,SAAS,SAAS,GAAG;AACvB,eAAK,aAAa;AAAA,YAChB,MAAM;AAAA,YACN,SAAS;AAAA,YACT,OAAO;AAAA,UACT,CAAC;AAAA,QACH;AAAA,MACF;AAGA,YAAM,UAAW,KAAK,MAAc,aAAa;AACjD,UAAI,WAAW,OAAO,QAAQ,WAAW,YAAY;AACnD,cAAM,WAAW,QAAQ,OAAO;AAChC,YAAI,SAAS,SAAS,GAAG;AACvB,eAAK,aAAa;AAAA,YAChB,MAAM;AAAA,YACN,SAAS;AAAA,YACT;AAAA,UACF,CAAC;AACD,kBAAQ,IAAI,iCAAuB,EAAE,WAAM,SAAS,MAAM,qBAAM;AAAA,QAClE;AAAA,MACF;AAAA,IACF;AAEA,YAAQ,IAAI,wDAAqB;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAKQ,oBAA0B;AAEhC,QAAI,KAAK,gBAAgB;AACvB,mBAAa,KAAK,cAAc;AAAA,IAClC;AAGA,QAAI,KAAK,qBAAqB,KAAK,wBAAwB;AACzD,cAAQ,MAAM,gEAAwB,KAAK,sBAAsB,iCAAQ;AACzE;AAAA,IACF;AAEA,SAAK;AAGL,UAAM,QAAQ,KAAK;AAAA,MACjB,KAAK,kBAAkB,KAAK,IAAI,GAAG,KAAK,oBAAoB,CAAC;AAAA,MAC7D;AAAA,IACF;AAEA,YAAQ,IAAI,cAAc,KAAK,+BAAW,KAAK,iBAAiB,wBAAS;AAEzE,SAAK,iBAAiB,WAAW,YAAY;AAC3C,UAAI;AACF,cAAM,KAAK,gBAAgB;AAC3B,gBAAQ,IAAI,4FAA2B;AAAA,MACzC,SAAS,OAAO;AACd,gBAAQ,MAAM,wCAAqB,MAAgB,OAAO,EAAE;AAE5D,aAAK,kBAAkB;AAAA,MACzB;AAAA,IACF,GAAG,KAAK;AAAA,EACV;AAAA;AAAA;AAAA;AAAA,EAKQ,WAAW,KAA+B;AAChD,QAAI,KAAK,aAAa,KAAK,aAAa;AACtC,WAAK,UAAU,MAAM,KAAK,UAAU,GAAG,IAAI,IAAI;AAAA,IACjD;AAAA,EAEF;AAAA;AAAA;AAAA;AAAA,EAKQ,aAAa,KAA+B;AAClD,QAAI,CAAC,KAAK,WAAW;AACnB;AAAA,IACF;AACA,SAAK,WAAW,GAAG;AAAA,EACrB;AACF;","names":[]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
4
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
5
|
+
}) : x)(function(x) {
|
|
6
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
7
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
8
|
+
});
|
|
9
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
10
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
11
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
12
|
+
if (decorator = decorators[i])
|
|
13
|
+
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
14
|
+
if (kind && result) __defProp(target, key, result);
|
|
15
|
+
return result;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export {
|
|
19
|
+
__require,
|
|
20
|
+
__decorateClass
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=chunk-BDS2QGZ5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
// src/template/resolver.ts
|
|
2
|
+
var PlaceholderResolver = class _PlaceholderResolver {
|
|
3
|
+
// 正则表达式模式
|
|
4
|
+
static PATTERNS = {
|
|
5
|
+
// {{#each}}...{{/each}} 循环渲染
|
|
6
|
+
each: /\{\{#each\}\}(.*?)\{\{\/each\}\}/gs,
|
|
7
|
+
// {{#if}}...{{/if}} 条件渲染
|
|
8
|
+
conditional: /\{\{#if\}\}(.*?)\{\{\/if\}\}/gs,
|
|
9
|
+
// {{variable}} 或 {{obj.key}} 或 {{var|default}}
|
|
10
|
+
variable: /\{\{([^}]+)\}\}/g
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* 解析模板中的占位符
|
|
14
|
+
* @param template 模板内容
|
|
15
|
+
* @param context 变量上下文
|
|
16
|
+
* @returns 解析后的内容
|
|
17
|
+
*/
|
|
18
|
+
static resolve(template, context = {}) {
|
|
19
|
+
let result = _PlaceholderResolver.processEach(template, context);
|
|
20
|
+
result = _PlaceholderResolver.processConditionals(result, context);
|
|
21
|
+
result = result.replace(_PlaceholderResolver.PATTERNS.variable, (_, expr) => {
|
|
22
|
+
const trimmed = expr.trim();
|
|
23
|
+
const pipeIndex = trimmed.indexOf("|");
|
|
24
|
+
let path;
|
|
25
|
+
let defaultValue;
|
|
26
|
+
if (pipeIndex !== -1) {
|
|
27
|
+
path = trimmed.slice(0, pipeIndex).trim();
|
|
28
|
+
defaultValue = trimmed.slice(pipeIndex + 1).trim();
|
|
29
|
+
} else {
|
|
30
|
+
path = trimmed;
|
|
31
|
+
}
|
|
32
|
+
const value = _PlaceholderResolver.getNestedValue(context, path);
|
|
33
|
+
if (value !== void 0 && value !== null) {
|
|
34
|
+
return String(value);
|
|
35
|
+
}
|
|
36
|
+
return defaultValue ?? "";
|
|
37
|
+
});
|
|
38
|
+
return result;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* 处理循环渲染 {{#each}}...{{/each}}
|
|
42
|
+
* 格式:{{#each}}arrayName
|
|
43
|
+
* ...template...
|
|
44
|
+
* {{/each}}
|
|
45
|
+
* 在循环内可使用数组元素的字段(如 {{name}}, {{description}})或 {{this}} 引用整个对象
|
|
46
|
+
*/
|
|
47
|
+
static processEach(template, context) {
|
|
48
|
+
return template.replace(
|
|
49
|
+
_PlaceholderResolver.PATTERNS.each,
|
|
50
|
+
(match, body) => {
|
|
51
|
+
const lines = body.split("\n");
|
|
52
|
+
const arrayName = lines[0].trim();
|
|
53
|
+
const loopTemplate = lines.slice(1).join("\n");
|
|
54
|
+
const array = _PlaceholderResolver.getNestedValue(context, arrayName);
|
|
55
|
+
if (!Array.isArray(array)) {
|
|
56
|
+
return "";
|
|
57
|
+
}
|
|
58
|
+
return array.map((item) => {
|
|
59
|
+
const itemContext = {
|
|
60
|
+
...context,
|
|
61
|
+
...item,
|
|
62
|
+
this: item
|
|
63
|
+
};
|
|
64
|
+
return _PlaceholderResolver.resolve(loopTemplate, itemContext);
|
|
65
|
+
}).join("");
|
|
66
|
+
}
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* 处理条件渲染 {{#if}}...{{/if}}
|
|
71
|
+
* 条件格式:{{#if}}varName{{/if}} - 只有当 varName 为真时才显示内容
|
|
72
|
+
*/
|
|
73
|
+
static processConditionals(template, context) {
|
|
74
|
+
return template.replace(
|
|
75
|
+
_PlaceholderResolver.PATTERNS.conditional,
|
|
76
|
+
(_, content) => {
|
|
77
|
+
const trimmed = content.trim();
|
|
78
|
+
const value = _PlaceholderResolver.getNestedValue(context, trimmed);
|
|
79
|
+
if (value === true || value === 1 || value === "true") {
|
|
80
|
+
return "";
|
|
81
|
+
}
|
|
82
|
+
if (value) {
|
|
83
|
+
return content;
|
|
84
|
+
}
|
|
85
|
+
return "";
|
|
86
|
+
}
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* 获取嵌套对象的值
|
|
91
|
+
* 支持点号分隔的路径,如 "user.name"
|
|
92
|
+
*/
|
|
93
|
+
static getNestedValue(obj, path) {
|
|
94
|
+
const keys = path.split(".");
|
|
95
|
+
let current = obj;
|
|
96
|
+
for (const key of keys) {
|
|
97
|
+
if (current === null || current === void 0) {
|
|
98
|
+
return void 0;
|
|
99
|
+
}
|
|
100
|
+
current = current[key];
|
|
101
|
+
}
|
|
102
|
+
return current;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* 获取模板中使用的变量列表
|
|
106
|
+
*/
|
|
107
|
+
static extractVariables(template) {
|
|
108
|
+
const variables = /* @__PURE__ */ new Set();
|
|
109
|
+
let match;
|
|
110
|
+
const regex = /\{\{([^}|]+?)(?:\|[^}]*)?\}\}/g;
|
|
111
|
+
while ((match = regex.exec(template)) !== null) {
|
|
112
|
+
variables.add(match[1].trim());
|
|
113
|
+
}
|
|
114
|
+
return Array.from(variables);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* 验证上下文是否包含所需变量
|
|
118
|
+
* @returns 缺失的变量数组
|
|
119
|
+
*/
|
|
120
|
+
static validate(template, context) {
|
|
121
|
+
const required = _PlaceholderResolver.extractVariables(template);
|
|
122
|
+
const missing = [];
|
|
123
|
+
for (const path of required) {
|
|
124
|
+
const value = _PlaceholderResolver.getNestedValue(context, path);
|
|
125
|
+
if (value === void 0 || value === null || value === "") {
|
|
126
|
+
missing.push(path);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return missing;
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
export {
|
|
134
|
+
PlaceholderResolver
|
|
135
|
+
};
|
|
136
|
+
//# sourceMappingURL=chunk-BVF7RUXV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/template/resolver.ts"],"sourcesContent":["/**\n * 占位符解析器\n * 使用正则表达式实现占位符替换\n */\n\nimport type { PlaceholderContext } from './types.js';\n\n/**\n * 占位符解析器\n */\nexport class PlaceholderResolver {\n // 正则表达式模式\n private static PATTERNS = {\n // {{#each}}...{{/each}} 循环渲染\n each: /\\{\\{#each\\}\\}(.*?)\\{\\{\\/each\\}\\}/gs,\n // {{#if}}...{{/if}} 条件渲染\n conditional: /\\{\\{#if\\}\\}(.*?)\\{\\{\\/if\\}\\}/gs,\n // {{variable}} 或 {{obj.key}} 或 {{var|default}}\n variable: /\\{\\{([^}]+)\\}\\}/g,\n };\n\n /**\n * 解析模板中的占位符\n * @param template 模板内容\n * @param context 变量上下文\n * @returns 解析后的内容\n */\n static resolve(template: string, context: PlaceholderContext = {}): string {\n // 1. 处理循环渲染 {{#each}}...{{/each}}\n let result = PlaceholderResolver.processEach(template, context);\n\n // 2. 处理条件渲染 {{#if}}...{{/if}}\n result = PlaceholderResolver.processConditionals(result, context);\n\n // 2. 处理变量替换(支持嵌套和默认值)\n result = result.replace(PlaceholderResolver.PATTERNS.variable, (_, expr) => {\n const trimmed = expr.trim();\n\n // 分离默认值: var|default\n const pipeIndex = trimmed.indexOf('|');\n let path: string;\n let defaultValue: string | undefined;\n\n if (pipeIndex !== -1) {\n path = trimmed.slice(0, pipeIndex).trim();\n defaultValue = trimmed.slice(pipeIndex + 1).trim();\n } else {\n path = trimmed;\n }\n\n // 获取值(支持嵌套访问)\n const value = PlaceholderResolver.getNestedValue(context, path);\n\n // 返回值或默认值\n if (value !== undefined && value !== null) {\n return String(value);\n }\n return defaultValue ?? '';\n });\n\n return result;\n }\n\n /**\n * 处理循环渲染 {{#each}}...{{/each}}\n * 格式:{{#each}}arrayName\n * ...template...\n * {{/each}}\n * 在循环内可使用数组元素的字段(如 {{name}}, {{description}})或 {{this}} 引用整个对象\n */\n private static processEach(\n template: string,\n context: PlaceholderContext\n ): string {\n return template.replace(\n PlaceholderResolver.PATTERNS.each,\n (match, body: string) => {\n // 解析内容:第一行是数组变量名,其余是循环模板\n const lines = body.split('\\n');\n const arrayName = lines[0].trim();\n const loopTemplate = lines.slice(1).join('\\n');\n\n // 获取数组数据\n const array = PlaceholderResolver.getNestedValue(context, arrayName);\n\n // 不是数组则返回空\n if (!Array.isArray(array)) {\n return '';\n }\n\n // 渲染每个元素\n return array.map((item) => {\n // 将 item 的字段作为上下文,也提供 this 引用整个对象\n const itemContext: PlaceholderContext = {\n ...context,\n ...item,\n this: item,\n };\n return PlaceholderResolver.resolve(loopTemplate, itemContext);\n }).join('');\n });\n }\n\n /**\n * 处理条件渲染 {{#if}}...{{/if}}\n * 条件格式:{{#if}}varName{{/if}} - 只有当 varName 为真时才显示内容\n */\n private static processConditionals(\n template: string,\n context: PlaceholderContext\n ): string {\n return template.replace(\n PlaceholderResolver.PATTERNS.conditional,\n (_, content: string) => {\n // 检查条件变量是否存在且为真\n const trimmed = content.trim();\n const value = PlaceholderResolver.getNestedValue(context, trimmed);\n\n // 布尔值判断\n if (value === true || value === 1 || value === 'true') {\n return ''; // 条件为真,保留内容(但这里逻辑反了,应该返回内容)\n }\n if (value) {\n return content;\n }\n return ''; // 条件为假,移除内容\n });\n }\n\n /**\n * 获取嵌套对象的值\n * 支持点号分隔的路径,如 \"user.name\"\n */\n private static getNestedValue(obj: any, path: string): any {\n const keys = path.split('.');\n let current = obj;\n\n for (const key of keys) {\n if (current === null || current === undefined) {\n return undefined;\n }\n current = current[key];\n }\n\n return current;\n }\n\n /**\n * 获取模板中使用的变量列表\n */\n static extractVariables(template: string): string[] {\n const variables = new Set<string>();\n let match: RegExpExecArray | null;\n\n // 提取所有变量(不包括条件渲染)\n const regex = /\\{\\{([^}|]+?)(?:\\|[^}]*)?\\}\\}/g;\n while ((match = regex.exec(template)) !== null) {\n variables.add(match[1].trim());\n }\n\n return Array.from(variables);\n }\n\n /**\n * 验证上下文是否包含所需变量\n * @returns 缺失的变量数组\n */\n static validate(\n template: string,\n context: PlaceholderContext\n ): string[] {\n const required = PlaceholderResolver.extractVariables(template);\n const missing: string[] = [];\n\n for (const path of required) {\n const value = PlaceholderResolver.getNestedValue(context, path);\n if (value === undefined || value === null || value === '') {\n missing.push(path);\n }\n }\n\n return missing;\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AgentBase,
|
|
3
|
+
OpencodeBasicFeature,
|
|
4
|
+
SkillFeature,
|
|
5
|
+
SubAgentFeature,
|
|
6
|
+
TemplateComposer,
|
|
7
|
+
createLLM,
|
|
8
|
+
loadConfigSync
|
|
9
|
+
} from "./chunk-N7J76R5P.js";
|
|
10
|
+
|
|
11
|
+
// src/agents/system/ExplorerAgent.ts
|
|
12
|
+
import { existsSync } from "fs";
|
|
13
|
+
import { cwd, platform } from "process";
|
|
14
|
+
var ExplorerAgent = class extends AgentBase {
|
|
15
|
+
_systemContext;
|
|
16
|
+
_config;
|
|
17
|
+
_skillsDir;
|
|
18
|
+
/**
|
|
19
|
+
* 构造函数
|
|
20
|
+
*
|
|
21
|
+
* @param config 探索者配置(全部可选,不传则使用默认配置)
|
|
22
|
+
*/
|
|
23
|
+
constructor(config = {}) {
|
|
24
|
+
const systemContext = {
|
|
25
|
+
SYSTEM_WORKING_DIR: cwd(),
|
|
26
|
+
SYSTEM_IS_GIT_REPOSITORY: existsSync(cwd() + "/.git"),
|
|
27
|
+
SYSTEM_PLATFORM: platform,
|
|
28
|
+
SYSTEM_DATE: (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
|
|
29
|
+
// YYYY-MM-DD
|
|
30
|
+
SYSTEM_CURRENT_MODEL: "unknown"
|
|
31
|
+
// 稍后更新
|
|
32
|
+
};
|
|
33
|
+
let llm = config.llm;
|
|
34
|
+
let fileConfig;
|
|
35
|
+
if (!llm) {
|
|
36
|
+
const configName = config.configName ?? "default";
|
|
37
|
+
fileConfig = loadConfigSync(configName);
|
|
38
|
+
llm = createLLM(fileConfig);
|
|
39
|
+
systemContext.SYSTEM_CURRENT_MODEL = fileConfig.defaultModel.model;
|
|
40
|
+
console.log(`[ExplorerAgent] \u5DF2\u52A0\u8F7D\u914D\u7F6E: ${configName}, \u6A21\u578B: ${fileConfig.defaultModel.model}`);
|
|
41
|
+
}
|
|
42
|
+
const agentConfig = {
|
|
43
|
+
llm,
|
|
44
|
+
tools: [],
|
|
45
|
+
// 工具由 Feature 提供
|
|
46
|
+
maxTurns: Infinity,
|
|
47
|
+
// 无限交互次数
|
|
48
|
+
systemMessage: config.systemMessage,
|
|
49
|
+
name: config.name
|
|
50
|
+
};
|
|
51
|
+
super(agentConfig);
|
|
52
|
+
this._systemContext = systemContext;
|
|
53
|
+
this._config = fileConfig;
|
|
54
|
+
this._skillsDir = config.skillsDir;
|
|
55
|
+
this.setSystemContext(systemContext);
|
|
56
|
+
this.use(new OpencodeBasicFeature());
|
|
57
|
+
this.use(new SkillFeature(config.skillsDir));
|
|
58
|
+
this.use(new SubAgentFeature());
|
|
59
|
+
this.getTools().disable("write");
|
|
60
|
+
this.getTools().disable("edit");
|
|
61
|
+
this.getTools().disable("safe_trash_delete");
|
|
62
|
+
this.getTools().disable("safe_trash_list");
|
|
63
|
+
this.getTools().disable("safe_trash_restore");
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Agent 初始化钩子
|
|
67
|
+
* 配置系统提示词,禁用写入和编辑工具(只读模式)
|
|
68
|
+
*/
|
|
69
|
+
async onInitiate() {
|
|
70
|
+
if (!this.systemMessage) {
|
|
71
|
+
this.setSystemPrompt(
|
|
72
|
+
new TemplateComposer().add({ file: ".agentdev/prompts/explorer.md" }).add("\n\n## \u7CFB\u7EDF\u73AF\u5883\n\n").add("- \u5DE5\u4F5C\u76EE\u5F55: `{{SYSTEM_WORKING_DIR}}`\n").add("- Git \u4ED3\u5E93: {{SYSTEM_IS_GIT_REPOSITORY}}\n").add("- \u64CD\u4F5C\u7CFB\u7EDF: {{SYSTEM_PLATFORM}}\n").add("- bash\u7248\u672C\uFF1APowerShell 5.1\n").add("- \u5F53\u524D\u65E5\u671F: {{SYSTEM_DATE}}\n")
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* 获取系统环境信息
|
|
78
|
+
*/
|
|
79
|
+
getSystemContext() {
|
|
80
|
+
return this._systemContext;
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export {
|
|
85
|
+
ExplorerAgent
|
|
86
|
+
};
|
|
87
|
+
//# sourceMappingURL=chunk-DI5EGMGG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/agents/system/ExplorerAgent.ts"],"sourcesContent":["/**\r\n * ExplorerAgent - 代码探索者 Agent\r\n *\r\n * 专注于代码库探索和理解的轻量级 Agent\r\n * 仅配备 read、list、bash 三个核心工具\r\n * 适用于代码审查、结构分析、文档生成等场景\r\n */\r\n\r\nimport { Agent } from '../../core/agent.js';\r\nimport { SkillFeature, SubAgentFeature, OpencodeBasicFeature } from '../../features/index.js';\r\nimport type { AgentConfig, LLMClient } from '../../core/types.js';\r\nimport type { AgentConfigFile } from '../../core/config.js';\r\nimport { loadConfigSync } from '../../core/config.js';\r\nimport { createLLM } from '../../llm/index.js';\r\nimport { existsSync } from 'fs';\r\nimport { cwd, platform } from 'process';\r\nimport { TemplateComposer } from '../../template/composer.js';\r\n\r\n/**\r\n * 系统环境信息上下文\r\n */\r\nexport interface SystemContext {\r\n /** 当前工作目录 */\r\n SYSTEM_WORKING_DIR: string;\r\n /** 是否是 Git 仓库 */\r\n SYSTEM_IS_GIT_REPOSITORY: boolean;\r\n /** 操作系统平台 */\r\n SYSTEM_PLATFORM: NodeJS.Platform;\r\n /** 当前日期 (YYYY-MM-DD) */\r\n SYSTEM_DATE: string;\r\n /** 当前使用的模型名称 */\r\n SYSTEM_CURRENT_MODEL: string;\r\n /** 索引签名,允许作为 PlaceholderContext 使用 */\r\n [key: string]: any;\r\n}\r\n\r\n/**\r\n * ExplorerAgent 配置选项\r\n *\r\n * 所有参数都是可选的,默认会自动同步加载配置文件\r\n */\r\nexport interface ExplorerAgentConfig {\r\n /** LLM 客户端(可选,不传则自动同步加载配置创建) */\r\n llm?: LLMClient;\r\n /** 配置文件名(可选,默认 'default') */\r\n configName?: string;\r\n /** Agent 显示名称(可选) */\r\n name?: string;\r\n /** 系统提示词(可选,默认使用 explorer.md) */\r\n systemMessage?: string;\r\n /** Skills 目录(可选,默认使用 .agentdev/skills) */\r\n skillsDir?: string;\r\n}\r\n\r\n/**\r\n * 代码探索者 Agent\r\n *\r\n * 轻量级代码探索 Agent,专注于:\r\n * - 代码库结构分析\r\n * - 代码审查和理解\r\n * - 文档生成\r\n * - 依赖关系梳理\r\n *\r\n * 构造函数不传任何参数时,会自动同步加载配置文件创建 LLM\r\n */\r\nexport class ExplorerAgent extends Agent {\r\n protected _systemContext: SystemContext;\r\n protected _config?: AgentConfigFile;\r\n protected _skillsDir?: string;\r\n\r\n /**\r\n * 构造函数\r\n *\r\n * @param config 探索者配置(全部可选,不传则使用默认配置)\r\n */\r\n constructor(config: ExplorerAgentConfig = {}) {\r\n // 建立系统环境信息\r\n const systemContext: SystemContext = {\r\n SYSTEM_WORKING_DIR: cwd(),\r\n SYSTEM_IS_GIT_REPOSITORY: existsSync(cwd() + '/.git'),\r\n SYSTEM_PLATFORM: platform,\r\n SYSTEM_DATE: new Date().toISOString().split('T')[0], // YYYY-MM-DD\r\n SYSTEM_CURRENT_MODEL: 'unknown', // 稍后更新\r\n };\r\n\r\n // 准备 LLM:如果没传入,同步加载配置\r\n let llm = config.llm;\r\n let fileConfig: AgentConfigFile | undefined;\r\n if (!llm) {\r\n const configName = config.configName ?? 'default';\r\n fileConfig = loadConfigSync(configName);\r\n llm = createLLM(fileConfig);\r\n systemContext.SYSTEM_CURRENT_MODEL = fileConfig.defaultModel.model;\r\n console.log(`[ExplorerAgent] 已加载配置: ${configName}, 模型: ${fileConfig.defaultModel.model}`);\r\n }\r\n\r\n // 构建完整的 Agent 配置\r\n const agentConfig: AgentConfig = {\r\n llm: llm!,\r\n tools: [], // 工具由 Feature 提供\r\n maxTurns: Infinity, // 无限交互次数\r\n systemMessage: config.systemMessage,\r\n name: config.name,\r\n };\r\n\r\n super(agentConfig);\r\n\r\n // 保存配置(必须在 super() 之后)\r\n this._systemContext = systemContext;\r\n this._config = fileConfig;\r\n this._skillsDir = config.skillsDir;\r\n this.setSystemContext(systemContext);\r\n\r\n // 注册 OpencodeBasicFeature(文件操作工具集)\r\n this.use(new OpencodeBasicFeature());\r\n\r\n // 注册 SkillFeature(invokeSkill 工具和 skills 上下文注入)\r\n this.use(new SkillFeature(config.skillsDir));\r\n\r\n // 注册 SubAgentFeature(子代理工具和消息处理)\r\n this.use(new SubAgentFeature());\r\n\r\n // 预禁用只读模式下不应暴露的工具,确保首次快照与运行时一致\r\n this.getTools().disable('write');\r\n this.getTools().disable('edit');\r\n this.getTools().disable('safe_trash_delete');\r\n this.getTools().disable('safe_trash_list');\r\n this.getTools().disable('safe_trash_restore');\r\n }\r\n\r\n /**\r\n * Agent 初始化钩子\r\n * 配置系统提示词,禁用写入和编辑工具(只读模式)\r\n */\r\n protected override async onInitiate(): Promise<void> {\r\n // 配置系统提示词\r\n if (!this.systemMessage) {\r\n this.setSystemPrompt(new TemplateComposer()\r\n .add({ file: '.agentdev/prompts/explorer.md' })\r\n .add('\\n\\n## 系统环境\\n\\n')\r\n .add('- 工作目录: `{{SYSTEM_WORKING_DIR}}`\\n')\r\n .add('- Git 仓库: {{SYSTEM_IS_GIT_REPOSITORY}}\\n')\r\n .add('- 操作系统: {{SYSTEM_PLATFORM}}\\n')\r\n .add('- bash版本:PowerShell 5.1\\n')\r\n .add('- 当前日期: {{SYSTEM_DATE}}\\n')\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * 获取系统环境信息\r\n */\r\n getSystemContext(): SystemContext {\r\n return this._systemContext;\r\n }\r\n}\r\n"],"mappings":";;;;;;;;;;;AAcA,SAAS,kBAAkB;AAC3B,SAAS,KAAK,gBAAgB;AAkDvB,IAAM,gBAAN,cAA4B,UAAM;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOV,YAAY,SAA8B,CAAC,GAAG;AAE5C,UAAM,gBAA+B;AAAA,MACnC,oBAAoB,IAAI;AAAA,MACxB,0BAA0B,WAAW,IAAI,IAAI,OAAO;AAAA,MACpD,iBAAiB;AAAA,MACjB,cAAa,oBAAI,KAAK,GAAE,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC;AAAA;AAAA,MAClD,sBAAsB;AAAA;AAAA,IACxB;AAGA,QAAI,MAAM,OAAO;AACjB,QAAI;AACJ,QAAI,CAAC,KAAK;AACR,YAAM,aAAa,OAAO,cAAc;AACxC,mBAAa,eAAe,UAAU;AACtC,YAAM,UAAU,UAAU;AAC1B,oBAAc,uBAAuB,WAAW,aAAa;AAC7D,cAAQ,IAAI,mDAA0B,UAAU,mBAAS,WAAW,aAAa,KAAK,EAAE;AAAA,IAC1F;AAGA,UAAM,cAA2B;AAAA,MAC/B;AAAA,MACA,OAAO,CAAC;AAAA;AAAA,MACR,UAAU;AAAA;AAAA,MACV,eAAe,OAAO;AAAA,MACtB,MAAM,OAAO;AAAA,IACf;AAEA,UAAM,WAAW;AAGjB,SAAK,iBAAiB;AACtB,SAAK,UAAU;AACf,SAAK,aAAa,OAAO;AACzB,SAAK,iBAAiB,aAAa;AAGnC,SAAK,IAAI,IAAI,qBAAqB,CAAC;AAGnC,SAAK,IAAI,IAAI,aAAa,OAAO,SAAS,CAAC;AAG3C,SAAK,IAAI,IAAI,gBAAgB,CAAC;AAG9B,SAAK,SAAS,EAAE,QAAQ,OAAO;AAC/B,SAAK,SAAS,EAAE,QAAQ,MAAM;AAC9B,SAAK,SAAS,EAAE,QAAQ,mBAAmB;AAC3C,SAAK,SAAS,EAAE,QAAQ,iBAAiB;AACzC,SAAK,SAAS,EAAE,QAAQ,oBAAoB;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAyB,aAA4B;AAEnD,QAAI,CAAC,KAAK,eAAe;AACvB,WAAK;AAAA,QAAgB,IAAI,iBAAiB,EACvC,IAAI,EAAE,MAAM,gCAAgC,CAAC,EAC7C,IAAI,qCAAiB,EACrB,IAAI,wDAAoC,EACxC,IAAI,oDAA0C,EAC9C,IAAI,mDAA+B,EACnC,IAAI,0CAA2B,EAC/B,IAAI,+CAA2B;AAAA,MAClC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,mBAAkC;AAChC,WAAO,KAAK;AAAA,EACd;AACF;","names":[]}
|