@dev-anywhere/proxy 0.1.8 → 0.1.9

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.
@@ -3,7 +3,7 @@ import {
3
3
  CONFIG_PATH,
4
4
  LOG_DIR,
5
5
  createLogger
6
- } from "./chunk-2XO3KLWW.js";
6
+ } from "./chunk-QFYI6AMN.js";
7
7
 
8
8
  // src/common/logger.ts
9
9
  import { existsSync, readFileSync } from "fs";
@@ -81,4 +81,4 @@ export {
81
81
  serviceLogger,
82
82
  terminalLogger
83
83
  };
84
- //# sourceMappingURL=chunk-GTTLWHIG.js.map
84
+ //# sourceMappingURL=chunk-2JUB4LDU.js.map
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  sessionPaths
4
- } from "./chunk-2XO3KLWW.js";
4
+ } from "./chunk-QFYI6AMN.js";
5
5
 
6
6
  // src/common/seq-counter.ts
7
7
  import { mkdirSync, readFileSync, writeFileSync, existsSync } from "fs";
@@ -152,4 +152,4 @@ export {
152
152
  IGNORED_EVENT_TYPES,
153
153
  SeqCounter
154
154
  };
155
- //# sourceMappingURL=chunk-PDX6QFJ7.js.map
155
+ //# sourceMappingURL=chunk-7XMJMVIL.js.map
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  DESIRED_RELAY_PATH
4
- } from "./chunk-2XO3KLWW.js";
4
+ } from "./chunk-QFYI6AMN.js";
5
5
 
6
6
  // src/common/daemon-env.ts
7
7
  import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "fs";
@@ -33,4 +33,4 @@ export {
33
33
  setDesiredDaemonRelay,
34
34
  daemonRelayArgs
35
35
  };
36
- //# sourceMappingURL=chunk-2SBGSJLQ.js.map
36
+ //# sourceMappingURL=chunk-BMVYMCKF.js.map
@@ -3,12 +3,12 @@ import {
3
3
  VALID_LOG_LEVELS,
4
4
  loadProxyRuntimeEnv,
5
5
  serviceLogger
6
- } from "./chunk-GTTLWHIG.js";
6
+ } from "./chunk-2JUB4LDU.js";
7
7
  import {
8
8
  CONFIG_PATH,
9
9
  PROFILE_NAME,
10
10
  defaultHookPortForProfile
11
- } from "./chunk-2XO3KLWW.js";
11
+ } from "./chunk-QFYI6AMN.js";
12
12
 
13
13
  // src/common/config.ts
14
14
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
@@ -192,4 +192,4 @@ export {
192
192
  buildProviderEnv,
193
193
  saveAgentCliPath
194
194
  };
195
- //# sourceMappingURL=chunk-R4S6OFIZ.js.map
195
+ //# sourceMappingURL=chunk-DCDXAM76.js.map
@@ -796,7 +796,7 @@ function pruneOldLogs(logDir, name, currentFilePath, retention) {
796
796
  }
797
797
  }
798
798
  function buildPinoLogger(options) {
799
- const { name, level = "info", logDir = DEFAULT_LOG_DIR, retention, stdout = false, silent = false } = options;
799
+ const { name, level = "info", logDir = DEFAULT_LOG_DIR, retention, stdout = false, silent = false, sync = false } = options;
800
800
  if (silent) {
801
801
  return pino({ level: "silent" });
802
802
  }
@@ -805,7 +805,9 @@ function buildPinoLogger(options) {
805
805
  const filePath = join(logDir, `${name}-${runId}.log`);
806
806
  linkLatestLog(logDir, name, filePath, runId);
807
807
  pruneOldLogs(logDir, name, filePath, retention);
808
- const streams = [{ stream: pino.destination(filePath) }];
808
+ const streams = [
809
+ { stream: pino.destination({ dest: filePath, sync }) }
810
+ ];
809
811
  if (stdout) {
810
812
  streams.unshift({ stream: process.stdout });
811
813
  }
@@ -865,4 +867,4 @@ export {
865
867
  SessionState,
866
868
  createLogger
867
869
  };
868
- //# sourceMappingURL=chunk-2XO3KLWW.js.map
870
+ //# sourceMappingURL=chunk-QFYI6AMN.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/common/paths.ts","../../../packages/shared/src/schemas/envelope.ts","../../../packages/shared/src/schemas/chat.ts","../../../packages/shared/src/schemas/tool.ts","../../../packages/shared/src/schemas/session.ts","../../../packages/shared/src/schemas/system.ts","../../../packages/shared/src/builders/index.ts","../../../packages/shared/src/schemas/relay-control.ts","../../../packages/shared/src/constants/relay-errors.ts","../../../packages/shared/src/constants/control-errors.ts","../../../packages/shared/src/constants/session.ts","../../../packages/shared/src/logger.ts"],"sourcesContent":["import { cpSync, existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n// 所有 dev-anywhere 文件路径的集中定义\n// 使用 os.homedir():POSIX 走 HOME,Windows 走 USERPROFILE;未设置时回退到 getpwuid。\n// 相比 process.env.HOME,不会在缺失环境变量时构造出 \"undefined/.dev-anywhere\"。\nconst HOME = homedir();\nconst MODULE_DIR = dirname(fileURLToPath(import.meta.url));\nconst SOURCE_FONT_ASSETS_DIR = resolve(MODULE_DIR, \"../../assets/fonts\");\nconst DIST_FONT_ASSETS_DIR = resolve(MODULE_DIR, \"../assets/fonts\");\nconst DEFAULT_FONT_FAMILY = \"sarasa-fixed-sc\";\nexport const DEFAULT_PROXY_PROFILE = \"default\";\n\ninterface ProxyProfilePaths {\n profileName: string;\n isDefaultProfile: boolean;\n appDir: string;\n profileDir: string;\n configPath: string;\n runDir: string;\n sockPath: string;\n pidPath: string;\n stoppedPath: string;\n desiredRelayPath: string;\n stateDir: string;\n sessionsPath: string;\n hookRegistryPath: string;\n dataDir: string;\n proxyIdPath: string;\n logDir: string;\n serviceLogPath: string;\n relayDataDir: string;\n fontDir: string;\n}\n\nexport function normalizeProxyProfileName(value: string | undefined): string {\n const normalized = value?.trim() || DEFAULT_PROXY_PROFILE;\n if (\n normalized === \".\" ||\n normalized === \"..\" ||\n !/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,63}$/.test(normalized)\n ) {\n throw new Error(\n `Invalid dev-anywhere profile \"${normalized}\". Use 1-64 letters, numbers, \".\", \"_\" or \"-\".`,\n );\n }\n return normalized;\n}\n\nfunction readProxyProfileNameFromArgv(argv: readonly string[]): string | undefined {\n const args = [...argv];\n while (args[0] === \"--\") args.shift();\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n if (arg === \"claude\" || arg === \"codex\") return undefined;\n if (arg === \"--profile\") {\n const next = args[i + 1];\n return next && !next.startsWith(\"-\") ? next : undefined;\n }\n if (arg.startsWith(\"--profile=\")) {\n return arg.slice(\"--profile=\".length);\n }\n }\n return undefined;\n}\n\nfunction resolveProxyProfileName(\n argv: readonly string[] = process.argv.slice(2),\n home: string = HOME,\n): string {\n return normalizeProxyProfileName(\n readProxyProfileNameFromArgv(argv) ?? readDefaultProfileFromConfig(home),\n );\n}\n\nfunction readDefaultProfileFromConfig(home: string): string | undefined {\n try {\n const parsed = JSON.parse(readFileSync(`${home}/.dev-anywhere/config.json`, \"utf-8\")) as {\n defaultProfile?: unknown;\n };\n return typeof parsed.defaultProfile === \"string\" ? parsed.defaultProfile : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport function buildProxyProfilePaths(home: string, profileName: string): ProxyProfilePaths {\n const normalizedProfile = normalizeProxyProfileName(profileName);\n const appDir = `${home}/.dev-anywhere`;\n const isDefaultProfile = normalizedProfile === DEFAULT_PROXY_PROFILE;\n const profileDir = isDefaultProfile ? appDir : `${appDir}/profiles/${normalizedProfile}`;\n const runDir = isDefaultProfile ? `${appDir}/run` : `${profileDir}/run`;\n const stateDir = isDefaultProfile ? `${appDir}/state` : `${profileDir}/state`;\n const dataDir = isDefaultProfile ? `${appDir}/data` : `${profileDir}/data`;\n const logDir = isDefaultProfile ? `${appDir}/logs` : `${profileDir}/logs`;\n const relayDataDir = `${appDir}/relay-data`;\n\n return {\n profileName: normalizedProfile,\n isDefaultProfile,\n appDir,\n profileDir,\n configPath: `${appDir}/config.json`,\n runDir,\n sockPath: `${runDir}/dev-anywhere.sock`,\n pidPath: `${runDir}/dev-anywhere.pid`,\n stoppedPath: `${runDir}/stopped`,\n desiredRelayPath: `${runDir}/desired-relay`,\n stateDir,\n sessionsPath: `${stateDir}/sessions.json`,\n hookRegistryPath: `${stateDir}/hooks.json`,\n dataDir,\n proxyIdPath: isDefaultProfile ? `${appDir}/proxy-id` : `${profileDir}/proxy-id`,\n logDir,\n serviceLogPath: `${logDir}/service.log`,\n relayDataDir,\n fontDir: `${relayDataDir}/fonts`,\n };\n}\n\nexport function defaultHookPortForProfile(profileName: string): number {\n const normalizedProfile = normalizeProxyProfileName(profileName);\n if (normalizedProfile === DEFAULT_PROXY_PROFILE) return 17654;\n\n let hash = 0;\n for (const char of normalizedProfile) {\n hash = (hash * 31 + char.charCodeAt(0)) % 1000;\n }\n return 17655 + hash;\n}\n\nexport const PROFILE_NAME = resolveProxyProfileName();\nconst PROFILE_PATHS = buildProxyProfilePaths(HOME, PROFILE_NAME);\n\n// 把 cwd 前缀替换为 ~,HOME 为空时原样返回(避免 replace(\"\", \"~\") 把 ~ 前缀到所有路径)\nexport function tildify(cwd: string): string {\n return HOME ? cwd.replace(HOME, \"~\") : cwd;\n}\nexport const CONFIG_PATH = PROFILE_PATHS.configPath;\n\n// 运行时文件\nexport const RUN_DIR = PROFILE_PATHS.runDir;\nexport const SOCK_PATH = PROFILE_PATHS.sockPath;\nexport const PID_PATH = PROFILE_PATHS.pidPath;\n// 停机标记文件。用户执行 `dev-anywhere stop` 时创建,其它时候不存在。文件内容无意义。\n// 作用:告诉 terminal 不要在此期间自动重启 daemon。\n//\n// 背景:terminal 在与 serve 的连接断开时,默认会 spawn 新 daemon 把连接修复。\n// 这与用户执行 stop 的诉求冲突——stop 刚结束 daemon,terminal 会立即把它重新拉起。\n// 解决办法是 stop 落下此标记,terminal 重连逻辑先检查标记:存在则仅 tryConnect,不 spawn。\nexport const STOPPED_PATH = PROFILE_PATHS.stoppedPath;\nexport const DESIRED_RELAY_PATH = PROFILE_PATHS.desiredRelayPath;\n\n// 持久化状态\nconst STATE_DIR = PROFILE_PATHS.stateDir;\nexport const SESSIONS_PATH = PROFILE_PATHS.sessionsPath;\nexport const HOOK_REGISTRY_PATH = PROFILE_PATHS.hookRegistryPath;\n\n// 会话数据\nexport const DATA_DIR = PROFILE_PATHS.dataDir;\nexport const PROXY_ID_PATH = PROFILE_PATHS.proxyIdPath;\nconst RELAY_DATA_DIR = PROFILE_PATHS.relayDataDir;\nconst FONT_DIR = PROFILE_PATHS.fontDir;\n\n// 日志\nexport const LOG_DIR = PROFILE_PATHS.logDir;\nexport const SERVICE_LOG_PATH = PROFILE_PATHS.serviceLogPath;\n\nfunction sessionDir(sessionId: string): string {\n return `${DATA_DIR}/${sessionId}`;\n}\n\nexport function sessionPaths(sessionId: string) {\n const dir = sessionDir(sessionId);\n return {\n dir,\n workerSock: `${dir}/worker.sock`,\n };\n}\n\nexport function isInitialized(): boolean {\n return existsSync(CONFIG_PATH);\n}\n\nconst DEFAULT_CONFIG = `{\n \"defaultProfile\": \"default\",\n \"profiles\": {\n \"default\": {\n \"relay\": \"cloud\"\n },\n \"local\": {\n \"relay\": \"local\"\n }\n },\n \"relays\": {\n \"cloud\": {\n \"url\": \"wss://dev-anywhere.example.com\",\n \"proxyToken\": \"\"\n },\n \"local\": {\n \"url\": \"ws://localhost:3100\"\n }\n }\n}\n`;\n\ntype FontAssetSource = {\n dir: string;\n family?: string;\n};\n\nfunction copyFontFamilyIfMissing(targetFontsDir: string, source: FontAssetSource): boolean {\n const family = source.family ?? DEFAULT_FONT_FAMILY;\n const sourceFamilyDir = `${source.dir}/${family}`;\n const targetFamilyDir = `${targetFontsDir}/${family}`;\n if (existsSync(targetFamilyDir) || !existsSync(sourceFamilyDir)) return false;\n mkdirSync(targetFontsDir, { recursive: true });\n cpSync(sourceFamilyDir, targetFamilyDir, { recursive: true });\n return true;\n}\n\nexport function installFontAssetsFromSources(\n targetFontsDir: string,\n sources: FontAssetSource[],\n): boolean {\n for (const source of sources) {\n if (copyFontFamilyIfMissing(targetFontsDir, source)) return true;\n }\n return false;\n}\n\nfunction installFontAssets(): void {\n installFontAssetsFromSources(FONT_DIR, [\n { dir: SOURCE_FONT_ASSETS_DIR, family: DEFAULT_FONT_FAMILY },\n { dir: DIST_FONT_ASSETS_DIR, family: DEFAULT_FONT_FAMILY },\n ]);\n}\n\nexport function initWorkspace(): void {\n ensureProfileWorkspace();\n mkdirSync(RELAY_DATA_DIR, { recursive: true });\n installFontAssets();\n if (!existsSync(CONFIG_PATH)) {\n writeFileSync(CONFIG_PATH, DEFAULT_CONFIG);\n }\n}\n\nexport function ensureProfileWorkspace(): void {\n mkdirSync(RUN_DIR, { recursive: true });\n mkdirSync(STATE_DIR, { recursive: true });\n mkdirSync(DATA_DIR, { recursive: true });\n mkdirSync(LOG_DIR, { recursive: true });\n}\n","import { z } from \"zod\";\nimport {\n UserInputPayloadSchema,\n AssistantMessagePayloadSchema,\n ThinkingPayloadSchema,\n} from \"./chat.js\";\nimport { ToolUseRequestPayloadSchema, ToolResultPayloadSchema } from \"./tool.js\";\nimport {\n SessionCreatePayloadSchema,\n SessionListPayloadSchema,\n SessionSwitchPayloadSchema,\n SessionTerminatePayloadSchema,\n SessionStatusPayloadSchema,\n} from \"./session.js\";\nimport {\n HeartbeatPayloadSchema,\n AuthPayloadSchema,\n SyncRequestPayloadSchema,\n SyncResponsePayloadSchema,\n} from \"./system.js\";\n\n// 信封基础字段:序列号、会话ID、时间戳、来源、协议版本\nconst BaseEnvelopeFields = {\n seq: z.number().int().nonnegative(),\n sessionId: z.string(),\n timestamp: z.number(),\n source: z.enum([\"proxy\", \"client\"]),\n version: z.string(),\n};\n\n// 按 type 字段区分的 discriminatedUnion 信封\nexport const MessageEnvelopeSchema = z.discriminatedUnion(\"type\", [\n // chat (3)\n z.object({\n ...BaseEnvelopeFields,\n type: z.literal(\"user_input\"),\n payload: UserInputPayloadSchema,\n }),\n z.object({\n ...BaseEnvelopeFields,\n type: z.literal(\"assistant_message\"),\n payload: AssistantMessagePayloadSchema,\n }),\n z.object({\n ...BaseEnvelopeFields,\n type: z.literal(\"thinking\"),\n payload: ThinkingPayloadSchema,\n }),\n // tool (4): 工具审批决策属于 relay control,不进入会话消息信封。\n // tool_use_request: 审批流请求(proxy → client),toolId 是 approval requestId\n z.object({\n ...BaseEnvelopeFields,\n type: z.literal(\"tool_use_request\"),\n payload: ToolUseRequestPayloadSchema,\n }),\n // tool_result: 工具执行结果(proxy → client),toolId 对应 assistant_tool_use / tool_use_request 的 toolId\n z.object({\n ...BaseEnvelopeFields,\n type: z.literal(\"tool_result\"),\n payload: ToolResultPayloadSchema,\n }),\n // assistant_tool_use: 纯展示型工具调用(proxy → client),区别于 tool_use_request 无审批语义\n // payload 结构复用 ToolUseRequestPayloadSchema;toolId 是 Claude 分配的 tool_use id\n z.object({\n ...BaseEnvelopeFields,\n type: z.literal(\"assistant_tool_use\"),\n payload: ToolUseRequestPayloadSchema,\n }),\n // session (5)\n z.object({\n ...BaseEnvelopeFields,\n type: z.literal(\"session_create\"),\n payload: SessionCreatePayloadSchema,\n }),\n z.object({\n ...BaseEnvelopeFields,\n type: z.literal(\"session_list\"),\n payload: SessionListPayloadSchema,\n }),\n z.object({\n ...BaseEnvelopeFields,\n type: z.literal(\"session_switch\"),\n payload: SessionSwitchPayloadSchema,\n }),\n z.object({\n ...BaseEnvelopeFields,\n type: z.literal(\"session_terminate\"),\n payload: SessionTerminatePayloadSchema,\n }),\n z.object({\n ...BaseEnvelopeFields,\n type: z.literal(\"session_status\"),\n payload: SessionStatusPayloadSchema,\n }),\n // system (5)\n z.object({\n ...BaseEnvelopeFields,\n type: z.literal(\"heartbeat\"),\n payload: HeartbeatPayloadSchema,\n }),\n z.object({\n ...BaseEnvelopeFields,\n type: z.literal(\"auth\"),\n payload: AuthPayloadSchema,\n }),\n z.object({\n ...BaseEnvelopeFields,\n type: z.literal(\"sync_request\"),\n payload: SyncRequestPayloadSchema,\n }),\n z.object({\n ...BaseEnvelopeFields,\n type: z.literal(\"sync_response\"),\n payload: SyncResponsePayloadSchema,\n }),\n]);\n\nexport type MessageEnvelope = z.infer<typeof MessageEnvelopeSchema>;\n\nexport type MessageType = MessageEnvelope[\"type\"];\n\nexport type MessageSource = MessageEnvelope[\"source\"];\n","import { z } from \"zod\";\n\n// 用户输入消息\nexport const UserInputPayloadSchema = z.object({\n text: z.string().min(1),\n messageId: z.string().min(1).optional(),\n});\n\nexport type UserInputPayload = z.infer<typeof UserInputPayloadSchema>;\n\n// 助手回复消息,isPartial 标识是否为流式中间结果\nexport const AssistantMessagePayloadSchema = z.object({\n text: z.string(),\n isPartial: z.boolean(),\n});\n\nexport type AssistantMessagePayload = z.infer<typeof AssistantMessagePayloadSchema>;\n\n// 思考过程消息\nexport const ThinkingPayloadSchema = z.object({\n text: z.string(),\n});\n\nexport type ThinkingPayload = z.infer<typeof ThinkingPayloadSchema>;\n","import { z } from \"zod\";\n\n// 工具调用请求\nexport const ToolUseRequestPayloadSchema = z.object({\n toolName: z.string(),\n toolId: z.string(),\n parameters: z.record(z.string(), z.unknown()),\n});\n\nexport type ToolUseRequestPayload = z.infer<typeof ToolUseRequestPayloadSchema>;\n\n// 工具调用批准,whitelistTool 为 true 时将该工具加入会话级白名单自动审批\nexport const ToolApprovePayloadSchema = z.object({\n toolId: z.string(),\n whitelistTool: z.boolean().optional(),\n});\n\nexport type ToolApprovePayload = z.infer<typeof ToolApprovePayloadSchema>;\n\n// 工具调用拒绝\nexport const ToolDenyPayloadSchema = z.object({\n toolId: z.string(),\n reason: z.string().optional(),\n});\n\nexport type ToolDenyPayload = z.infer<typeof ToolDenyPayloadSchema>;\n\n// 工具调用结果\nexport const ToolResultPayloadSchema = z.object({\n toolId: z.string(),\n result: z.unknown(),\n isError: z.boolean(),\n});\n\nexport type ToolResultPayload = z.infer<typeof ToolResultPayloadSchema>;\n","import { z } from \"zod\";\n\nconst sessionStateValues = [\"idle\", \"working\", \"waiting_approval\", \"error\", \"terminated\"] as const;\nconst providerValues = [\"claude\", \"codex\"] as const;\nconst ptyOwnerValues = [\"local-terminal\", \"proxy-hosted\"] as const;\nconst agentStatusPhaseValues = [\n \"idle\",\n \"thinking\",\n \"tool_use\",\n \"outputting\",\n \"waiting_permission\",\n \"error\",\n] as const;\n\n// 会话信息,用于会话列表展示\n// lastActive: 最近一次状态变更或运行时活动时间戳 (ms), 用于列表\"最近活动 N 分钟前\"显示, 可选\nexport const SessionInfoSchema = z.object({\n sessionId: z.string(),\n name: z.string().optional(),\n state: z.enum(sessionStateValues),\n mode: z.enum([\"pty\", \"json\"]).optional(),\n provider: z.enum(providerValues),\n // PTY 尺寸所有权:\n // - local-terminal: 本地 terminal 进程持有真实 PTY,Web 只按原始 cols/rows 展示\n // - proxy-hosted: serve 内托管 PTY,Web 可按视口请求 resize\n ptyOwner: z.enum(ptyOwnerValues).optional(),\n lastActive: z.number().optional(),\n});\nexport type SessionInfo = z.infer<typeof SessionInfoSchema>;\n\n// 创建会话\n// streamDelta: client 端系统设置\"逐字流式\"toggle,true 时 proxy spawn 带 --include-partial-messages\nexport const SessionCreatePayloadSchema = z.object({\n name: z.string().optional(),\n cwd: z.string().optional(),\n streamDelta: z.boolean().optional(),\n});\n\nexport type SessionCreatePayload = z.infer<typeof SessionCreatePayloadSchema>;\n\n// 会话列表\nexport const SessionListPayloadSchema = z.object({\n sessions: z.array(SessionInfoSchema),\n});\n\nexport type SessionListPayload = z.infer<typeof SessionListPayloadSchema>;\n\n// 切换会话\nexport const SessionSwitchPayloadSchema = z.object({\n sessionId: z.string(),\n});\n\nexport type SessionSwitchPayload = z.infer<typeof SessionSwitchPayloadSchema>;\n\n// 终止会话\nexport const SessionTerminatePayloadSchema = z.object({\n sessionId: z.string(),\n});\n\nexport type SessionTerminatePayload = z.infer<typeof SessionTerminatePayloadSchema>;\n\n// 会话状态变更\n// lastActive: 触发本次状态迁移或活动刷新的时间戳 (ms),用于列表相对时间显示。\nexport const SessionStatusPayloadSchema = z.object({\n sessionId: z.string(),\n state: z.enum(sessionStateValues),\n lastActive: z.number(),\n});\n\nexport type SessionStatusPayload = z.infer<typeof SessionStatusPayloadSchema>;\n\n// PTY 语义状态事件,描述当前 PTY 处于何种状态\nexport const PtyStatePayloadSchema = z.object({\n state: z.enum([\"working\", \"turn_complete\", \"approval_wait\", \"mid_pause\"]),\n title: z.string().optional(),\n tool: z.string().optional(),\n});\nexport type PtyStatePayload = z.infer<typeof PtyStatePayloadSchema>;\n\nexport const AgentStatusPayloadSchema = z.object({\n provider: z.enum(providerValues),\n phase: z.enum(agentStatusPhaseValues),\n seq: z.number().int().nonnegative(),\n updatedAt: z.number(),\n toolName: z.string().optional(),\n toolInput: z.record(z.string(), z.unknown()).optional(),\n permissionRequest: z\n .object({\n requestId: z.string(),\n toolName: z.string(),\n input: z.record(z.string(), z.unknown()),\n })\n .optional(),\n permissionResolution: z\n .object({\n requestId: z.string(),\n outcome: z.enum([\"allow\", \"deny\"]),\n })\n .optional(),\n summary: z.string().optional(),\n});\nexport type AgentStatusPayload = z.infer<typeof AgentStatusPayloadSchema>;\n","import { z } from \"zod\";\n\n// 心跳消息,空 payload\nexport const HeartbeatPayloadSchema = z.object({});\n\nexport type HeartbeatPayload = z.infer<typeof HeartbeatPayloadSchema>;\n\n// 认证消息,支持配对码和 token 两种方式\nexport const AuthPayloadSchema = z.object({\n pairingCode: z.string().optional(),\n token: z.string().optional(),\n});\n\nexport type AuthPayload = z.infer<typeof AuthPayloadSchema>;\n\n// 同步请求,客户端发送已收到的最大序列号\nexport const SyncRequestPayloadSchema = z.object({\n lastSeq: z.number().int().nonnegative(),\n});\n\nexport type SyncRequestPayload = z.infer<typeof SyncRequestPayloadSchema>;\n\n// 同步响应,使用 z.unknown 数组避免循环引用;恢复协议稳定后再收紧类型\nexport const SyncResponsePayloadSchema = z.object({\n messages: z.array(z.record(z.string(), z.unknown())),\n});\n\nexport type SyncResponsePayload = z.infer<typeof SyncResponsePayloadSchema>;\n","import type { MessageEnvelope } from \"../schemas/envelope.js\";\nimport { MessageEnvelopeSchema } from \"../schemas/envelope.js\";\n\n// 构建经过 schema 验证的消息信封\n// seq 由调用方提供,必须与 EventStore per-session seq 一致,保证 proxy 和 relay 对账可靠\nexport function buildMessage<T extends MessageEnvelope[\"type\"]>(\n type: T,\n sessionId: string,\n seq: number,\n payload: Extract<MessageEnvelope, { type: T }>[\"payload\"],\n source: \"proxy\" | \"client\",\n): Extract<MessageEnvelope, { type: T }> {\n const envelope = {\n seq,\n sessionId,\n type,\n payload,\n timestamp: Date.now(),\n source,\n version: \"1.0\",\n };\n return MessageEnvelopeSchema.parse(envelope) as Extract<MessageEnvelope, { type: T }>;\n}\n","import { z } from \"zod\";\nimport { AgentStatusPayloadSchema, PtyStatePayloadSchema } from \"./session.js\";\nimport { ToolApprovePayloadSchema, ToolDenyPayloadSchema } from \"./tool.js\";\nimport { RelayErrorCode } from \"../constants/relay-errors.js\";\nimport { ControlErrorCode } from \"../constants/control-errors.js\";\n\n// 控制消息中复用的子类型\nexport const ProxyInfoSchema = z.object({\n proxyId: z.string(),\n name: z.string().optional(),\n online: z.boolean(),\n sessions: z.array(z.string()).optional(),\n});\nexport type ProxyInfo = z.infer<typeof ProxyInfoSchema>;\n\nexport const AgentCliAvailabilitySchema = z.object({\n available: z.boolean(),\n command: z.string().optional(),\n error: z.string().optional(),\n suggestions: z.array(z.string()).optional(),\n});\nexport type AgentCliAvailability = z.infer<typeof AgentCliAvailabilitySchema>;\n\nexport const AgentCliStatusSchema = z.object({\n claude: AgentCliAvailabilitySchema,\n codex: AgentCliAvailabilitySchema,\n});\nexport type AgentCliStatus = z.infer<typeof AgentCliStatusSchema>;\n\nexport const DirEntrySchema = z.object({ name: z.string(), isDir: z.boolean() });\nexport type DirEntry = z.infer<typeof DirEntrySchema>;\n\nexport const FileTreeGroupSchema = z.object({\n path: z.string(),\n entries: z.array(DirEntrySchema),\n});\nexport type FileTreeGroup = z.infer<typeof FileTreeGroupSchema>;\n\nexport const CommandEntrySchema = z.object({\n name: z.string(),\n description: z.string(),\n argumentHint: z.string().optional(),\n source: z.string(),\n});\nexport type CommandEntry = z.infer<typeof CommandEntrySchema>;\n\nexport const HistorySessionSchema = z.object({\n id: z.string(),\n title: z.string(),\n projectDir: z.string(),\n updatedAt: z.number(),\n provider: z.enum([\"claude\", \"codex\"]).optional(),\n});\nexport type HistorySession = z.infer<typeof HistorySessionSchema>;\n\nconst SessionHistoryMessageSchema = z.object({\n role: z.enum([\"user\", \"assistant\"]),\n text: z.string(),\n timestamp: z.number().optional(),\n cursor: z.string().optional(),\n});\n\ntype RelayControlDirection = \"proxy_to_client\" | \"client_to_proxy\";\ntype EmptyShape = Record<never, never>;\nconst RequestIdShape = { requestId: z.string().min(1).optional() };\nconst ControlErrorCodeSchema = z.enum(\n Object.values(ControlErrorCode) as [ControlErrorCode, ...ControlErrorCode[]],\n);\nconst RequestErrorShape = {\n error: z.string().optional(),\n errorCode: ControlErrorCodeSchema.optional(),\n};\nconst ClipboardImageMimeTypeSchema = z.enum([\"image/png\", \"image/jpeg\", \"image/webp\", \"image/gif\"]);\n\ntype ControlDefinition<T extends string, S extends z.ZodRawShape> = {\n type: T;\n directions: ReadonlySet<RelayControlDirection>;\n schema: z.ZodObject<{ type: z.ZodLiteral<T> } & S>;\n};\n\nfunction control<T extends string>(type: T): ControlDefinition<T, EmptyShape>;\nfunction control<T extends string>(\n type: T,\n shape: undefined,\n directions: RelayControlDirection | RelayControlDirection[],\n): ControlDefinition<T, EmptyShape>;\nfunction control<T extends string, S extends z.ZodRawShape>(\n type: T,\n shape: S,\n directions?: RelayControlDirection | RelayControlDirection[],\n): ControlDefinition<T, S>;\nfunction control<T extends string, S extends z.ZodRawShape>(\n type: T,\n shape?: S,\n directions?: RelayControlDirection | RelayControlDirection[],\n): ControlDefinition<T, S | EmptyShape> {\n return {\n type,\n directions: new Set(Array.isArray(directions) ? directions : directions ? [directions] : []),\n schema: z.object({\n type: z.literal(type),\n ...(shape ?? {}),\n }) as z.ZodObject<{ type: z.ZodLiteral<T> } & (S | EmptyShape)>,\n };\n}\n\n// 中转服务器控制消息,独立于 MessageEnvelope 的传输层协议\nconst relayControlDefinitions = [\n control(\"proxy_register\", {\n proxyId: z.string().min(1),\n name: z.string().optional(),\n }),\n control(\"proxy_register_response\", {\n status: z.enum([\"new\", \"reconnected\"]),\n }),\n control(\"proxy_list_request\", RequestIdShape),\n control(\"proxy_list_response\", {\n ...RequestIdShape,\n proxies: z.array(ProxyInfoSchema),\n }),\n control(\"proxy_select\", { ...RequestIdShape, proxyId: z.string().min(1) }),\n control(\"proxy_select_response\", {\n ...RequestIdShape,\n success: z.boolean(),\n proxyId: z.string().optional(),\n ...RequestErrorShape,\n }),\n control(\"relay_error\", {\n code: z.enum(Object.values(RelayErrorCode) as [RelayErrorCode, ...RelayErrorCode[]]),\n message: z.string(),\n }),\n\n // 客户端注册协议\n control(\"client_register\", {\n clientId: z.string().min(1),\n }),\n control(\"client_register_response\", {\n status: z.enum([\"restored\", \"proxy_offline\", \"new\"]),\n proxyId: z.string().optional(),\n }),\n\n // Proxy 离线通知\n control(\"proxy_offline\", {\n proxyId: z.string(),\n }),\n\n // Proxy 主动断开,relay 立即清理资源\n control(\"proxy_disconnect\", {\n proxyId: z.string().min(1),\n }),\n\n // Proxy 重连后通知 client 恢复\n control(\"proxy_online\", {\n proxyId: z.string().min(1),\n }),\n\n // 目录列表请求与响应\n control(\n \"dir_list_request\",\n {\n proxyId: z.string().min(1).optional(),\n ...RequestIdShape,\n path: z.string(),\n },\n \"client_to_proxy\",\n ),\n control(\n \"dir_list_response\",\n { ...RequestIdShape, ...RequestErrorShape, entries: z.array(DirEntrySchema), path: z.string() },\n \"proxy_to_client\",\n ),\n\n // 目录创建请求与响应\n control(\"dir_create_request\", { ...RequestIdShape, path: z.string() }, \"client_to_proxy\"),\n control(\n \"dir_create_response\",\n {\n ...RequestIdShape,\n ...RequestErrorShape,\n path: z.string(),\n success: z.boolean(),\n },\n \"proxy_to_client\",\n ),\n\n // 命令列表推送,proxy 将可用命令列表推给 client\n control(\"command_list_push\", { commands: z.array(CommandEntrySchema) }, \"proxy_to_client\"),\n\n // 文件树推送: 按目录分组, 首组 path 即为 session cwd\n // 前端直接把每组写入 tree[path], 与 dir_list_response 共享 cache slot\n control(\n \"file_tree_push\",\n {\n groups: z.array(FileTreeGroupSchema),\n },\n \"proxy_to_client\",\n ),\n\n // 会话列表请求与权限模式变更\n control(\"session_list\", undefined, [\"client_to_proxy\", \"proxy_to_client\"]),\n control(\n \"permission_mode_change\",\n {\n mode: z.enum([\"default\", \"auto_accept\", \"plan\"]),\n // sessionId 可选:传入时 proxy 按该会话的 mode 分叉(PTY 发 Tab ANSI),未传走全局日志行为\n sessionId: z.string().optional(),\n },\n \"client_to_proxy\",\n ),\n\n // 会话历史浏览\n control(\"session_history_request\", RequestIdShape, \"client_to_proxy\"),\n control(\n \"session_history_response\",\n { ...RequestIdShape, sessions: z.array(HistorySessionSchema) },\n \"proxy_to_client\",\n ),\n\n // PTY 语义状态,从 Envelope 迁移到 Control 层\n control(\n \"pty_state\",\n { sessionId: z.string(), payload: PtyStatePayloadSchema },\n \"proxy_to_client\",\n ),\n\n // Provider 语义状态,来自 Claude/Codex hook 等结构化事件,不从 PTY 字节推断\n control(\n \"agent_status\",\n { sessionId: z.string(), payload: AgentStatusPayloadSchema },\n \"proxy_to_client\",\n ),\n\n // 终端标题变化,proxy -> client\n control(\"terminal_title\", { sessionId: z.string(), title: z.string() }, \"proxy_to_client\"),\n\n // 终端尺寸变化,proxy -> client\n control(\n \"terminal_resize\",\n { sessionId: z.string(), cols: z.number().int().positive(), rows: z.number().int().positive() },\n \"proxy_to_client\",\n ),\n control(\n \"terminal_resize_request\",\n { sessionId: z.string(), cols: z.number().int().positive(), rows: z.number().int().positive() },\n \"client_to_proxy\",\n ),\n\n // 远程终止 JSON 会话,client -> proxy\n control(\"session_terminate\", { sessionId: z.string() }, \"client_to_proxy\"),\n\n // 中断当前 turn,client -> proxy,SIGINT 到 worker 进程让 claude CLI abort 当前流\n control(\"session_worker_abort\", { sessionId: z.string() }, \"client_to_proxy\"),\n\n // turn 完成信号,proxy -> client,对应 claude stream-json 的 result 事件\n control(\n \"turn_result\",\n {\n sessionId: z.string(),\n success: z.boolean(),\n isError: z.boolean(),\n // stream-json result.result 是本轮最终文本。assistant_message 流丢失或 CLI 未发增量时,\n // Web 用它作为 JSON 模式兜底展示,避免 turn 已结束但界面空白。\n result: z.string().optional(),\n },\n \"proxy_to_client\",\n ),\n\n // 客户端发送到 PTY 的原始字节(ANSI 序列),不追加换行\n control(\n \"remote_input_raw\",\n { sessionId: z.string().min(1), data: z.string() },\n \"client_to_proxy\",\n ),\n control(\n \"clipboard_image_upload\",\n {\n ...RequestIdShape,\n sessionId: z.string().min(1),\n mimeType: ClipboardImageMimeTypeSchema,\n dataBase64: z.string().min(1),\n fileName: z.string().optional(),\n },\n \"client_to_proxy\",\n ),\n control(\n \"clipboard_image_upload_response\",\n {\n ...RequestIdShape,\n ...RequestErrorShape,\n sessionId: z.string().min(1),\n success: z.boolean(),\n path: z.string(),\n },\n \"proxy_to_client\",\n ),\n control(\n \"image_preview_request\",\n {\n ...RequestIdShape,\n sessionId: z.string().min(1),\n path: z.string().min(1),\n },\n \"client_to_proxy\",\n ),\n control(\n \"image_preview_response\",\n {\n ...RequestIdShape,\n ...RequestErrorShape,\n sessionId: z.string().min(1),\n success: z.boolean(),\n path: z.string(),\n mimeType: ClipboardImageMimeTypeSchema.optional(),\n dataBase64: z.string().optional(),\n size: z.number().int().nonnegative().optional(),\n },\n \"proxy_to_client\",\n ),\n\n // 客户端询问 proxy 的环境信息 (home 路径等), client -> proxy -> response\n // FilePathPicker 用 homePath 作为 select 模式下的默认起点, 新建会话时打开即可浏览\n control(\"proxy_info_request\", RequestIdShape, \"client_to_proxy\"),\n control(\n \"proxy_info\",\n { ...RequestIdShape, homePath: z.string(), agentCli: AgentCliStatusSchema },\n \"proxy_to_client\",\n ),\n control(\n \"agent_cli_config_update\",\n { ...RequestIdShape, provider: z.enum([\"claude\", \"codex\"]), path: z.string().min(1) },\n \"client_to_proxy\",\n ),\n control(\n \"agent_cli_config_update_response\",\n {\n ...RequestIdShape,\n provider: z.enum([\"claude\", \"codex\"]),\n agentCli: AgentCliStatusSchema.optional(),\n ...RequestErrorShape,\n },\n \"proxy_to_client\",\n ),\n\n // 远程创建 JSON 会话,client -> proxy -> response\n control(\n \"session_create\",\n {\n ...RequestIdShape,\n cwd: z.string(),\n provider: z.enum([\"claude\", \"codex\"]),\n mode: z.enum([\"json\", \"pty\"]).optional(),\n resumeSessionId: z.string().optional(),\n // 透传给 claude CLI 的 --permission-mode, undefined 时 proxy 兜底为 \"default\"\n permissionMode: z\n .enum([\"default\", \"auto\", \"acceptEdits\", \"plan\", \"bypassPermissions\", \"dontAsk\"])\n .optional(),\n },\n \"client_to_proxy\",\n ),\n control(\n \"session_create_response\",\n {\n ...RequestIdShape,\n sessionId: z.string(),\n mode: z.enum([\"json\", \"pty\"]).optional(),\n provider: z.enum([\"claude\", \"codex\"]).optional(),\n ptyOwner: z.enum([\"local-terminal\", \"proxy-hosted\"]).optional(),\n ...RequestErrorShape,\n },\n \"proxy_to_client\",\n ),\n\n // 客户端请求会话历史消息,client -> proxy\n control(\n \"session_messages_request\",\n {\n ...RequestIdShape,\n sessionId: z.string(),\n limit: z.number().int().min(1).max(200).optional(),\n before: z.string().optional(),\n },\n \"client_to_proxy\",\n ),\n\n // 客户端请求会话资源(命令列表 + 文件树),client -> proxy\n control(\n \"session_resources_request\",\n { ...RequestIdShape, sessionId: z.string() },\n \"client_to_proxy\",\n ),\n control(\n \"session_resources_response\",\n {\n ...RequestIdShape,\n ...RequestErrorShape,\n sessionId: z.string(),\n commands: z.array(CommandEntrySchema),\n groups: z.array(FileTreeGroupSchema),\n },\n \"proxy_to_client\",\n ),\n\n // 客户端请求当前 provider 语义状态;不经 relay 缓存,由 proxy 返回当前值\n control(\n \"agent_status_request\",\n { ...RequestIdShape, sessionId: z.string().optional() },\n \"client_to_proxy\",\n ),\n control(\n \"agent_status_response\",\n {\n ...RequestIdShape,\n statuses: z.array(z.object({ sessionId: z.string(), payload: AgentStatusPayloadSchema })),\n },\n \"proxy_to_client\",\n ),\n\n // 客户端确认已收到审批请求;proxy 只记录送达状态,不把它当成用户决策\n control(\n \"permission_request_delivered\",\n { sessionId: z.string(), requestId: z.string() },\n \"client_to_proxy\",\n ),\n control(\n \"tool_approve\",\n { sessionId: z.string(), payload: ToolApprovePayloadSchema },\n \"client_to_proxy\",\n ),\n control(\n \"tool_deny\",\n { sessionId: z.string(), payload: ToolDenyPayloadSchema },\n \"client_to_proxy\",\n ),\n\n // proxy 确认用户决策已进入 provider/worker 路径;web 用它更新审批卡片状态\n control(\n \"permission_decision_result\",\n {\n sessionId: z.string(),\n requestId: z.string(),\n outcome: z.enum([\"allow\", \"deny\"]),\n delivered: z.boolean(),\n message: z.string().optional(),\n },\n \"proxy_to_client\",\n ),\n\n // proxy 推送当前 pending 的工具审批列表,client 据此恢复审批卡片\n control(\n \"pending_approvals_push\",\n {\n sessionId: z.string(),\n approvals: z.array(\n z.object({\n requestId: z.string(),\n toolName: z.string(),\n input: z.record(z.string(), z.unknown()),\n }),\n ),\n },\n \"proxy_to_client\",\n ),\n\n // 恢复会话时推送历史消息,proxy -> client\n control(\n \"session_history_messages\",\n {\n ...RequestIdShape,\n sessionId: z.string(),\n before: z.string().optional(),\n messages: z.array(SessionHistoryMessageSchema),\n hasMore: z.boolean().optional(),\n nextBefore: z.string().optional(),\n },\n \"proxy_to_client\",\n ),\n\n // proxy 重连后同步活跃 session 列表给 relay\n control(\"session_sync\", {\n sessions: z.array(\n z.object({\n id: z.string(),\n mode: z.enum([\"pty\", \"json\"]),\n provider: z.enum([\"claude\", \"codex\"]),\n ptyOwner: z.enum([\"local-terminal\", \"proxy-hosted\"]).optional(),\n state: z.string(),\n }),\n ),\n }),\n\n // PTY 会话订阅,client -> proxy,触发 terminal serialize() 返回当前状态\n control(\n \"session_subscribe\",\n { sessionId: z.string(), requestId: z.string().optional() },\n \"client_to_proxy\",\n ),\n\n // PTY 会话快照,proxy -> client,serialize() 的全量终端状态\n control(\n \"session_snapshot\",\n {\n sessionId: z.string(),\n cols: z.number().int().positive(),\n rows: z.number().int().positive(),\n data: z.string(),\n outputSeq: z.number().int().nonnegative(),\n requestId: z.string().optional(),\n },\n \"proxy_to_client\",\n ),\n] as const;\n\nconst relayControlSchemas = relayControlDefinitions.map((definition) => definition.schema) as [\n (typeof relayControlDefinitions)[number][\"schema\"],\n ...Array<(typeof relayControlDefinitions)[number][\"schema\"]>,\n];\n\nexport const RelayControlSchema = z.discriminatedUnion(\"type\", relayControlSchemas);\n\nexport type RelayControlMessage = z.infer<typeof RelayControlSchema>;\nexport type RelayControlType = RelayControlMessage[\"type\"];\n\nexport const ProxyToClientRelayControlTypes = new Set(\n relayControlDefinitions\n .filter((definition) => definition.directions.has(\"proxy_to_client\"))\n .map((definition) => definition.type),\n);\n\nexport function isProxyToClientRelayControlType(type: RelayControlType): boolean {\n return ProxyToClientRelayControlTypes.has(type);\n}\n\nexport const ClientToProxyRelayControlTypes = new Set(\n relayControlDefinitions\n .filter((definition) => definition.directions.has(\"client_to_proxy\"))\n .map((definition) => definition.type),\n);\n\nexport function isClientToProxyRelayControlType(type: RelayControlType): boolean {\n return ClientToProxyRelayControlTypes.has(type);\n}\n","// relay 实际发出的 6 个错误码。schema 侧 RelayControlSchema.relay_error.code 用 z.enum 收紧,\n// handler 侧用这个常量引用避免裸字面量拼错。\nexport const RelayErrorCode = {\n NOT_REGISTERED: \"NOT_REGISTERED\",\n NOT_BOUND: \"NOT_BOUND\",\n PROXY_OFFLINE: \"PROXY_OFFLINE\",\n INVALID_MESSAGE: \"INVALID_MESSAGE\",\n UNSUPPORTED: \"UNSUPPORTED\",\n INVALID_RANGE: \"INVALID_RANGE\",\n} as const;\n\nexport type RelayErrorCode = (typeof RelayErrorCode)[keyof typeof RelayErrorCode];\n","export const ControlErrorCode = {\n INVALID_PATH: \"INVALID_PATH\",\n PATH_NOT_FOUND: \"PATH_NOT_FOUND\",\n PATH_NOT_DIRECTORY: \"PATH_NOT_DIRECTORY\",\n PATH_ACCESS_DENIED: \"PATH_ACCESS_DENIED\",\n PROXY_OFFLINE: \"PROXY_OFFLINE\",\n SESSION_NOT_FOUND: \"SESSION_NOT_FOUND\",\n PROVIDER_UNSUPPORTED: \"PROVIDER_UNSUPPORTED\",\n WORKER_START_FAILED: \"WORKER_START_FAILED\",\n PROCESS_START_FAILED: \"PROCESS_START_FAILED\",\n UNKNOWN: \"UNKNOWN\",\n} as const;\n\nexport type ControlErrorCode = (typeof ControlErrorCode)[keyof typeof ControlErrorCode];\n","// 会话状态枚举\nexport const SessionState = {\n IDLE: \"idle\",\n WORKING: \"working\",\n WAITING_APPROVAL: \"waiting_approval\",\n ERROR: \"error\",\n TERMINATED: \"terminated\",\n} as const;\n\nexport type SessionState = (typeof SessionState)[keyof typeof SessionState];\n","import {\n lstatSync,\n mkdirSync,\n readdirSync,\n renameSync,\n statSync,\n symlinkSync,\n unlinkSync,\n} from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { basename, join } from \"node:path\";\nimport pino from \"pino\";\n\nexport type { Logger } from \"pino\";\n\nexport interface CreateLoggerOptions {\n name: string;\n level?: string;\n logDir?: string;\n retention?: number;\n stdout?: boolean;\n silent?: boolean;\n}\n\nconst DEFAULT_LOG_DIR = `${homedir()}/.dev-anywhere/logs`;\nconst DEFAULT_LOG_RETENTION = 50;\n\nconst PROCESS_LOG_RUN_ID = sanitizeRunId(\n `${new Date().toISOString().replace(/[:.]/g, \"-\")}-${process.pid}`,\n);\n\nfunction sanitizeRunId(runId: string): string {\n return runId.replace(/[^a-zA-Z0-9._-]/g, \"_\");\n}\n\nfunction linkLatestLog(logDir: string, name: string, filePath: string, runId: string): void {\n const latestPath = join(logDir, `${name}.log`);\n\n try {\n const stat = lstatSync(latestPath);\n if (stat.isSymbolicLink()) {\n unlinkSync(latestPath);\n } else {\n renameSync(latestPath, join(logDir, `${name}-legacy-${runId}.log`));\n }\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code !== \"ENOENT\") return;\n }\n\n try {\n symlinkSync(basename(filePath), latestPath);\n } catch {\n // 日志本体仍然写入 run-specific 文件;latest 链接失败不应阻塞服务启动。\n }\n}\n\nfunction resolveRetention(retention: number | undefined): number {\n if (retention === undefined) return DEFAULT_LOG_RETENTION;\n return Number.isFinite(retention) && retention >= 0\n ? Math.floor(retention)\n : DEFAULT_LOG_RETENTION;\n}\n\nfunction pruneOldLogs(\n logDir: string,\n name: string,\n currentFilePath: string,\n retention: number | undefined,\n): void {\n const keep = resolveRetention(retention);\n if (keep === 0) return;\n\n const currentFileName = basename(currentFilePath);\n const prefix = `${name}-`;\n const candidates = readdirSync(logDir)\n .filter(\n (entry) => entry.startsWith(prefix) && entry.endsWith(\".log\") && entry !== currentFileName,\n )\n .map((entry) => {\n const path = join(logDir, entry);\n try {\n return { path, mtimeMs: statSync(path).mtimeMs };\n } catch {\n return null;\n }\n })\n .filter((entry): entry is { path: string; mtimeMs: number } => entry !== null)\n .sort((a, b) => b.mtimeMs - a.mtimeMs);\n\n for (const stale of candidates.slice(Math.max(0, keep - 1))) {\n try {\n unlinkSync(stale.path);\n } catch {\n // 日志清理失败不能影响主进程启动。\n }\n }\n}\n\nfunction buildPinoLogger(options: CreateLoggerOptions): pino.Logger {\n const {\n name,\n level = \"info\",\n logDir = DEFAULT_LOG_DIR,\n retention,\n stdout = false,\n silent = false,\n } = options;\n\n if (silent) {\n return pino({ level: \"silent\" });\n }\n\n mkdirSync(logDir, { recursive: true });\n\n const runId = PROCESS_LOG_RUN_ID;\n const filePath = join(logDir, `${name}-${runId}.log`);\n linkLatestLog(logDir, name, filePath, runId);\n pruneOldLogs(logDir, name, filePath, retention);\n const streams: pino.StreamEntry[] = [{ stream: pino.destination(filePath) }];\n\n if (stdout) {\n streams.unshift({ stream: process.stdout });\n }\n\n return pino({ level }, pino.multistream(streams));\n}\n\n// 返回一个 lazy proxy:调用 createLogger 本身不触发 mkdirSync / pino.destination\n// 等任何文件 IO,只有第一次实际访问 logger 的方法/属性时才构造底层 pino Logger。\n// 这样 `dev-anywhere -v` / `dev-anywhere init` 等不需要写日志的命令路径不会\n// 落地空 log 文件,也避免异步 SonicBoom 在 process.exit 时未 ready 的 race。\nexport function createLogger(options: CreateLoggerOptions): pino.Logger {\n let real: pino.Logger | null = null;\n const ensure = (): pino.Logger => {\n if (!real) real = buildPinoLogger(options);\n return real;\n };\n\n return new Proxy(Object.create(null) as pino.Logger, {\n get(_target, prop) {\n const target = ensure();\n const value = Reflect.get(target, prop, target);\n return typeof value === \"function\" ? value.bind(target) : value;\n },\n set(_target, prop, value) {\n return Reflect.set(ensure(), prop, value);\n },\n has(_target, prop) {\n return Reflect.has(ensure(), prop);\n },\n ownKeys() {\n return Reflect.ownKeys(ensure());\n },\n getOwnPropertyDescriptor(_target, prop) {\n return Reflect.getOwnPropertyDescriptor(ensure(), prop);\n },\n });\n}\n"],"mappings":"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","names":["z","z","z","z","z","z","z","mkdirSync","homedir"]}
1
+ {"version":3,"sources":["../src/common/paths.ts","../../../packages/shared/src/schemas/envelope.ts","../../../packages/shared/src/schemas/chat.ts","../../../packages/shared/src/schemas/tool.ts","../../../packages/shared/src/schemas/session.ts","../../../packages/shared/src/schemas/system.ts","../../../packages/shared/src/builders/index.ts","../../../packages/shared/src/schemas/relay-control.ts","../../../packages/shared/src/constants/relay-errors.ts","../../../packages/shared/src/constants/control-errors.ts","../../../packages/shared/src/constants/session.ts","../../../packages/shared/src/logger.ts"],"sourcesContent":["import { cpSync, existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n// 所有 dev-anywhere 文件路径的集中定义\n// 使用 os.homedir():POSIX 走 HOME,Windows 走 USERPROFILE;未设置时回退到 getpwuid。\n// 相比 process.env.HOME,不会在缺失环境变量时构造出 \"undefined/.dev-anywhere\"。\nconst HOME = homedir();\nconst MODULE_DIR = dirname(fileURLToPath(import.meta.url));\nconst SOURCE_FONT_ASSETS_DIR = resolve(MODULE_DIR, \"../../assets/fonts\");\nconst DIST_FONT_ASSETS_DIR = resolve(MODULE_DIR, \"../assets/fonts\");\nconst DEFAULT_FONT_FAMILY = \"sarasa-fixed-sc\";\nexport const DEFAULT_PROXY_PROFILE = \"default\";\n\ninterface ProxyProfilePaths {\n profileName: string;\n isDefaultProfile: boolean;\n appDir: string;\n profileDir: string;\n configPath: string;\n runDir: string;\n sockPath: string;\n pidPath: string;\n stoppedPath: string;\n desiredRelayPath: string;\n stateDir: string;\n sessionsPath: string;\n hookRegistryPath: string;\n dataDir: string;\n proxyIdPath: string;\n logDir: string;\n serviceLogPath: string;\n relayDataDir: string;\n fontDir: string;\n}\n\nexport function normalizeProxyProfileName(value: string | undefined): string {\n const normalized = value?.trim() || DEFAULT_PROXY_PROFILE;\n if (\n normalized === \".\" ||\n normalized === \"..\" ||\n !/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,63}$/.test(normalized)\n ) {\n throw new Error(\n `Invalid dev-anywhere profile \"${normalized}\". Use 1-64 letters, numbers, \".\", \"_\" or \"-\".`,\n );\n }\n return normalized;\n}\n\nfunction readProxyProfileNameFromArgv(argv: readonly string[]): string | undefined {\n const args = [...argv];\n while (args[0] === \"--\") args.shift();\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n if (arg === \"claude\" || arg === \"codex\") return undefined;\n if (arg === \"--profile\") {\n const next = args[i + 1];\n return next && !next.startsWith(\"-\") ? next : undefined;\n }\n if (arg.startsWith(\"--profile=\")) {\n return arg.slice(\"--profile=\".length);\n }\n }\n return undefined;\n}\n\nfunction resolveProxyProfileName(\n argv: readonly string[] = process.argv.slice(2),\n home: string = HOME,\n): string {\n return normalizeProxyProfileName(\n readProxyProfileNameFromArgv(argv) ?? readDefaultProfileFromConfig(home),\n );\n}\n\nfunction readDefaultProfileFromConfig(home: string): string | undefined {\n try {\n const parsed = JSON.parse(readFileSync(`${home}/.dev-anywhere/config.json`, \"utf-8\")) as {\n defaultProfile?: unknown;\n };\n return typeof parsed.defaultProfile === \"string\" ? parsed.defaultProfile : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport function buildProxyProfilePaths(home: string, profileName: string): ProxyProfilePaths {\n const normalizedProfile = normalizeProxyProfileName(profileName);\n const appDir = `${home}/.dev-anywhere`;\n const isDefaultProfile = normalizedProfile === DEFAULT_PROXY_PROFILE;\n const profileDir = isDefaultProfile ? appDir : `${appDir}/profiles/${normalizedProfile}`;\n const runDir = isDefaultProfile ? `${appDir}/run` : `${profileDir}/run`;\n const stateDir = isDefaultProfile ? `${appDir}/state` : `${profileDir}/state`;\n const dataDir = isDefaultProfile ? `${appDir}/data` : `${profileDir}/data`;\n const logDir = isDefaultProfile ? `${appDir}/logs` : `${profileDir}/logs`;\n const relayDataDir = `${appDir}/relay-data`;\n\n return {\n profileName: normalizedProfile,\n isDefaultProfile,\n appDir,\n profileDir,\n configPath: `${appDir}/config.json`,\n runDir,\n sockPath: `${runDir}/dev-anywhere.sock`,\n pidPath: `${runDir}/dev-anywhere.pid`,\n stoppedPath: `${runDir}/stopped`,\n desiredRelayPath: `${runDir}/desired-relay`,\n stateDir,\n sessionsPath: `${stateDir}/sessions.json`,\n hookRegistryPath: `${stateDir}/hooks.json`,\n dataDir,\n proxyIdPath: isDefaultProfile ? `${appDir}/proxy-id` : `${profileDir}/proxy-id`,\n logDir,\n serviceLogPath: `${logDir}/service.log`,\n relayDataDir,\n fontDir: `${relayDataDir}/fonts`,\n };\n}\n\nexport function defaultHookPortForProfile(profileName: string): number {\n const normalizedProfile = normalizeProxyProfileName(profileName);\n if (normalizedProfile === DEFAULT_PROXY_PROFILE) return 17654;\n\n let hash = 0;\n for (const char of normalizedProfile) {\n hash = (hash * 31 + char.charCodeAt(0)) % 1000;\n }\n return 17655 + hash;\n}\n\nexport const PROFILE_NAME = resolveProxyProfileName();\nconst PROFILE_PATHS = buildProxyProfilePaths(HOME, PROFILE_NAME);\n\n// 把 cwd 前缀替换为 ~,HOME 为空时原样返回(避免 replace(\"\", \"~\") 把 ~ 前缀到所有路径)\nexport function tildify(cwd: string): string {\n return HOME ? cwd.replace(HOME, \"~\") : cwd;\n}\nexport const CONFIG_PATH = PROFILE_PATHS.configPath;\n\n// 运行时文件\nexport const RUN_DIR = PROFILE_PATHS.runDir;\nexport const SOCK_PATH = PROFILE_PATHS.sockPath;\nexport const PID_PATH = PROFILE_PATHS.pidPath;\n// 停机标记文件。用户执行 `dev-anywhere stop` 时创建,其它时候不存在。文件内容无意义。\n// 作用:告诉 terminal 不要在此期间自动重启 daemon。\n//\n// 背景:terminal 在与 serve 的连接断开时,默认会 spawn 新 daemon 把连接修复。\n// 这与用户执行 stop 的诉求冲突——stop 刚结束 daemon,terminal 会立即把它重新拉起。\n// 解决办法是 stop 落下此标记,terminal 重连逻辑先检查标记:存在则仅 tryConnect,不 spawn。\nexport const STOPPED_PATH = PROFILE_PATHS.stoppedPath;\nexport const DESIRED_RELAY_PATH = PROFILE_PATHS.desiredRelayPath;\n\n// 持久化状态\nconst STATE_DIR = PROFILE_PATHS.stateDir;\nexport const SESSIONS_PATH = PROFILE_PATHS.sessionsPath;\nexport const HOOK_REGISTRY_PATH = PROFILE_PATHS.hookRegistryPath;\n\n// 会话数据\nexport const DATA_DIR = PROFILE_PATHS.dataDir;\nexport const PROXY_ID_PATH = PROFILE_PATHS.proxyIdPath;\nconst RELAY_DATA_DIR = PROFILE_PATHS.relayDataDir;\nconst FONT_DIR = PROFILE_PATHS.fontDir;\n\n// 日志\nexport const LOG_DIR = PROFILE_PATHS.logDir;\nexport const SERVICE_LOG_PATH = PROFILE_PATHS.serviceLogPath;\n\nfunction sessionDir(sessionId: string): string {\n return `${DATA_DIR}/${sessionId}`;\n}\n\nexport function sessionPaths(sessionId: string) {\n const dir = sessionDir(sessionId);\n return {\n dir,\n workerSock: `${dir}/worker.sock`,\n };\n}\n\nexport function isInitialized(): boolean {\n return existsSync(CONFIG_PATH);\n}\n\nconst DEFAULT_CONFIG = `{\n \"defaultProfile\": \"default\",\n \"profiles\": {\n \"default\": {\n \"relay\": \"cloud\"\n },\n \"local\": {\n \"relay\": \"local\"\n }\n },\n \"relays\": {\n \"cloud\": {\n \"url\": \"wss://dev-anywhere.example.com\",\n \"proxyToken\": \"\"\n },\n \"local\": {\n \"url\": \"ws://localhost:3100\"\n }\n }\n}\n`;\n\ntype FontAssetSource = {\n dir: string;\n family?: string;\n};\n\nfunction copyFontFamilyIfMissing(targetFontsDir: string, source: FontAssetSource): boolean {\n const family = source.family ?? DEFAULT_FONT_FAMILY;\n const sourceFamilyDir = `${source.dir}/${family}`;\n const targetFamilyDir = `${targetFontsDir}/${family}`;\n if (existsSync(targetFamilyDir) || !existsSync(sourceFamilyDir)) return false;\n mkdirSync(targetFontsDir, { recursive: true });\n cpSync(sourceFamilyDir, targetFamilyDir, { recursive: true });\n return true;\n}\n\nexport function installFontAssetsFromSources(\n targetFontsDir: string,\n sources: FontAssetSource[],\n): boolean {\n for (const source of sources) {\n if (copyFontFamilyIfMissing(targetFontsDir, source)) return true;\n }\n return false;\n}\n\nfunction installFontAssets(): void {\n installFontAssetsFromSources(FONT_DIR, [\n { dir: SOURCE_FONT_ASSETS_DIR, family: DEFAULT_FONT_FAMILY },\n { dir: DIST_FONT_ASSETS_DIR, family: DEFAULT_FONT_FAMILY },\n ]);\n}\n\nexport function initWorkspace(): void {\n ensureProfileWorkspace();\n mkdirSync(RELAY_DATA_DIR, { recursive: true });\n installFontAssets();\n if (!existsSync(CONFIG_PATH)) {\n writeFileSync(CONFIG_PATH, DEFAULT_CONFIG);\n }\n}\n\nexport function ensureProfileWorkspace(): void {\n mkdirSync(RUN_DIR, { recursive: true });\n mkdirSync(STATE_DIR, { recursive: true });\n mkdirSync(DATA_DIR, { recursive: true });\n mkdirSync(LOG_DIR, { recursive: true });\n}\n","import { z } from \"zod\";\nimport {\n UserInputPayloadSchema,\n AssistantMessagePayloadSchema,\n ThinkingPayloadSchema,\n} from \"./chat.js\";\nimport { ToolUseRequestPayloadSchema, ToolResultPayloadSchema } from \"./tool.js\";\nimport {\n SessionCreatePayloadSchema,\n SessionListPayloadSchema,\n SessionSwitchPayloadSchema,\n SessionTerminatePayloadSchema,\n SessionStatusPayloadSchema,\n} from \"./session.js\";\nimport {\n HeartbeatPayloadSchema,\n AuthPayloadSchema,\n SyncRequestPayloadSchema,\n SyncResponsePayloadSchema,\n} from \"./system.js\";\n\n// 信封基础字段:序列号、会话ID、时间戳、来源、协议版本\nconst BaseEnvelopeFields = {\n seq: z.number().int().nonnegative(),\n sessionId: z.string(),\n timestamp: z.number(),\n source: z.enum([\"proxy\", \"client\"]),\n version: z.string(),\n};\n\n// 按 type 字段区分的 discriminatedUnion 信封\nexport const MessageEnvelopeSchema = z.discriminatedUnion(\"type\", [\n // chat (3)\n z.object({\n ...BaseEnvelopeFields,\n type: z.literal(\"user_input\"),\n payload: UserInputPayloadSchema,\n }),\n z.object({\n ...BaseEnvelopeFields,\n type: z.literal(\"assistant_message\"),\n payload: AssistantMessagePayloadSchema,\n }),\n z.object({\n ...BaseEnvelopeFields,\n type: z.literal(\"thinking\"),\n payload: ThinkingPayloadSchema,\n }),\n // tool (4): 工具审批决策属于 relay control,不进入会话消息信封。\n // tool_use_request: 审批流请求(proxy → client),toolId 是 approval requestId\n z.object({\n ...BaseEnvelopeFields,\n type: z.literal(\"tool_use_request\"),\n payload: ToolUseRequestPayloadSchema,\n }),\n // tool_result: 工具执行结果(proxy → client),toolId 对应 assistant_tool_use / tool_use_request 的 toolId\n z.object({\n ...BaseEnvelopeFields,\n type: z.literal(\"tool_result\"),\n payload: ToolResultPayloadSchema,\n }),\n // assistant_tool_use: 纯展示型工具调用(proxy → client),区别于 tool_use_request 无审批语义\n // payload 结构复用 ToolUseRequestPayloadSchema;toolId 是 Claude 分配的 tool_use id\n z.object({\n ...BaseEnvelopeFields,\n type: z.literal(\"assistant_tool_use\"),\n payload: ToolUseRequestPayloadSchema,\n }),\n // session (5)\n z.object({\n ...BaseEnvelopeFields,\n type: z.literal(\"session_create\"),\n payload: SessionCreatePayloadSchema,\n }),\n z.object({\n ...BaseEnvelopeFields,\n type: z.literal(\"session_list\"),\n payload: SessionListPayloadSchema,\n }),\n z.object({\n ...BaseEnvelopeFields,\n type: z.literal(\"session_switch\"),\n payload: SessionSwitchPayloadSchema,\n }),\n z.object({\n ...BaseEnvelopeFields,\n type: z.literal(\"session_terminate\"),\n payload: SessionTerminatePayloadSchema,\n }),\n z.object({\n ...BaseEnvelopeFields,\n type: z.literal(\"session_status\"),\n payload: SessionStatusPayloadSchema,\n }),\n // system (5)\n z.object({\n ...BaseEnvelopeFields,\n type: z.literal(\"heartbeat\"),\n payload: HeartbeatPayloadSchema,\n }),\n z.object({\n ...BaseEnvelopeFields,\n type: z.literal(\"auth\"),\n payload: AuthPayloadSchema,\n }),\n z.object({\n ...BaseEnvelopeFields,\n type: z.literal(\"sync_request\"),\n payload: SyncRequestPayloadSchema,\n }),\n z.object({\n ...BaseEnvelopeFields,\n type: z.literal(\"sync_response\"),\n payload: SyncResponsePayloadSchema,\n }),\n]);\n\nexport type MessageEnvelope = z.infer<typeof MessageEnvelopeSchema>;\n\nexport type MessageType = MessageEnvelope[\"type\"];\n\nexport type MessageSource = MessageEnvelope[\"source\"];\n","import { z } from \"zod\";\n\n// 用户输入消息\nexport const UserInputPayloadSchema = z.object({\n text: z.string().min(1),\n messageId: z.string().min(1).optional(),\n});\n\nexport type UserInputPayload = z.infer<typeof UserInputPayloadSchema>;\n\n// 助手回复消息,isPartial 标识是否为流式中间结果\nexport const AssistantMessagePayloadSchema = z.object({\n text: z.string(),\n isPartial: z.boolean(),\n});\n\nexport type AssistantMessagePayload = z.infer<typeof AssistantMessagePayloadSchema>;\n\n// 思考过程消息\nexport const ThinkingPayloadSchema = z.object({\n text: z.string(),\n});\n\nexport type ThinkingPayload = z.infer<typeof ThinkingPayloadSchema>;\n","import { z } from \"zod\";\n\n// 工具调用请求\nexport const ToolUseRequestPayloadSchema = z.object({\n toolName: z.string(),\n toolId: z.string(),\n parameters: z.record(z.string(), z.unknown()),\n});\n\nexport type ToolUseRequestPayload = z.infer<typeof ToolUseRequestPayloadSchema>;\n\n// 工具调用批准,whitelistTool 为 true 时将该工具加入会话级白名单自动审批\nexport const ToolApprovePayloadSchema = z.object({\n toolId: z.string(),\n whitelistTool: z.boolean().optional(),\n});\n\nexport type ToolApprovePayload = z.infer<typeof ToolApprovePayloadSchema>;\n\n// 工具调用拒绝\nexport const ToolDenyPayloadSchema = z.object({\n toolId: z.string(),\n reason: z.string().optional(),\n});\n\nexport type ToolDenyPayload = z.infer<typeof ToolDenyPayloadSchema>;\n\n// 工具调用结果\nexport const ToolResultPayloadSchema = z.object({\n toolId: z.string(),\n result: z.unknown(),\n isError: z.boolean(),\n});\n\nexport type ToolResultPayload = z.infer<typeof ToolResultPayloadSchema>;\n","import { z } from \"zod\";\n\nconst sessionStateValues = [\"idle\", \"working\", \"waiting_approval\", \"error\", \"terminated\"] as const;\nconst providerValues = [\"claude\", \"codex\"] as const;\nconst ptyOwnerValues = [\"local-terminal\", \"proxy-hosted\"] as const;\nconst agentStatusPhaseValues = [\n \"idle\",\n \"thinking\",\n \"tool_use\",\n \"outputting\",\n \"waiting_permission\",\n \"error\",\n] as const;\n\n// 会话信息,用于会话列表展示\n// lastActive: 最近一次状态变更或运行时活动时间戳 (ms), 用于列表\"最近活动 N 分钟前\"显示, 可选\nexport const SessionInfoSchema = z.object({\n sessionId: z.string(),\n name: z.string().optional(),\n state: z.enum(sessionStateValues),\n mode: z.enum([\"pty\", \"json\"]).optional(),\n provider: z.enum(providerValues),\n // PTY 尺寸所有权:\n // - local-terminal: 本地 terminal 进程持有真实 PTY,Web 只按原始 cols/rows 展示\n // - proxy-hosted: serve 内托管 PTY,Web 可按视口请求 resize\n ptyOwner: z.enum(ptyOwnerValues).optional(),\n lastActive: z.number().optional(),\n});\nexport type SessionInfo = z.infer<typeof SessionInfoSchema>;\n\n// 创建会话\n// streamDelta: client 端系统设置\"逐字流式\"toggle,true 时 proxy spawn 带 --include-partial-messages\nexport const SessionCreatePayloadSchema = z.object({\n name: z.string().optional(),\n cwd: z.string().optional(),\n streamDelta: z.boolean().optional(),\n});\n\nexport type SessionCreatePayload = z.infer<typeof SessionCreatePayloadSchema>;\n\n// 会话列表\nexport const SessionListPayloadSchema = z.object({\n sessions: z.array(SessionInfoSchema),\n});\n\nexport type SessionListPayload = z.infer<typeof SessionListPayloadSchema>;\n\n// 切换会话\nexport const SessionSwitchPayloadSchema = z.object({\n sessionId: z.string(),\n});\n\nexport type SessionSwitchPayload = z.infer<typeof SessionSwitchPayloadSchema>;\n\n// 终止会话\nexport const SessionTerminatePayloadSchema = z.object({\n sessionId: z.string(),\n});\n\nexport type SessionTerminatePayload = z.infer<typeof SessionTerminatePayloadSchema>;\n\n// 会话状态变更\n// lastActive: 触发本次状态迁移或活动刷新的时间戳 (ms),用于列表相对时间显示。\nexport const SessionStatusPayloadSchema = z.object({\n sessionId: z.string(),\n state: z.enum(sessionStateValues),\n lastActive: z.number(),\n});\n\nexport type SessionStatusPayload = z.infer<typeof SessionStatusPayloadSchema>;\n\n// PTY 语义状态事件,描述当前 PTY 处于何种状态\nexport const PtyStatePayloadSchema = z.object({\n state: z.enum([\"working\", \"turn_complete\", \"approval_wait\", \"mid_pause\"]),\n title: z.string().optional(),\n tool: z.string().optional(),\n});\nexport type PtyStatePayload = z.infer<typeof PtyStatePayloadSchema>;\n\nexport const AgentStatusPayloadSchema = z.object({\n provider: z.enum(providerValues),\n phase: z.enum(agentStatusPhaseValues),\n seq: z.number().int().nonnegative(),\n updatedAt: z.number(),\n toolName: z.string().optional(),\n toolInput: z.record(z.string(), z.unknown()).optional(),\n permissionRequest: z\n .object({\n requestId: z.string(),\n toolName: z.string(),\n input: z.record(z.string(), z.unknown()),\n })\n .optional(),\n permissionResolution: z\n .object({\n requestId: z.string(),\n outcome: z.enum([\"allow\", \"deny\"]),\n })\n .optional(),\n summary: z.string().optional(),\n});\nexport type AgentStatusPayload = z.infer<typeof AgentStatusPayloadSchema>;\n","import { z } from \"zod\";\n\n// 心跳消息,空 payload\nexport const HeartbeatPayloadSchema = z.object({});\n\nexport type HeartbeatPayload = z.infer<typeof HeartbeatPayloadSchema>;\n\n// 认证消息,支持配对码和 token 两种方式\nexport const AuthPayloadSchema = z.object({\n pairingCode: z.string().optional(),\n token: z.string().optional(),\n});\n\nexport type AuthPayload = z.infer<typeof AuthPayloadSchema>;\n\n// 同步请求,客户端发送已收到的最大序列号\nexport const SyncRequestPayloadSchema = z.object({\n lastSeq: z.number().int().nonnegative(),\n});\n\nexport type SyncRequestPayload = z.infer<typeof SyncRequestPayloadSchema>;\n\n// 同步响应,使用 z.unknown 数组避免循环引用;恢复协议稳定后再收紧类型\nexport const SyncResponsePayloadSchema = z.object({\n messages: z.array(z.record(z.string(), z.unknown())),\n});\n\nexport type SyncResponsePayload = z.infer<typeof SyncResponsePayloadSchema>;\n","import type { MessageEnvelope } from \"../schemas/envelope.js\";\nimport { MessageEnvelopeSchema } from \"../schemas/envelope.js\";\n\n// 构建经过 schema 验证的消息信封\n// seq 由调用方提供,必须与 EventStore per-session seq 一致,保证 proxy 和 relay 对账可靠\nexport function buildMessage<T extends MessageEnvelope[\"type\"]>(\n type: T,\n sessionId: string,\n seq: number,\n payload: Extract<MessageEnvelope, { type: T }>[\"payload\"],\n source: \"proxy\" | \"client\",\n): Extract<MessageEnvelope, { type: T }> {\n const envelope = {\n seq,\n sessionId,\n type,\n payload,\n timestamp: Date.now(),\n source,\n version: \"1.0\",\n };\n return MessageEnvelopeSchema.parse(envelope) as Extract<MessageEnvelope, { type: T }>;\n}\n","import { z } from \"zod\";\nimport { AgentStatusPayloadSchema, PtyStatePayloadSchema } from \"./session.js\";\nimport { ToolApprovePayloadSchema, ToolDenyPayloadSchema } from \"./tool.js\";\nimport { RelayErrorCode } from \"../constants/relay-errors.js\";\nimport { ControlErrorCode } from \"../constants/control-errors.js\";\n\n// 控制消息中复用的子类型\nexport const ProxyInfoSchema = z.object({\n proxyId: z.string(),\n name: z.string().optional(),\n online: z.boolean(),\n sessions: z.array(z.string()).optional(),\n});\nexport type ProxyInfo = z.infer<typeof ProxyInfoSchema>;\n\nexport const AgentCliAvailabilitySchema = z.object({\n available: z.boolean(),\n command: z.string().optional(),\n error: z.string().optional(),\n suggestions: z.array(z.string()).optional(),\n});\nexport type AgentCliAvailability = z.infer<typeof AgentCliAvailabilitySchema>;\n\nexport const AgentCliStatusSchema = z.object({\n claude: AgentCliAvailabilitySchema,\n codex: AgentCliAvailabilitySchema,\n});\nexport type AgentCliStatus = z.infer<typeof AgentCliStatusSchema>;\n\nexport const DirEntrySchema = z.object({ name: z.string(), isDir: z.boolean() });\nexport type DirEntry = z.infer<typeof DirEntrySchema>;\n\nexport const FileTreeGroupSchema = z.object({\n path: z.string(),\n entries: z.array(DirEntrySchema),\n});\nexport type FileTreeGroup = z.infer<typeof FileTreeGroupSchema>;\n\nexport const CommandEntrySchema = z.object({\n name: z.string(),\n description: z.string(),\n argumentHint: z.string().optional(),\n source: z.string(),\n});\nexport type CommandEntry = z.infer<typeof CommandEntrySchema>;\n\nexport const HistorySessionSchema = z.object({\n id: z.string(),\n title: z.string(),\n projectDir: z.string(),\n updatedAt: z.number(),\n provider: z.enum([\"claude\", \"codex\"]).optional(),\n});\nexport type HistorySession = z.infer<typeof HistorySessionSchema>;\n\nconst SessionHistoryMessageSchema = z.object({\n role: z.enum([\"user\", \"assistant\"]),\n text: z.string(),\n timestamp: z.number().optional(),\n cursor: z.string().optional(),\n});\n\ntype RelayControlDirection = \"proxy_to_client\" | \"client_to_proxy\";\ntype EmptyShape = Record<never, never>;\nconst RequestIdShape = { requestId: z.string().min(1).optional() };\nconst ControlErrorCodeSchema = z.enum(\n Object.values(ControlErrorCode) as [ControlErrorCode, ...ControlErrorCode[]],\n);\nconst RequestErrorShape = {\n error: z.string().optional(),\n errorCode: ControlErrorCodeSchema.optional(),\n};\nconst ClipboardImageMimeTypeSchema = z.enum([\"image/png\", \"image/jpeg\", \"image/webp\", \"image/gif\"]);\n\ntype ControlDefinition<T extends string, S extends z.ZodRawShape> = {\n type: T;\n directions: ReadonlySet<RelayControlDirection>;\n schema: z.ZodObject<{ type: z.ZodLiteral<T> } & S>;\n};\n\nfunction control<T extends string>(type: T): ControlDefinition<T, EmptyShape>;\nfunction control<T extends string>(\n type: T,\n shape: undefined,\n directions: RelayControlDirection | RelayControlDirection[],\n): ControlDefinition<T, EmptyShape>;\nfunction control<T extends string, S extends z.ZodRawShape>(\n type: T,\n shape: S,\n directions?: RelayControlDirection | RelayControlDirection[],\n): ControlDefinition<T, S>;\nfunction control<T extends string, S extends z.ZodRawShape>(\n type: T,\n shape?: S,\n directions?: RelayControlDirection | RelayControlDirection[],\n): ControlDefinition<T, S | EmptyShape> {\n return {\n type,\n directions: new Set(Array.isArray(directions) ? directions : directions ? [directions] : []),\n schema: z.object({\n type: z.literal(type),\n ...(shape ?? {}),\n }) as z.ZodObject<{ type: z.ZodLiteral<T> } & (S | EmptyShape)>,\n };\n}\n\n// 中转服务器控制消息,独立于 MessageEnvelope 的传输层协议\nconst relayControlDefinitions = [\n control(\"proxy_register\", {\n proxyId: z.string().min(1),\n name: z.string().optional(),\n }),\n control(\"proxy_register_response\", {\n status: z.enum([\"new\", \"reconnected\"]),\n }),\n control(\"proxy_list_request\", RequestIdShape),\n control(\"proxy_list_response\", {\n ...RequestIdShape,\n proxies: z.array(ProxyInfoSchema),\n }),\n control(\"proxy_select\", { ...RequestIdShape, proxyId: z.string().min(1) }),\n control(\"proxy_select_response\", {\n ...RequestIdShape,\n success: z.boolean(),\n proxyId: z.string().optional(),\n ...RequestErrorShape,\n }),\n control(\"relay_error\", {\n code: z.enum(Object.values(RelayErrorCode) as [RelayErrorCode, ...RelayErrorCode[]]),\n message: z.string(),\n }),\n\n // 客户端注册协议\n control(\"client_register\", {\n clientId: z.string().min(1),\n }),\n control(\"client_register_response\", {\n status: z.enum([\"restored\", \"proxy_offline\", \"new\"]),\n proxyId: z.string().optional(),\n }),\n\n // Proxy 离线通知\n control(\"proxy_offline\", {\n proxyId: z.string(),\n }),\n\n // Proxy 主动断开,relay 立即清理资源\n control(\"proxy_disconnect\", {\n proxyId: z.string().min(1),\n }),\n\n // Proxy 重连后通知 client 恢复\n control(\"proxy_online\", {\n proxyId: z.string().min(1),\n }),\n\n // 目录列表请求与响应\n control(\n \"dir_list_request\",\n {\n proxyId: z.string().min(1).optional(),\n ...RequestIdShape,\n path: z.string(),\n },\n \"client_to_proxy\",\n ),\n control(\n \"dir_list_response\",\n { ...RequestIdShape, ...RequestErrorShape, entries: z.array(DirEntrySchema), path: z.string() },\n \"proxy_to_client\",\n ),\n\n // 目录创建请求与响应\n control(\"dir_create_request\", { ...RequestIdShape, path: z.string() }, \"client_to_proxy\"),\n control(\n \"dir_create_response\",\n {\n ...RequestIdShape,\n ...RequestErrorShape,\n path: z.string(),\n success: z.boolean(),\n },\n \"proxy_to_client\",\n ),\n\n // 命令列表推送,proxy 将可用命令列表推给 client\n control(\"command_list_push\", { commands: z.array(CommandEntrySchema) }, \"proxy_to_client\"),\n\n // 文件树推送: 按目录分组, 首组 path 即为 session cwd\n // 前端直接把每组写入 tree[path], 与 dir_list_response 共享 cache slot\n control(\n \"file_tree_push\",\n {\n groups: z.array(FileTreeGroupSchema),\n },\n \"proxy_to_client\",\n ),\n\n // 会话列表请求与权限模式变更\n control(\"session_list\", undefined, [\"client_to_proxy\", \"proxy_to_client\"]),\n control(\n \"permission_mode_change\",\n {\n mode: z.enum([\"default\", \"auto_accept\", \"plan\"]),\n // sessionId 可选:传入时 proxy 按该会话的 mode 分叉(PTY 发 Tab ANSI),未传走全局日志行为\n sessionId: z.string().optional(),\n },\n \"client_to_proxy\",\n ),\n\n // 会话历史浏览\n control(\"session_history_request\", RequestIdShape, \"client_to_proxy\"),\n control(\n \"session_history_response\",\n { ...RequestIdShape, sessions: z.array(HistorySessionSchema) },\n \"proxy_to_client\",\n ),\n\n // PTY 语义状态,从 Envelope 迁移到 Control 层\n control(\n \"pty_state\",\n { sessionId: z.string(), payload: PtyStatePayloadSchema },\n \"proxy_to_client\",\n ),\n\n // Provider 语义状态,来自 Claude/Codex hook 等结构化事件,不从 PTY 字节推断\n control(\n \"agent_status\",\n { sessionId: z.string(), payload: AgentStatusPayloadSchema },\n \"proxy_to_client\",\n ),\n\n // 终端标题变化,proxy -> client\n control(\"terminal_title\", { sessionId: z.string(), title: z.string() }, \"proxy_to_client\"),\n\n // 终端尺寸变化,proxy -> client\n control(\n \"terminal_resize\",\n { sessionId: z.string(), cols: z.number().int().positive(), rows: z.number().int().positive() },\n \"proxy_to_client\",\n ),\n control(\n \"terminal_resize_request\",\n { sessionId: z.string(), cols: z.number().int().positive(), rows: z.number().int().positive() },\n \"client_to_proxy\",\n ),\n\n // 远程终止 JSON 会话,client -> proxy\n control(\"session_terminate\", { sessionId: z.string() }, \"client_to_proxy\"),\n\n // 中断当前 turn,client -> proxy,SIGINT 到 worker 进程让 claude CLI abort 当前流\n control(\"session_worker_abort\", { sessionId: z.string() }, \"client_to_proxy\"),\n\n // turn 完成信号,proxy -> client,对应 claude stream-json 的 result 事件\n control(\n \"turn_result\",\n {\n sessionId: z.string(),\n success: z.boolean(),\n isError: z.boolean(),\n // stream-json result.result 是本轮最终文本。assistant_message 流丢失或 CLI 未发增量时,\n // Web 用它作为 JSON 模式兜底展示,避免 turn 已结束但界面空白。\n result: z.string().optional(),\n },\n \"proxy_to_client\",\n ),\n\n // 客户端发送到 PTY 的原始字节(ANSI 序列),不追加换行\n control(\n \"remote_input_raw\",\n { sessionId: z.string().min(1), data: z.string() },\n \"client_to_proxy\",\n ),\n control(\n \"clipboard_image_upload\",\n {\n ...RequestIdShape,\n sessionId: z.string().min(1),\n mimeType: ClipboardImageMimeTypeSchema,\n dataBase64: z.string().min(1),\n fileName: z.string().optional(),\n },\n \"client_to_proxy\",\n ),\n control(\n \"clipboard_image_upload_response\",\n {\n ...RequestIdShape,\n ...RequestErrorShape,\n sessionId: z.string().min(1),\n success: z.boolean(),\n path: z.string(),\n },\n \"proxy_to_client\",\n ),\n control(\n \"image_preview_request\",\n {\n ...RequestIdShape,\n sessionId: z.string().min(1),\n path: z.string().min(1),\n },\n \"client_to_proxy\",\n ),\n control(\n \"image_preview_response\",\n {\n ...RequestIdShape,\n ...RequestErrorShape,\n sessionId: z.string().min(1),\n success: z.boolean(),\n path: z.string(),\n mimeType: ClipboardImageMimeTypeSchema.optional(),\n dataBase64: z.string().optional(),\n size: z.number().int().nonnegative().optional(),\n },\n \"proxy_to_client\",\n ),\n\n // 客户端询问 proxy 的环境信息 (home 路径等), client -> proxy -> response\n // FilePathPicker 用 homePath 作为 select 模式下的默认起点, 新建会话时打开即可浏览\n control(\"proxy_info_request\", RequestIdShape, \"client_to_proxy\"),\n control(\n \"proxy_info\",\n { ...RequestIdShape, homePath: z.string(), agentCli: AgentCliStatusSchema },\n \"proxy_to_client\",\n ),\n control(\n \"agent_cli_config_update\",\n { ...RequestIdShape, provider: z.enum([\"claude\", \"codex\"]), path: z.string().min(1) },\n \"client_to_proxy\",\n ),\n control(\n \"agent_cli_config_update_response\",\n {\n ...RequestIdShape,\n provider: z.enum([\"claude\", \"codex\"]),\n agentCli: AgentCliStatusSchema.optional(),\n ...RequestErrorShape,\n },\n \"proxy_to_client\",\n ),\n\n // 远程创建 JSON 会话,client -> proxy -> response\n control(\n \"session_create\",\n {\n ...RequestIdShape,\n cwd: z.string(),\n provider: z.enum([\"claude\", \"codex\"]),\n mode: z.enum([\"json\", \"pty\"]).optional(),\n resumeSessionId: z.string().optional(),\n // 透传给 claude CLI 的 --permission-mode, undefined 时 proxy 兜底为 \"default\"\n permissionMode: z\n .enum([\"default\", \"auto\", \"acceptEdits\", \"plan\", \"bypassPermissions\", \"dontAsk\"])\n .optional(),\n },\n \"client_to_proxy\",\n ),\n control(\n \"session_create_response\",\n {\n ...RequestIdShape,\n sessionId: z.string(),\n mode: z.enum([\"json\", \"pty\"]).optional(),\n provider: z.enum([\"claude\", \"codex\"]).optional(),\n ptyOwner: z.enum([\"local-terminal\", \"proxy-hosted\"]).optional(),\n ...RequestErrorShape,\n },\n \"proxy_to_client\",\n ),\n\n // 客户端请求会话历史消息,client -> proxy\n control(\n \"session_messages_request\",\n {\n ...RequestIdShape,\n sessionId: z.string(),\n limit: z.number().int().min(1).max(200).optional(),\n before: z.string().optional(),\n },\n \"client_to_proxy\",\n ),\n\n // 客户端请求会话资源(命令列表 + 文件树),client -> proxy\n control(\n \"session_resources_request\",\n { ...RequestIdShape, sessionId: z.string() },\n \"client_to_proxy\",\n ),\n control(\n \"session_resources_response\",\n {\n ...RequestIdShape,\n ...RequestErrorShape,\n sessionId: z.string(),\n commands: z.array(CommandEntrySchema),\n groups: z.array(FileTreeGroupSchema),\n },\n \"proxy_to_client\",\n ),\n\n // 客户端请求当前 provider 语义状态;不经 relay 缓存,由 proxy 返回当前值\n control(\n \"agent_status_request\",\n { ...RequestIdShape, sessionId: z.string().optional() },\n \"client_to_proxy\",\n ),\n control(\n \"agent_status_response\",\n {\n ...RequestIdShape,\n statuses: z.array(z.object({ sessionId: z.string(), payload: AgentStatusPayloadSchema })),\n },\n \"proxy_to_client\",\n ),\n\n // 客户端确认已收到审批请求;proxy 只记录送达状态,不把它当成用户决策\n control(\n \"permission_request_delivered\",\n { sessionId: z.string(), requestId: z.string() },\n \"client_to_proxy\",\n ),\n control(\n \"tool_approve\",\n { sessionId: z.string(), payload: ToolApprovePayloadSchema },\n \"client_to_proxy\",\n ),\n control(\n \"tool_deny\",\n { sessionId: z.string(), payload: ToolDenyPayloadSchema },\n \"client_to_proxy\",\n ),\n\n // proxy 确认用户决策已进入 provider/worker 路径;web 用它更新审批卡片状态\n control(\n \"permission_decision_result\",\n {\n sessionId: z.string(),\n requestId: z.string(),\n outcome: z.enum([\"allow\", \"deny\"]),\n delivered: z.boolean(),\n message: z.string().optional(),\n },\n \"proxy_to_client\",\n ),\n\n // proxy 推送当前 pending 的工具审批列表,client 据此恢复审批卡片\n control(\n \"pending_approvals_push\",\n {\n sessionId: z.string(),\n approvals: z.array(\n z.object({\n requestId: z.string(),\n toolName: z.string(),\n input: z.record(z.string(), z.unknown()),\n }),\n ),\n },\n \"proxy_to_client\",\n ),\n\n // 恢复会话时推送历史消息,proxy -> client\n control(\n \"session_history_messages\",\n {\n ...RequestIdShape,\n sessionId: z.string(),\n before: z.string().optional(),\n messages: z.array(SessionHistoryMessageSchema),\n hasMore: z.boolean().optional(),\n nextBefore: z.string().optional(),\n },\n \"proxy_to_client\",\n ),\n\n // proxy 重连后同步活跃 session 列表给 relay\n control(\"session_sync\", {\n sessions: z.array(\n z.object({\n id: z.string(),\n mode: z.enum([\"pty\", \"json\"]),\n provider: z.enum([\"claude\", \"codex\"]),\n ptyOwner: z.enum([\"local-terminal\", \"proxy-hosted\"]).optional(),\n state: z.string(),\n }),\n ),\n }),\n\n // PTY 会话订阅,client -> proxy,触发 terminal serialize() 返回当前状态\n control(\n \"session_subscribe\",\n { sessionId: z.string(), requestId: z.string().optional() },\n \"client_to_proxy\",\n ),\n\n // PTY 会话快照,proxy -> client,serialize() 的全量终端状态\n control(\n \"session_snapshot\",\n {\n sessionId: z.string(),\n cols: z.number().int().positive(),\n rows: z.number().int().positive(),\n data: z.string(),\n outputSeq: z.number().int().nonnegative(),\n requestId: z.string().optional(),\n },\n \"proxy_to_client\",\n ),\n] as const;\n\nconst relayControlSchemas = relayControlDefinitions.map((definition) => definition.schema) as [\n (typeof relayControlDefinitions)[number][\"schema\"],\n ...Array<(typeof relayControlDefinitions)[number][\"schema\"]>,\n];\n\nexport const RelayControlSchema = z.discriminatedUnion(\"type\", relayControlSchemas);\n\nexport type RelayControlMessage = z.infer<typeof RelayControlSchema>;\nexport type RelayControlType = RelayControlMessage[\"type\"];\n\nexport const ProxyToClientRelayControlTypes = new Set(\n relayControlDefinitions\n .filter((definition) => definition.directions.has(\"proxy_to_client\"))\n .map((definition) => definition.type),\n);\n\nexport function isProxyToClientRelayControlType(type: RelayControlType): boolean {\n return ProxyToClientRelayControlTypes.has(type);\n}\n\nexport const ClientToProxyRelayControlTypes = new Set(\n relayControlDefinitions\n .filter((definition) => definition.directions.has(\"client_to_proxy\"))\n .map((definition) => definition.type),\n);\n\nexport function isClientToProxyRelayControlType(type: RelayControlType): boolean {\n return ClientToProxyRelayControlTypes.has(type);\n}\n","// relay 实际发出的 6 个错误码。schema 侧 RelayControlSchema.relay_error.code 用 z.enum 收紧,\n// handler 侧用这个常量引用避免裸字面量拼错。\nexport const RelayErrorCode = {\n NOT_REGISTERED: \"NOT_REGISTERED\",\n NOT_BOUND: \"NOT_BOUND\",\n PROXY_OFFLINE: \"PROXY_OFFLINE\",\n INVALID_MESSAGE: \"INVALID_MESSAGE\",\n UNSUPPORTED: \"UNSUPPORTED\",\n INVALID_RANGE: \"INVALID_RANGE\",\n} as const;\n\nexport type RelayErrorCode = (typeof RelayErrorCode)[keyof typeof RelayErrorCode];\n","export const ControlErrorCode = {\n INVALID_PATH: \"INVALID_PATH\",\n PATH_NOT_FOUND: \"PATH_NOT_FOUND\",\n PATH_NOT_DIRECTORY: \"PATH_NOT_DIRECTORY\",\n PATH_ACCESS_DENIED: \"PATH_ACCESS_DENIED\",\n PROXY_OFFLINE: \"PROXY_OFFLINE\",\n SESSION_NOT_FOUND: \"SESSION_NOT_FOUND\",\n PROVIDER_UNSUPPORTED: \"PROVIDER_UNSUPPORTED\",\n WORKER_START_FAILED: \"WORKER_START_FAILED\",\n PROCESS_START_FAILED: \"PROCESS_START_FAILED\",\n UNKNOWN: \"UNKNOWN\",\n} as const;\n\nexport type ControlErrorCode = (typeof ControlErrorCode)[keyof typeof ControlErrorCode];\n","// 会话状态枚举\nexport const SessionState = {\n IDLE: \"idle\",\n WORKING: \"working\",\n WAITING_APPROVAL: \"waiting_approval\",\n ERROR: \"error\",\n TERMINATED: \"terminated\",\n} as const;\n\nexport type SessionState = (typeof SessionState)[keyof typeof SessionState];\n","import {\n lstatSync,\n mkdirSync,\n readdirSync,\n renameSync,\n statSync,\n symlinkSync,\n unlinkSync,\n} from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { basename, join } from \"node:path\";\nimport pino from \"pino\";\n\nexport type { Logger } from \"pino\";\n\nexport interface CreateLoggerOptions {\n name: string;\n level?: string;\n logDir?: string;\n retention?: number;\n stdout?: boolean;\n silent?: boolean;\n // 同步落盘:sonic-boom 默认异步 open + 异步 write,测试里需要在断言前看到文件,\n // 或在 afterEach 删目录前确保后台 worker 已经退出,必须开同步。生产保留异步以避免热路径阻塞。\n sync?: boolean;\n}\n\nconst DEFAULT_LOG_DIR = `${homedir()}/.dev-anywhere/logs`;\nconst DEFAULT_LOG_RETENTION = 50;\n\nconst PROCESS_LOG_RUN_ID = sanitizeRunId(\n `${new Date().toISOString().replace(/[:.]/g, \"-\")}-${process.pid}`,\n);\n\nfunction sanitizeRunId(runId: string): string {\n return runId.replace(/[^a-zA-Z0-9._-]/g, \"_\");\n}\n\nfunction linkLatestLog(logDir: string, name: string, filePath: string, runId: string): void {\n const latestPath = join(logDir, `${name}.log`);\n\n try {\n const stat = lstatSync(latestPath);\n if (stat.isSymbolicLink()) {\n unlinkSync(latestPath);\n } else {\n renameSync(latestPath, join(logDir, `${name}-legacy-${runId}.log`));\n }\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code !== \"ENOENT\") return;\n }\n\n try {\n symlinkSync(basename(filePath), latestPath);\n } catch {\n // 日志本体仍然写入 run-specific 文件;latest 链接失败不应阻塞服务启动。\n }\n}\n\nfunction resolveRetention(retention: number | undefined): number {\n if (retention === undefined) return DEFAULT_LOG_RETENTION;\n return Number.isFinite(retention) && retention >= 0\n ? Math.floor(retention)\n : DEFAULT_LOG_RETENTION;\n}\n\nfunction pruneOldLogs(\n logDir: string,\n name: string,\n currentFilePath: string,\n retention: number | undefined,\n): void {\n const keep = resolveRetention(retention);\n if (keep === 0) return;\n\n const currentFileName = basename(currentFilePath);\n const prefix = `${name}-`;\n const candidates = readdirSync(logDir)\n .filter(\n (entry) => entry.startsWith(prefix) && entry.endsWith(\".log\") && entry !== currentFileName,\n )\n .map((entry) => {\n const path = join(logDir, entry);\n try {\n return { path, mtimeMs: statSync(path).mtimeMs };\n } catch {\n return null;\n }\n })\n .filter((entry): entry is { path: string; mtimeMs: number } => entry !== null)\n .sort((a, b) => b.mtimeMs - a.mtimeMs);\n\n for (const stale of candidates.slice(Math.max(0, keep - 1))) {\n try {\n unlinkSync(stale.path);\n } catch {\n // 日志清理失败不能影响主进程启动。\n }\n }\n}\n\nfunction buildPinoLogger(options: CreateLoggerOptions): pino.Logger {\n const {\n name,\n level = \"info\",\n logDir = DEFAULT_LOG_DIR,\n retention,\n stdout = false,\n silent = false,\n sync = false,\n } = options;\n\n if (silent) {\n return pino({ level: \"silent\" });\n }\n\n mkdirSync(logDir, { recursive: true });\n\n const runId = PROCESS_LOG_RUN_ID;\n const filePath = join(logDir, `${name}-${runId}.log`);\n linkLatestLog(logDir, name, filePath, runId);\n pruneOldLogs(logDir, name, filePath, retention);\n const streams: pino.StreamEntry[] = [\n { stream: pino.destination({ dest: filePath, sync }) },\n ];\n\n if (stdout) {\n streams.unshift({ stream: process.stdout });\n }\n\n return pino({ level }, pino.multistream(streams));\n}\n\n// 返回一个 lazy proxy:调用 createLogger 本身不触发 mkdirSync / pino.destination\n// 等任何文件 IO,只有第一次实际访问 logger 的方法/属性时才构造底层 pino Logger。\n// 这样 `dev-anywhere -v` / `dev-anywhere init` 等不需要写日志的命令路径不会\n// 落地空 log 文件,也避免异步 SonicBoom 在 process.exit 时未 ready 的 race。\nexport function createLogger(options: CreateLoggerOptions): pino.Logger {\n let real: pino.Logger | null = null;\n const ensure = (): pino.Logger => {\n if (!real) real = buildPinoLogger(options);\n return real;\n };\n\n return new Proxy(Object.create(null) as pino.Logger, {\n get(_target, prop) {\n const target = ensure();\n const value = Reflect.get(target, prop, target);\n return typeof value === \"function\" ? value.bind(target) : value;\n },\n set(_target, prop, value) {\n return Reflect.set(ensure(), prop, value);\n },\n has(_target, prop) {\n return Reflect.has(ensure(), prop);\n },\n ownKeys() {\n return Reflect.ownKeys(ensure());\n },\n getOwnPropertyDescriptor(_target, prop) {\n return Reflect.getOwnPropertyDescriptor(ensure(), prop);\n },\n });\n}\n"],"mappings":"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","names":["z","z","z","z","z","z","z","mkdirSync","homedir"]}
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  SessionState
4
- } from "./chunk-2XO3KLWW.js";
4
+ } from "./chunk-QFYI6AMN.js";
5
5
 
6
6
  // src/ipc/ipc-protocol.ts
7
7
  import { z } from "zod";
@@ -343,4 +343,4 @@ export {
343
343
  serializeIpc,
344
344
  createIpcReader
345
345
  };
346
- //# sourceMappingURL=chunk-BLWDLNT6.js.map
346
+ //# sourceMappingURL=chunk-U5T7ZYXT.js.map
package/dist/index.js CHANGED
@@ -2,14 +2,14 @@
2
2
  import {
3
3
  daemonRelayArgs,
4
4
  setDesiredDaemonRelay
5
- } from "./chunk-2SBGSJLQ.js";
5
+ } from "./chunk-BMVYMCKF.js";
6
6
  import {
7
7
  spawnScript
8
8
  } from "./chunk-ZUWAB67J.js";
9
9
  import {
10
10
  createIpcReader,
11
11
  serializeIpc
12
- } from "./chunk-BLWDLNT6.js";
12
+ } from "./chunk-U5T7ZYXT.js";
13
13
  import {
14
14
  CONFIG_PATH,
15
15
  PID_PATH,
@@ -20,7 +20,7 @@ import {
20
20
  ensureProfileWorkspace,
21
21
  initWorkspace,
22
22
  isInitialized
23
- } from "./chunk-2XO3KLWW.js";
23
+ } from "./chunk-QFYI6AMN.js";
24
24
 
25
25
  // src/index.ts
26
26
  import { existsSync, readFileSync, unlinkSync, writeFileSync } from "fs";
@@ -246,7 +246,7 @@ var program = new Command("dev-anywhere").description("Dev Anywhere - transparen
246
246
  console.error(err instanceof Error ? err.message : String(err));
247
247
  process.exit(1);
248
248
  }
249
- const { startTerminal } = await import("./terminal-4MDRBCL4.js");
249
+ const { startTerminal } = await import("./terminal-FJAIRC73.js");
250
250
  const { provider, args } = invocation;
251
251
  await startTerminal(args, provider);
252
252
  });
@@ -300,7 +300,7 @@ relay.command("token").description("Print the relay's current client token (auth
300
300
  console.error(`Dev Anywhere is not initialized. Run "dev-anywhere init" first.`);
301
301
  process.exit(1);
302
302
  }
303
- const { runRelayTokenCommand } = await import("./relay-token-KQPEQVP7.js");
303
+ const { runRelayTokenCommand } = await import("./relay-token-Z4JZFPQ5.js");
304
304
  await runRelayTokenCommand({ relayName: opts.relay });
305
305
  });
306
306
  program.addCommand(relay);
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  loadConfig
4
- } from "./chunk-R4S6OFIZ.js";
5
- import "./chunk-GTTLWHIG.js";
6
- import "./chunk-2XO3KLWW.js";
4
+ } from "./chunk-DCDXAM76.js";
5
+ import "./chunk-2JUB4LDU.js";
6
+ import "./chunk-QFYI6AMN.js";
7
7
 
8
8
  // src/relay-token.ts
9
9
  function toHttpUrl(relayUrl) {
@@ -30,7 +30,7 @@ async function runRelayTokenCommand(options) {
30
30
  );
31
31
  process.exit(1);
32
32
  }
33
- const adminUrl = `${toHttpUrl(relayUrl)}/admin/client-token`;
33
+ const adminUrl = `${toHttpUrl(relayUrl)}/api/admin/client-token`;
34
34
  let res;
35
35
  try {
36
36
  res = await fetch(adminUrl, {
@@ -78,4 +78,4 @@ function printResult(relayName, relayUrl, result) {
78
78
  export {
79
79
  runRelayTokenCommand
80
80
  };
81
- //# sourceMappingURL=relay-token-KQPEQVP7.js.map
81
+ //# sourceMappingURL=relay-token-Z4JZFPQ5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/relay-token.ts"],"sourcesContent":["// `dev-anywhere relay token` 实现:用本地 proxyToken 向已配置的 relay\n// 请求当前生效的 client token,避免运维者必须 ssh 到 VPS 读 .env。\nimport { loadConfig } from \"./common/config.js\";\n\ninterface FetchClientTokenResult {\n status: \"ok\" | \"no_client_token\";\n clientToken?: string;\n}\n\nfunction toHttpUrl(relayUrl: string): string {\n return relayUrl.replace(/^ws:/i, \"http:\").replace(/^wss:/i, \"https:\").replace(/\\/$/, \"\");\n}\n\nexport async function runRelayTokenCommand(options: { relayName?: string }): Promise<void> {\n let config: ReturnType<typeof loadConfig>;\n try {\n config = loadConfig({ relayName: options.relayName });\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n\n const { relayName, relayUrl, relayToken } = config;\n if (!relayUrl) {\n console.error(\n `Relay \"${relayName}\" has no URL configured. Edit ~/.dev-anywhere/config.json or set RELAY_URL.`,\n );\n process.exit(1);\n }\n if (!relayToken) {\n console.error(\n `Relay \"${relayName}\" has no proxy token configured. The admin endpoint requires one.`,\n );\n process.exit(1);\n }\n\n const adminUrl = `${toHttpUrl(relayUrl)}/api/admin/client-token`;\n let res: Response;\n try {\n res = await fetch(adminUrl, {\n headers: { authorization: `Bearer ${relayToken}` },\n cache: \"no-store\",\n });\n } catch (err) {\n console.error(`Request to ${adminUrl} failed: ${err instanceof Error ? err.message : err}`);\n process.exit(1);\n }\n\n if (res.status === 401) {\n console.error(\n `Relay rejected the proxy token (HTTP 401). Verify ~/.dev-anywhere/config.json matches the relay's RELAY_PROXY_TOKEN.`,\n );\n process.exit(1);\n }\n if (res.status === 204) {\n const result: FetchClientTokenResult = { status: \"no_client_token\" };\n printResult(relayName, relayUrl, result);\n return;\n }\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n console.error(`Unexpected response from relay (HTTP ${res.status}): ${body}`);\n process.exit(1);\n }\n\n const json = (await res.json()) as { clientToken?: unknown };\n if (typeof json.clientToken !== \"string\" || json.clientToken.length === 0) {\n console.error(`Relay returned a malformed payload: ${JSON.stringify(json)}`);\n process.exit(1);\n }\n printResult(relayName, relayUrl, { status: \"ok\", clientToken: json.clientToken });\n}\n\nfunction printResult(relayName: string, relayUrl: string, result: FetchClientTokenResult): void {\n const httpBase = toHttpUrl(relayUrl);\n console.log(`Relay: ${relayName} (${relayUrl})`);\n if (result.status === \"no_client_token\") {\n console.log(`Token: (not configured — /client endpoint is open)`);\n console.log(`URL: ${httpBase}/`);\n return;\n }\n console.log(`Token: ${result.clientToken}`);\n console.log(`URL: ${httpBase}/?relayToken=${encodeURIComponent(result.clientToken!)}`);\n}\n"],"mappings":";;;;;;;;AASA,SAAS,UAAU,UAA0B;AAC3C,SAAO,SAAS,QAAQ,SAAS,OAAO,EAAE,QAAQ,UAAU,QAAQ,EAAE,QAAQ,OAAO,EAAE;AACzF;AAEA,eAAsB,qBAAqB,SAAgD;AACzF,MAAI;AACJ,MAAI;AACF,aAAS,WAAW,EAAE,WAAW,QAAQ,UAAU,CAAC;AAAA,EACtD,SAAS,KAAK;AACZ,YAAQ,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAC9D,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,EAAE,WAAW,UAAU,WAAW,IAAI;AAC5C,MAAI,CAAC,UAAU;AACb,YAAQ;AAAA,MACN,UAAU,SAAS;AAAA,IACrB;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,MAAI,CAAC,YAAY;AACf,YAAQ;AAAA,MACN,UAAU,SAAS;AAAA,IACrB;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,WAAW,GAAG,UAAU,QAAQ,CAAC;AACvC,MAAI;AACJ,MAAI;AACF,UAAM,MAAM,MAAM,UAAU;AAAA,MAC1B,SAAS,EAAE,eAAe,UAAU,UAAU,GAAG;AAAA,MACjD,OAAO;AAAA,IACT,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,YAAQ,MAAM,cAAc,QAAQ,YAAY,eAAe,QAAQ,IAAI,UAAU,GAAG,EAAE;AAC1F,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,MAAI,IAAI,WAAW,KAAK;AACtB,YAAQ;AAAA,MACN;AAAA,IACF;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,MAAI,IAAI,WAAW,KAAK;AACtB,UAAM,SAAiC,EAAE,QAAQ,kBAAkB;AACnE,gBAAY,WAAW,UAAU,MAAM;AACvC;AAAA,EACF;AACA,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,OAAO,MAAM,IAAI,KAAK,EAAE,MAAM,MAAM,EAAE;AAC5C,YAAQ,MAAM,wCAAwC,IAAI,MAAM,MAAM,IAAI,EAAE;AAC5E,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,MAAI,OAAO,KAAK,gBAAgB,YAAY,KAAK,YAAY,WAAW,GAAG;AACzE,YAAQ,MAAM,uCAAuC,KAAK,UAAU,IAAI,CAAC,EAAE;AAC3E,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,cAAY,WAAW,UAAU,EAAE,QAAQ,MAAM,aAAa,KAAK,YAAY,CAAC;AAClF;AAEA,SAAS,YAAY,WAAmB,UAAkB,QAAsC;AAC9F,QAAM,WAAW,UAAU,QAAQ;AACnC,UAAQ,IAAI,UAAU,SAAS,KAAK,QAAQ,GAAG;AAC/C,MAAI,OAAO,WAAW,mBAAmB;AACvC,YAAQ,IAAI,yDAAoD;AAChE,YAAQ,IAAI,UAAU,QAAQ,GAAG;AACjC;AAAA,EACF;AACA,UAAQ,IAAI,UAAU,OAAO,WAAW,EAAE;AAC1C,UAAQ,IAAI,UAAU,QAAQ,gBAAgB,mBAAmB,OAAO,WAAY,CAAC,EAAE;AACzF;","names":[]}
package/dist/serve.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  KnownContentBlockSchema,
6
6
  SeqCounter,
7
7
  StreamJsonEventSchema
8
- } from "./chunk-PDX6QFJ7.js";
8
+ } from "./chunk-7XMJMVIL.js";
9
9
  import {
10
10
  createFSM,
11
11
  defineFSM,
@@ -27,15 +27,15 @@ import {
27
27
  createWorkerReader,
28
28
  serializeIpc,
29
29
  serializeWorkerMsg
30
- } from "./chunk-BLWDLNT6.js";
30
+ } from "./chunk-U5T7ZYXT.js";
31
31
  import {
32
32
  buildProviderEnv,
33
33
  loadConfig,
34
34
  saveAgentCliPath
35
- } from "./chunk-R4S6OFIZ.js";
35
+ } from "./chunk-DCDXAM76.js";
36
36
  import {
37
37
  serviceLogger
38
- } from "./chunk-GTTLWHIG.js";
38
+ } from "./chunk-2JUB4LDU.js";
39
39
  import {
40
40
  ControlErrorCode,
41
41
  DATA_DIR,
@@ -53,7 +53,7 @@ import {
53
53
  ensureProfileWorkspace,
54
54
  sessionPaths,
55
55
  tildify
56
- } from "./chunk-2XO3KLWW.js";
56
+ } from "./chunk-QFYI6AMN.js";
57
57
 
58
58
  // src/serve.ts
59
59
  import { createServer as createServer2 } from "net";
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  ControlRequestEventSchema,
4
4
  SeqCounter
5
- } from "./chunk-PDX6QFJ7.js";
5
+ } from "./chunk-7XMJMVIL.js";
6
6
  import {
7
7
  CLAUDE_PROVIDER
8
8
  } from "./chunk-6O6JTF24.js";
@@ -10,8 +10,8 @@ import {
10
10
  LineBuffer,
11
11
  createWorkerReader,
12
12
  serializeWorkerMsg
13
- } from "./chunk-BLWDLNT6.js";
14
- import "./chunk-2XO3KLWW.js";
13
+ } from "./chunk-U5T7ZYXT.js";
14
+ import "./chunk-QFYI6AMN.js";
15
15
 
16
16
  // src/session-worker.ts
17
17
  import { createServer } from "net";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  daemonRelayArgs
4
- } from "./chunk-2SBGSJLQ.js";
4
+ } from "./chunk-BMVYMCKF.js";
5
5
  import {
6
6
  createFSM,
7
7
  extractOscSequences,
@@ -20,17 +20,17 @@ import {
20
20
  createIpcReader,
21
21
  encodeBinaryIpcFrame,
22
22
  serializeIpc
23
- } from "./chunk-BLWDLNT6.js";
23
+ } from "./chunk-U5T7ZYXT.js";
24
24
  import {
25
25
  terminalLogger
26
- } from "./chunk-GTTLWHIG.js";
26
+ } from "./chunk-2JUB4LDU.js";
27
27
  import {
28
28
  PROFILE_NAME,
29
29
  SERVICE_LOG_PATH,
30
30
  SOCK_PATH,
31
31
  STOPPED_PATH,
32
32
  tildify
33
- } from "./chunk-2XO3KLWW.js";
33
+ } from "./chunk-QFYI6AMN.js";
34
34
 
35
35
  // src/terminal.ts
36
36
  import { connect } from "net";
@@ -680,4 +680,4 @@ async function startTerminal(providerArgs, providerId = providerFromEnv()) {
680
680
  export {
681
681
  startTerminal
682
682
  };
683
- //# sourceMappingURL=terminal-4MDRBCL4.js.map
683
+ //# sourceMappingURL=terminal-FJAIRC73.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dev-anywhere/proxy",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "Transparent local proxy for AI coding CLIs that bridges local sessions to a web/PWA client via a relay server.",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -52,8 +52,8 @@
52
52
  "@types/node": "^25.5.2",
53
53
  "@types/ws": "^8.18.1",
54
54
  "vitest": "^4.1.2",
55
- "@dev-anywhere/shared": "0.1.8",
56
- "@dev-anywhere/relay": "0.1.8"
55
+ "@dev-anywhere/shared": "0.1.9",
56
+ "@dev-anywhere/relay": "0.1.9"
57
57
  },
58
58
  "scripts": {
59
59
  "build": "tsup",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/relay-token.ts"],"sourcesContent":["// `dev-anywhere relay token` 实现:用本地 proxyToken 向已配置的 relay\n// 请求当前生效的 client token,避免运维者必须 ssh 到 VPS 读 .env。\nimport { loadConfig } from \"./common/config.js\";\n\ninterface FetchClientTokenResult {\n status: \"ok\" | \"no_client_token\";\n clientToken?: string;\n}\n\nfunction toHttpUrl(relayUrl: string): string {\n return relayUrl.replace(/^ws:/i, \"http:\").replace(/^wss:/i, \"https:\").replace(/\\/$/, \"\");\n}\n\nexport async function runRelayTokenCommand(options: { relayName?: string }): Promise<void> {\n let config: ReturnType<typeof loadConfig>;\n try {\n config = loadConfig({ relayName: options.relayName });\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n\n const { relayName, relayUrl, relayToken } = config;\n if (!relayUrl) {\n console.error(\n `Relay \"${relayName}\" has no URL configured. Edit ~/.dev-anywhere/config.json or set RELAY_URL.`,\n );\n process.exit(1);\n }\n if (!relayToken) {\n console.error(\n `Relay \"${relayName}\" has no proxy token configured. The admin endpoint requires one.`,\n );\n process.exit(1);\n }\n\n const adminUrl = `${toHttpUrl(relayUrl)}/admin/client-token`;\n let res: Response;\n try {\n res = await fetch(adminUrl, {\n headers: { authorization: `Bearer ${relayToken}` },\n cache: \"no-store\",\n });\n } catch (err) {\n console.error(`Request to ${adminUrl} failed: ${err instanceof Error ? err.message : err}`);\n process.exit(1);\n }\n\n if (res.status === 401) {\n console.error(\n `Relay rejected the proxy token (HTTP 401). Verify ~/.dev-anywhere/config.json matches the relay's RELAY_PROXY_TOKEN.`,\n );\n process.exit(1);\n }\n if (res.status === 204) {\n const result: FetchClientTokenResult = { status: \"no_client_token\" };\n printResult(relayName, relayUrl, result);\n return;\n }\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n console.error(`Unexpected response from relay (HTTP ${res.status}): ${body}`);\n process.exit(1);\n }\n\n const json = (await res.json()) as { clientToken?: unknown };\n if (typeof json.clientToken !== \"string\" || json.clientToken.length === 0) {\n console.error(`Relay returned a malformed payload: ${JSON.stringify(json)}`);\n process.exit(1);\n }\n printResult(relayName, relayUrl, { status: \"ok\", clientToken: json.clientToken });\n}\n\nfunction printResult(relayName: string, relayUrl: string, result: FetchClientTokenResult): void {\n const httpBase = toHttpUrl(relayUrl);\n console.log(`Relay: ${relayName} (${relayUrl})`);\n if (result.status === \"no_client_token\") {\n console.log(`Token: (not configured — /client endpoint is open)`);\n console.log(`URL: ${httpBase}/`);\n return;\n }\n console.log(`Token: ${result.clientToken}`);\n console.log(`URL: ${httpBase}/?relayToken=${encodeURIComponent(result.clientToken!)}`);\n}\n"],"mappings":";;;;;;;;AASA,SAAS,UAAU,UAA0B;AAC3C,SAAO,SAAS,QAAQ,SAAS,OAAO,EAAE,QAAQ,UAAU,QAAQ,EAAE,QAAQ,OAAO,EAAE;AACzF;AAEA,eAAsB,qBAAqB,SAAgD;AACzF,MAAI;AACJ,MAAI;AACF,aAAS,WAAW,EAAE,WAAW,QAAQ,UAAU,CAAC;AAAA,EACtD,SAAS,KAAK;AACZ,YAAQ,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAC9D,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,EAAE,WAAW,UAAU,WAAW,IAAI;AAC5C,MAAI,CAAC,UAAU;AACb,YAAQ;AAAA,MACN,UAAU,SAAS;AAAA,IACrB;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,MAAI,CAAC,YAAY;AACf,YAAQ;AAAA,MACN,UAAU,SAAS;AAAA,IACrB;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,WAAW,GAAG,UAAU,QAAQ,CAAC;AACvC,MAAI;AACJ,MAAI;AACF,UAAM,MAAM,MAAM,UAAU;AAAA,MAC1B,SAAS,EAAE,eAAe,UAAU,UAAU,GAAG;AAAA,MACjD,OAAO;AAAA,IACT,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,YAAQ,MAAM,cAAc,QAAQ,YAAY,eAAe,QAAQ,IAAI,UAAU,GAAG,EAAE;AAC1F,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,MAAI,IAAI,WAAW,KAAK;AACtB,YAAQ;AAAA,MACN;AAAA,IACF;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,MAAI,IAAI,WAAW,KAAK;AACtB,UAAM,SAAiC,EAAE,QAAQ,kBAAkB;AACnE,gBAAY,WAAW,UAAU,MAAM;AACvC;AAAA,EACF;AACA,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,OAAO,MAAM,IAAI,KAAK,EAAE,MAAM,MAAM,EAAE;AAC5C,YAAQ,MAAM,wCAAwC,IAAI,MAAM,MAAM,IAAI,EAAE;AAC5E,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,MAAI,OAAO,KAAK,gBAAgB,YAAY,KAAK,YAAY,WAAW,GAAG;AACzE,YAAQ,MAAM,uCAAuC,KAAK,UAAU,IAAI,CAAC,EAAE;AAC3E,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,cAAY,WAAW,UAAU,EAAE,QAAQ,MAAM,aAAa,KAAK,YAAY,CAAC;AAClF;AAEA,SAAS,YAAY,WAAmB,UAAkB,QAAsC;AAC9F,QAAM,WAAW,UAAU,QAAQ;AACnC,UAAQ,IAAI,UAAU,SAAS,KAAK,QAAQ,GAAG;AAC/C,MAAI,OAAO,WAAW,mBAAmB;AACvC,YAAQ,IAAI,yDAAoD;AAChE,YAAQ,IAAI,UAAU,QAAQ,GAAG;AACjC;AAAA,EACF;AACA,UAAQ,IAAI,UAAU,OAAO,WAAW,EAAE;AAC1C,UAAQ,IAAI,UAAU,QAAQ,gBAAgB,mBAAmB,OAAO,WAAY,CAAC,EAAE;AACzF;","names":[]}