#!/usr/bin/env node

// ../../packages/shared/dist/schemas/envelope.js
import { z as z6 } from "zod";

// ../../packages/shared/dist/schemas/id.js
import { z } from "zod";
var MAX_ID_LENGTH = 256;
var IdSchema = z.string().min(1).max(MAX_ID_LENGTH);

// ../../packages/shared/dist/schemas/chat.js
import { z as z2 } from "zod";
var UserInputPayloadSchema = z2.object({
  text: z2.string().min(1),
  messageId: z2.string().min(1).optional()
});
var AssistantMessagePayloadSchema = z2.object({
  text: z2.string(),
  isPartial: z2.boolean()
});
var ThinkingPayloadSchema = z2.object({
  text: z2.string()
});

// ../../packages/shared/dist/schemas/tool.js
import { z as z3 } from "zod";
var ToolUseRequestPayloadSchema = z3.object({
  toolName: z3.string(),
  toolId: IdSchema,
  parameters: z3.record(z3.string(), z3.unknown())
});
var ToolApprovePayloadSchema = z3.object({
  toolId: IdSchema,
  whitelistTool: z3.boolean().optional()
});
var ToolDenyPayloadSchema = z3.object({
  toolId: IdSchema,
  reason: z3.string().optional()
});
var ToolResultPayloadSchema = z3.object({
  toolId: IdSchema,
  result: z3.unknown(),
  isError: z3.boolean()
});

// ../../packages/shared/dist/schemas/session.js
import { z as z4 } from "zod";

// ../../packages/shared/dist/constants/enums.js
var providerValues = ["claude", "codex"];
var ptyOwnerValues = ["local-terminal", "proxy-hosted"];
var sessionModeValues = ["pty", "json"];
var sessionKindValues = ["agent", "terminal"];

// ../../packages/shared/dist/constants/pty.js
var PtySemanticState = {
  WORKING: "working",
  TURN_COMPLETE: "turn_complete",
  APPROVAL_WAIT: "approval_wait"
};
var ptySemanticStateValues = [
  PtySemanticState.WORKING,
  PtySemanticState.TURN_COMPLETE,
  PtySemanticState.APPROVAL_WAIT
];

// ../../packages/shared/dist/schemas/session.js
var sessionStateValues = [
  "idle",
  "working",
  "compacting",
  "waiting_approval",
  "error",
  "terminated"
];
var agentStatusPhaseValues = [
  "idle",
  "thinking",
  "tool_use",
  "outputting",
  "waiting_permission",
  "error"
];
var SessionInfoSchema = z4.object({
  sessionId: IdSchema,
  kind: z4.enum(sessionKindValues).optional(),
  name: z4.string().optional(),
  // cwd 只用于展示完整路径/tooltip，不作为前端路由或权限判断来源。
  cwd: z4.string().optional(),
  // true 表示 name 是用户显式命名，PTY UI 不再让 OSC terminal_title 覆盖它。
  nameLocked: z4.boolean().optional(),
  state: z4.enum(sessionStateValues),
  mode: z4.enum(sessionModeValues).optional(),
  provider: z4.enum(providerValues),
  // PTY 尺寸所有权:
  // - local-terminal: 本地 terminal 进程持有真实 PTY，Web 只按原始 cols/rows 展示
  // - proxy-hosted: serve 内托管 PTY，Web 可按视口请求 resize
  ptyOwner: z4.enum(ptyOwnerValues).optional(),
  lastActive: z4.number().optional()
});
var SessionCreatePayloadSchema = z4.object({
  name: z4.string().optional(),
  cwd: z4.string().optional(),
  streamDelta: z4.boolean().optional()
});
var SessionListPayloadSchema = z4.object({
  sessions: z4.array(SessionInfoSchema)
});
var SessionSwitchPayloadSchema = z4.object({
  sessionId: IdSchema
});
var SessionTerminatePayloadSchema = z4.object({
  sessionId: IdSchema
});
var SessionStatusPayloadSchema = z4.object({
  sessionId: IdSchema,
  state: z4.enum(sessionStateValues),
  lastActive: z4.number()
});
var PtyStatePayloadSchema = z4.object({
  state: z4.enum(ptySemanticStateValues),
  // Semantic event sequence. Present for runtime PTY semantic events; optional for
  // legacy cleanup messages from older proxies.
  seq: z4.number().int().nonnegative().optional(),
  title: z4.string().optional(),
  tool: z4.string().optional()
});
var AgentStatusPayloadSchema = z4.object({
  provider: z4.enum(providerValues),
  phase: z4.enum(agentStatusPhaseValues),
  seq: z4.number().int().nonnegative(),
  updatedAt: z4.number(),
  toolName: z4.string().optional(),
  toolInput: z4.record(z4.string(), z4.unknown()).optional(),
  permissionRequest: z4.object({
    requestId: IdSchema,
    toolName: z4.string(),
    input: z4.record(z4.string(), z4.unknown())
  }).optional(),
  permissionResolution: z4.object({
    requestId: IdSchema,
    outcome: z4.enum(["allow", "deny"])
  }).optional(),
  summary: z4.string().optional()
});

// ../../packages/shared/dist/schemas/system.js
import { z as z5 } from "zod";
var HeartbeatPayloadSchema = z5.object({});
var AuthPayloadSchema = z5.object({
  pairingCode: z5.string().optional(),
  token: z5.string().optional()
});
var SyncRequestPayloadSchema = z5.object({
  lastSeq: z5.number().int().nonnegative()
});
var SyncResponsePayloadSchema = z5.object({
  messages: z5.array(z5.record(z5.string(), z5.unknown()))
});

// ../../packages/shared/dist/schemas/envelope.js
var BaseEnvelopeFields = {
  seq: z6.number().int().nonnegative(),
  timestamp: z6.number(),
  source: z6.enum(["proxy", "client"]),
  version: z6.string()
};
var SessionedEnvelopeFields = {
  ...BaseEnvelopeFields,
  sessionId: IdSchema
};
var MessageEnvelopeSchema = z6.discriminatedUnion("type", [
  // chat (3)
  z6.object({
    ...SessionedEnvelopeFields,
    type: z6.literal("user_input"),
    payload: UserInputPayloadSchema
  }),
  z6.object({
    ...SessionedEnvelopeFields,
    type: z6.literal("assistant_message"),
    payload: AssistantMessagePayloadSchema
  }),
  z6.object({
    ...SessionedEnvelopeFields,
    type: z6.literal("thinking"),
    payload: ThinkingPayloadSchema
  }),
  // tool (4): 工具审批决策属于 relay control，不进入会话消息信封。
  // tool_use_request: 审批流请求（proxy → client），toolId 是 approval requestId
  z6.object({
    ...SessionedEnvelopeFields,
    type: z6.literal("tool_use_request"),
    payload: ToolUseRequestPayloadSchema
  }),
  // tool_result: 工具执行结果（proxy → client），toolId 对应 assistant_tool_use / tool_use_request 的 toolId
  z6.object({
    ...SessionedEnvelopeFields,
    type: z6.literal("tool_result"),
    payload: ToolResultPayloadSchema
  }),
  // assistant_tool_use: 纯展示型工具调用（proxy → client），区别于 tool_use_request 无审批语义
  // payload 结构复用 ToolUseRequestPayloadSchema；toolId 是 Claude 分配的 tool_use id
  z6.object({
    ...SessionedEnvelopeFields,
    type: z6.literal("assistant_tool_use"),
    payload: ToolUseRequestPayloadSchema
  }),
  // session (5)
  z6.object({
    ...SessionedEnvelopeFields,
    type: z6.literal("session_create"),
    payload: SessionCreatePayloadSchema
  }),
  // session_list 是全局广播 (列出所有 session), 不绑定具体 sessionId, 不携带该字段。
  z6.object({
    ...BaseEnvelopeFields,
    type: z6.literal("session_list"),
    payload: SessionListPayloadSchema
  }),
  z6.object({
    ...SessionedEnvelopeFields,
    type: z6.literal("session_switch"),
    payload: SessionSwitchPayloadSchema
  }),
  z6.object({
    ...SessionedEnvelopeFields,
    type: z6.literal("session_terminate"),
    payload: SessionTerminatePayloadSchema
  }),
  z6.object({
    ...SessionedEnvelopeFields,
    type: z6.literal("session_status"),
    payload: SessionStatusPayloadSchema
  }),
  // system (5): 心跳 / 认证 / 同步——全局, 无 sessionId
  z6.object({
    ...BaseEnvelopeFields,
    type: z6.literal("heartbeat"),
    payload: HeartbeatPayloadSchema
  }),
  z6.object({
    ...BaseEnvelopeFields,
    type: z6.literal("auth"),
    payload: AuthPayloadSchema
  }),
  z6.object({
    ...BaseEnvelopeFields,
    type: z6.literal("sync_request"),
    payload: SyncRequestPayloadSchema
  }),
  z6.object({
    ...BaseEnvelopeFields,
    type: z6.literal("sync_response"),
    payload: SyncResponsePayloadSchema
  })
]);

// ../../packages/shared/dist/builders/index.js
function buildMessage(type, sessionId, seq, payload, source) {
  const envelope = {
    seq,
    ...sessionId !== null ? { sessionId } : {},
    type,
    payload,
    timestamp: Date.now(),
    source,
    version: "1.0"
  };
  return MessageEnvelopeSchema.parse(envelope);
}
function serializeControl(msg) {
  return JSON.stringify(msg);
}

// ../../packages/shared/dist/state-machine.js
function computeAbsorbingSet(transitions) {
  const absorbing = /* @__PURE__ */ new Set();
  const entries = Object.entries(transitions);
  for (const [s, outs] of entries) {
    if (outs.length === 0)
      absorbing.add(s);
  }
  let changed = true;
  while (changed) {
    changed = false;
    for (const [s, outs] of entries) {
      if (absorbing.has(s))
        continue;
      if (outs.length > 0 && outs.every((t) => absorbing.has(t))) {
        absorbing.add(s);
        changed = true;
      }
    }
  }
  return absorbing;
}
function createFSM(def) {
  let state = def.initial;
  const absorbing = computeAbsorbingSet(def.transitions);
  const tryTransitionTo = (to) => {
    const allowed = def.transitions[state];
    if (!allowed?.includes(to)) {
      def.onRejected?.(state, to, absorbing.has(state));
      return false;
    }
    const from = state;
    state = to;
    def.onTransition?.(from, to);
    return true;
  };
  return {
    current: () => state,
    is: (s) => state === s,
    isIn: (ss) => ss.includes(state),
    canTransitionTo: (to) => def.transitions[state]?.includes(to) ?? false,
    transitionTo: (to) => {
      if (!tryTransitionTo(to)) {
        throw new Error(`Invalid FSM transition: ${state} -> ${to}`);
      }
    },
    tryTransitionTo,
    isInAbsorbingState: () => absorbing.has(state)
  };
}
function defineFSM(transitions) {
  const absorbing = computeAbsorbingSet(transitions);
  return {
    canTransition: (from, to) => transitions[from]?.includes(to) ?? false,
    isAbsorbing: (state) => absorbing.has(state)
  };
}

// ../../packages/shared/dist/schemas/voice.js
import { z as z7 } from "zod";
var voiceProviderValues = ["aliyun-bailian"];
var voiceRegionValues = ["cn", "intl"];
var voiceOptionSourceValues = ["official", "custom"];
var voiceOptionGenderValues = ["male", "female", "unknown"];
var VoiceProviderConfigSchema = z7.object({
  provider: z7.enum(voiceProviderValues),
  configured: z7.boolean(),
  region: z7.enum(voiceRegionValues),
  asrModel: z7.string().min(1),
  ttsModel: z7.string().min(1),
  ttsVoice: z7.string().min(1),
  turnIdleSeconds: z7.number().int().positive().safe().default(3)
}).strict();
var VoiceConfigUpdateSchema = z7.object({
  provider: z7.enum(voiceProviderValues).optional(),
  apiKey: z7.string().min(1).optional(),
  clearApiKey: z7.boolean().optional(),
  region: z7.enum(voiceRegionValues).optional(),
  asrModel: z7.string().min(1).optional(),
  ttsModel: z7.string().min(1).optional(),
  ttsVoice: z7.string().min(1).optional(),
  turnIdleSeconds: z7.number().int().positive().safe().optional()
}).strict();
var VoiceOptionSchema = z7.object({
  value: z7.string().min(1),
  label: z7.string().min(1),
  description: z7.string().min(1).optional(),
  gender: z7.enum(voiceOptionGenderValues).optional(),
  age: z7.string().min(1).optional(),
  model: z7.string().min(1).optional(),
  source: z7.enum(voiceOptionSourceValues)
}).strict();
var VoiceCapabilitiesSchema = z7.object({
  asrModels: z7.array(VoiceOptionSchema),
  ttsModels: z7.array(VoiceOptionSchema),
  ttsVoices: z7.array(VoiceOptionSchema),
  fetchedAt: z7.number().optional()
}).strict();
var VoiceSummaryReasonSchema = z7.enum([
  "code",
  "table",
  "diff",
  "log",
  "stack_trace",
  "long_list",
  "long_text",
  "mixed",
  "approval"
]);

// ../../packages/shared/dist/slash-commands.js
function isCompactCommandText(text) {
  return /^\/compact(?:\s|$)/.test(text.trimStart());
}

// ../../packages/shared/dist/schemas/relay-control.js
import { z as z8 } from "zod";

// ../../packages/shared/dist/constants/relay-errors.js
var RelayErrorCode = {
  NOT_REGISTERED: "NOT_REGISTERED",
  NOT_BOUND: "NOT_BOUND",
  PROXY_OFFLINE: "PROXY_OFFLINE",
  INVALID_MESSAGE: "INVALID_MESSAGE",
  UNSUPPORTED: "UNSUPPORTED",
  INVALID_RANGE: "INVALID_RANGE"
};

// ../../packages/shared/dist/constants/control-errors.js
var ControlErrorCode = {
  INVALID_PATH: "INVALID_PATH",
  PATH_NOT_FOUND: "PATH_NOT_FOUND",
  PATH_NOT_DIRECTORY: "PATH_NOT_DIRECTORY",
  PATH_ACCESS_DENIED: "PATH_ACCESS_DENIED",
  PROXY_OFFLINE: "PROXY_OFFLINE",
  SESSION_NOT_FOUND: "SESSION_NOT_FOUND",
  PROVIDER_UNSUPPORTED: "PROVIDER_UNSUPPORTED",
  WORKER_START_FAILED: "WORKER_START_FAILED",
  PROCESS_START_FAILED: "PROCESS_START_FAILED",
  UNKNOWN: "UNKNOWN"
};

// ../../packages/shared/dist/schemas/relay-control.js
var ProxyInfoSchema = z8.object({
  proxyId: IdSchema,
  name: z8.string().optional(),
  online: z8.boolean(),
  sessions: z8.array(z8.string()).optional()
});
var RelayClientInfoSchema = z8.object({
  clientId: IdSchema,
  proxyId: IdSchema.optional(),
  connectedAt: z8.number().int().nonnegative(),
  current: z8.boolean().optional(),
  userAgent: z8.string().optional(),
  platform: z8.string().optional(),
  maxTouchPoints: z8.number().int().nonnegative().optional(),
  browserName: z8.string().min(1),
  osName: z8.string().min(1),
  deviceKind: z8.enum(["desktop", "tablet", "phone", "unknown"]),
  remoteAddress: z8.string().optional()
});
var AgentCliAvailabilitySchema = z8.object({
  available: z8.boolean(),
  command: z8.string().optional(),
  error: z8.string().optional(),
  suggestions: z8.array(z8.string()).optional()
});
var AgentCliStatusSchema = z8.object({
  claude: AgentCliAvailabilitySchema,
  codex: AgentCliAvailabilitySchema
});
var DirEntrySchema = z8.object({ name: z8.string(), isDir: z8.boolean() });
var FileTreeGroupSchema = z8.object({
  path: z8.string(),
  entries: z8.array(DirEntrySchema)
});
var CommandEntrySchema = z8.object({
  name: z8.string(),
  description: z8.string(),
  argumentHint: z8.string().optional(),
  source: z8.string()
});
var HistorySessionSchema = z8.object({
  id: z8.string(),
  title: z8.string(),
  projectDir: z8.string(),
  updatedAt: z8.number(),
  provider: z8.enum(providerValues).optional(),
  preferredMode: z8.enum(sessionModeValues).optional()
});
var SessionHistoryMessageSchema = z8.object({
  role: z8.enum(["user", "assistant", "system"]),
  text: z8.string(),
  timestamp: z8.number().optional(),
  cursor: z8.string().optional()
});
var RequestIdShape = { requestId: IdSchema.optional() };
var RequiredRequestIdShape = { requestId: IdSchema };
var ControlErrorCodeSchema = z8.enum(Object.values(ControlErrorCode));
var RequestErrorShape = {
  error: z8.string().optional(),
  errorCode: ControlErrorCodeSchema.optional()
};
var RemoteFileDispositionSchema = z8.enum(["inline", "download"]);
var RemoteFileUploadKindSchema = z8.enum(["clipboard_image", "file"]);
function control(type, shape, directions) {
  return {
    type,
    directions: new Set(Array.isArray(directions) ? directions : directions ? [directions] : []),
    schema: z8.object({
      type: z8.literal(type),
      ...shape ?? {}
    })
  };
}
var relayControlDefinitions = [
  control("proxy_register", {
    proxyId: IdSchema,
    name: z8.string().optional()
  }),
  control("proxy_register_response", {
    status: z8.enum(["new", "reconnected"])
  }),
  control("proxy_list_request", RequestIdShape),
  control("proxy_list_response", {
    ...RequestIdShape,
    proxies: z8.array(ProxyInfoSchema)
  }),
  control("relay_client_list_request", RequestIdShape),
  control("relay_client_list_response", {
    ...RequestIdShape,
    clients: z8.array(RelayClientInfoSchema)
  }),
  control("relay_client_kick", { ...RequiredRequestIdShape, clientId: IdSchema }),
  control("relay_client_kick_response", {
    ...RequiredRequestIdShape,
    clientId: IdSchema,
    success: z8.boolean(),
    ...RequestErrorShape
  }),
  control("relay_client_kicked", {
    reason: z8.string().optional()
  }),
  control("remote_file_url_request", {
    ...RequiredRequestIdShape,
    sessionId: IdSchema,
    path: z8.string().min(1),
    disposition: RemoteFileDispositionSchema
  }),
  control("remote_file_url_response", {
    ...RequiredRequestIdShape,
    ...RequestErrorShape,
    sessionId: IdSchema,
    path: z8.string().optional(),
    success: z8.boolean(),
    url: z8.string().optional(),
    expiresAt: z8.number().int().nonnegative().optional()
  }),
  control("remote_file_stream_request", {
    streamId: IdSchema,
    sessionId: IdSchema,
    path: z8.string().min(1),
    disposition: RemoteFileDispositionSchema
  }),
  control("remote_file_stream_response", {
    ...RequestErrorShape,
    streamId: IdSchema,
    sessionId: IdSchema,
    success: z8.boolean(),
    path: z8.string().optional(),
    mimeType: z8.string().optional(),
    size: z8.number().int().nonnegative().optional(),
    fileName: z8.string().optional()
  }),
  control("remote_file_stream_complete", {
    ...RequestErrorShape,
    streamId: IdSchema,
    success: z8.boolean()
  }),
  control("remote_file_stream_cancel", {
    streamId: IdSchema
  }),
  control("remote_file_upload_url_request", {
    ...RequiredRequestIdShape,
    sessionId: IdSchema,
    kind: RemoteFileUploadKindSchema,
    fileName: z8.string().optional(),
    mimeType: z8.string().min(1),
    size: z8.number().int().nonnegative().optional()
  }),
  control("remote_file_upload_url_response", {
    ...RequiredRequestIdShape,
    ...RequestErrorShape,
    sessionId: IdSchema,
    success: z8.boolean(),
    uploadUrl: z8.string().optional(),
    expiresAt: z8.number().int().nonnegative().optional()
  }),
  control("remote_file_upload_stream_request", {
    uploadId: IdSchema,
    sessionId: IdSchema,
    kind: RemoteFileUploadKindSchema,
    fileName: z8.string().optional(),
    mimeType: z8.string().min(1),
    size: z8.number().int().nonnegative().optional()
  }),
  control("remote_file_upload_stream_complete", {
    uploadId: IdSchema
  }),
  control("remote_file_upload_stream_cancel", {
    uploadId: IdSchema
  }),
  control("remote_file_upload_stream_response", {
    ...RequestErrorShape,
    uploadId: IdSchema,
    sessionId: IdSchema,
    success: z8.boolean(),
    path: z8.string().optional()
  }),
  control("proxy_select", { ...RequestIdShape, proxyId: IdSchema }),
  control("proxy_select_response", {
    ...RequestIdShape,
    success: z8.boolean(),
    proxyId: IdSchema.optional(),
    ...RequestErrorShape
  }),
  control("relay_error", {
    code: z8.enum(Object.values(RelayErrorCode)),
    message: z8.string(),
    // 可选 requestId: relay 把 client 发来 raw 的 requestId 字段透传回来,
    // client 侧 waitForMessage 据此把对应 pending request 立即拒掉而不必等到 timeout。
    requestId: IdSchema.optional()
  }),
  // Voice Pilot config is relay-local: client reads/updates the relay's stored provider settings.
  control("voice_config_request", RequestIdShape),
  control("voice_config_response", {
    ...RequestIdShape,
    ...RequestErrorShape,
    config: VoiceProviderConfigSchema.optional()
  }),
  control("voice_config_update", {
    ...RequestIdShape,
    config: VoiceConfigUpdateSchema
  }),
  control("voice_config_update_response", {
    ...RequestIdShape,
    ...RequestErrorShape,
    success: z8.boolean(),
    config: VoiceProviderConfigSchema.optional()
  }),
  control("voice_config_test", {
    ...RequestIdShape,
    config: VoiceConfigUpdateSchema.optional()
  }),
  control("voice_config_test_response", {
    ...RequestIdShape,
    ...RequestErrorShape,
    success: z8.boolean(),
    audioBase64: z8.string().optional(),
    audioSampleRate: z8.number().int().positive().optional(),
    audioEncoding: z8.literal("pcm_s16le").optional(),
    transcript: z8.string().optional()
  }),
  control("voice_capabilities_request", {
    ...RequestIdShape,
    region: z8.enum(voiceRegionValues).optional()
  }),
  control("voice_capabilities_response", {
    ...RequestIdShape,
    ...RequestErrorShape,
    capabilities: VoiceCapabilitiesSchema.optional()
  }),
  // Lightweight latency probes. These measure synthetic round-trip latency for the transport
  // segments and intentionally stay separate from PTY input echo tracing.
  control("latency_web_relay_ping", RequiredRequestIdShape),
  control("latency_web_relay_pong", {
    ...RequiredRequestIdShape,
    relayNow: z8.number().optional()
  }),
  control("latency_relay_proxy_request", RequiredRequestIdShape),
  control("latency_relay_proxy_response", {
    ...RequiredRequestIdShape,
    success: z8.boolean(),
    rttMs: z8.number().nonnegative().optional(),
    error: z8.string().optional()
  }),
  control("latency_relay_proxy_ping", {
    ...RequiredRequestIdShape,
    relayNow: z8.number().optional()
  }),
  control("latency_relay_proxy_pong", {
    ...RequiredRequestIdShape,
    proxyNow: z8.number().optional()
  }),
  control("latency_web_proxy_ping", RequiredRequestIdShape, "client_to_proxy"),
  control("latency_web_proxy_pong", { ...RequiredRequestIdShape, proxyNow: z8.number().optional() }, "proxy_to_client"),
  // 客户端注册协议
  control("client_register", {
    clientId: IdSchema,
    userAgent: z8.string().optional(),
    platform: z8.string().optional(),
    maxTouchPoints: z8.number().int().nonnegative().optional(),
    browserName: z8.string().min(1),
    osName: z8.string().min(1),
    deviceKind: z8.enum(["desktop", "tablet", "phone", "unknown"])
  }),
  control("client_register_response", {
    status: z8.enum(["restored", "proxy_offline", "new"]),
    proxyId: IdSchema.optional()
  }),
  // Proxy 离线通知
  control("proxy_offline", {
    proxyId: IdSchema
  }),
  // Proxy 主动断开，relay 立即清理资源
  control("proxy_disconnect", {
    proxyId: IdSchema
  }),
  // Proxy 重连后通知 client 恢复
  control("proxy_online", {
    proxyId: IdSchema
  }),
  // 目录列表请求与响应
  control("dir_list_request", {
    proxyId: IdSchema.optional(),
    ...RequestIdShape,
    path: z8.string()
  }, "client_to_proxy"),
  control("dir_list_response", { ...RequestIdShape, ...RequestErrorShape, entries: z8.array(DirEntrySchema), path: z8.string() }, "proxy_to_client"),
  // 目录创建请求与响应
  control("dir_create_request", { ...RequestIdShape, path: z8.string() }, "client_to_proxy"),
  control("dir_create_response", {
    ...RequestIdShape,
    ...RequestErrorShape,
    path: z8.string(),
    success: z8.boolean()
  }, "proxy_to_client"),
  // 命令列表推送，proxy 将可用命令列表推给 client
  control("command_list_push", { commands: z8.array(CommandEntrySchema) }, "proxy_to_client"),
  // 文件树推送: 按目录分组, 首组 path 即为 session cwd
  // 前端直接把每组写入 tree[path], 与 dir_list_response 共享 cache slot
  control("file_tree_push", {
    groups: z8.array(FileTreeGroupSchema)
  }, "proxy_to_client"),
  // 会话列表请求与权限模式变更
  control("session_list", void 0, ["client_to_proxy", "proxy_to_client"]),
  control("permission_mode_change", {
    mode: z8.enum(["default", "auto_accept", "plan"]),
    // sessionId 可选：传入时 proxy 按该会话的 mode 分叉（PTY 发 Tab ANSI），未传走全局日志行为
    sessionId: IdSchema.optional()
  }, "client_to_proxy"),
  // 会话历史浏览
  control("session_history_request", RequestIdShape, "client_to_proxy"),
  control("session_history_response", { ...RequestIdShape, sessions: z8.array(HistorySessionSchema) }, "proxy_to_client"),
  // PTY 语义状态，从 Envelope 迁移到 Control 层
  control("pty_state", { sessionId: IdSchema, payload: PtyStatePayloadSchema }, "proxy_to_client"),
  // Provider 语义状态，来自 Claude/Codex hook 等结构化事件，不从 PTY 字节推断
  control("agent_status", { sessionId: IdSchema, payload: AgentStatusPayloadSchema }, "proxy_to_client"),
  // 终端标题变化，proxy -> client
  control("terminal_title", { sessionId: IdSchema, title: z8.string() }, "proxy_to_client"),
  // 终端尺寸变化，proxy -> client
  control("terminal_resize", { sessionId: IdSchema, cols: z8.number().int().positive(), rows: z8.number().int().positive() }, "proxy_to_client"),
  control("terminal_resize_request", { sessionId: IdSchema, cols: z8.number().int().positive(), rows: z8.number().int().positive() }, "client_to_proxy"),
  // 远程终止 JSON 会话，client -> proxy
  control("session_terminate", { sessionId: IdSchema }, "client_to_proxy"),
  control("session_rename", { ...RequestIdShape, sessionId: IdSchema, name: z8.string() }, "client_to_proxy"),
  control("session_rename_response", {
    ...RequestIdShape,
    sessionId: IdSchema,
    success: z8.boolean(),
    name: z8.string().optional(),
    ...RequestErrorShape
  }, "proxy_to_client"),
  // 中断当前 turn，client -> proxy；JSON 由 session-worker 打断 Claude 子进程并保留会话。
  control("session_worker_abort", { sessionId: IdSchema }, "client_to_proxy"),
  // turn 完成信号，proxy -> client，对应 claude stream-json 的 result 事件
  control("turn_result", {
    sessionId: IdSchema,
    success: z8.boolean(),
    isError: z8.boolean(),
    // stream-json result.result 是本轮最终文本。assistant_message 流丢失或 CLI 未发增量时，
    // Web 用它作为 JSON 模式兜底展示，避免 turn 已结束但界面空白。
    result: z8.string().optional()
  }, "proxy_to_client"),
  // 客户端发送到 PTY 的原始字节（ANSI 序列），不追加换行
  control("remote_input_raw", { sessionId: IdSchema, data: z8.string(), traceId: IdSchema.optional() }, "client_to_proxy"),
  // 客户端询问 proxy 的环境信息 (home 路径等), client -> proxy -> response
  // FilePathPicker 用 homePath 作为 select 模式下的默认起点, 新建会话时打开即可浏览
  control("proxy_info_request", RequestIdShape, "client_to_proxy"),
  control("proxy_info", { ...RequestIdShape, homePath: z8.string(), agentCli: AgentCliStatusSchema }, "proxy_to_client"),
  control("agent_cli_config_update", { ...RequestIdShape, provider: z8.enum(providerValues), path: z8.string().min(1) }, "client_to_proxy"),
  control("agent_cli_config_update_response", {
    ...RequestIdShape,
    provider: z8.enum(providerValues),
    agentCli: AgentCliStatusSchema.optional(),
    ...RequestErrorShape
  }, "proxy_to_client"),
  // 远程创建 JSON 会话，client -> proxy -> response
  control("session_create", {
    ...RequestIdShape,
    kind: z8.enum(sessionKindValues).optional(),
    cwd: z8.string().optional(),
    name: z8.string().optional(),
    provider: z8.enum(providerValues).optional(),
    mode: z8.enum(sessionModeValues).optional(),
    resumeSessionId: z8.string().optional(),
    // 透传给 claude CLI 的 --permission-mode, undefined 时 proxy 兜底为 "default"
    permissionMode: z8.enum(["default", "auto", "acceptEdits", "plan", "bypassPermissions", "dontAsk"]).optional()
  }, "client_to_proxy"),
  control("session_create_response", {
    ...RequestIdShape,
    // 失败路径只送 errorCode/error, sessionId 此时无语义。成功路径才有 id。
    sessionId: IdSchema.optional(),
    name: z8.string().optional(),
    nameLocked: z8.boolean().optional(),
    kind: z8.enum(sessionKindValues).optional(),
    mode: z8.enum(sessionModeValues).optional(),
    provider: z8.enum(providerValues).optional(),
    ptyOwner: z8.enum(ptyOwnerValues).optional(),
    ...RequestErrorShape
  }, "proxy_to_client"),
  // 客户端请求会话历史消息，client -> proxy
  control("session_messages_request", {
    ...RequestIdShape,
    sessionId: IdSchema,
    limit: z8.number().int().min(1).max(200).optional(),
    before: z8.string().optional()
  }, "client_to_proxy"),
  // 客户端请求会话资源（命令列表 + 文件树），client -> proxy
  control("session_resources_request", { ...RequestIdShape, sessionId: IdSchema }, "client_to_proxy"),
  control("session_resources_response", {
    ...RequestIdShape,
    ...RequestErrorShape,
    sessionId: IdSchema,
    commands: z8.array(CommandEntrySchema),
    groups: z8.array(FileTreeGroupSchema)
  }, "proxy_to_client"),
  // 客户端请求当前 provider 语义状态；不经 relay 缓存，由 proxy 返回当前值
  control("agent_status_request", { ...RequestIdShape, sessionId: IdSchema.optional() }, "client_to_proxy"),
  control("agent_status_response", {
    ...RequestIdShape,
    statuses: z8.array(z8.object({ sessionId: IdSchema, payload: AgentStatusPayloadSchema }))
  }, "proxy_to_client"),
  // 客户端确认已收到审批请求；proxy 只记录送达状态，不把它当成用户决策
  control("permission_request_delivered", { sessionId: IdSchema, requestId: IdSchema }, "client_to_proxy"),
  control("tool_approve", { sessionId: IdSchema, payload: ToolApprovePayloadSchema }, "client_to_proxy"),
  control("tool_deny", { sessionId: IdSchema, payload: ToolDenyPayloadSchema }, "client_to_proxy"),
  // proxy 确认用户决策已进入 provider/worker 路径；web 用它更新审批卡片状态
  control("permission_decision_result", {
    sessionId: IdSchema,
    requestId: IdSchema,
    outcome: z8.enum(["allow", "deny"]),
    delivered: z8.boolean(),
    message: z8.string().optional()
  }, "proxy_to_client"),
  // proxy 推送当前 pending 的工具审批列表，client 据此恢复审批卡片
  control("pending_approvals_push", {
    sessionId: IdSchema,
    approvals: z8.array(z8.object({
      requestId: IdSchema,
      toolName: z8.string(),
      input: z8.record(z8.string(), z8.unknown())
    }))
  }, "proxy_to_client"),
  // Voice Pilot speech summaries are produced by proxy-side Claude Code so it can read project context.
  control("voice_summary_request", {
    ...RequestIdShape,
    sessionId: IdSchema,
    messageId: IdSchema,
    text: z8.string().min(1),
    reason: VoiceSummaryReasonSchema
  }, "client_to_proxy"),
  control("voice_summary_response", {
    ...RequestIdShape,
    ...RequestErrorShape,
    sessionId: IdSchema,
    messageId: IdSchema,
    success: z8.boolean(),
    summary: z8.string().min(1).optional()
  }, "proxy_to_client"),
  // 恢复会话时推送历史消息，proxy -> client
  control("session_history_messages", {
    ...RequestIdShape,
    sessionId: IdSchema,
    before: z8.string().optional(),
    messages: z8.array(SessionHistoryMessageSchema),
    hasMore: z8.boolean().optional(),
    nextBefore: z8.string().optional()
  }, "proxy_to_client"),
  // proxy 重连后同步活跃 session 列表给 relay。session_sync 由 relay 自消费（更新 proxy-session
  // 关联）不转发给 client，因此**没有** direction 标注——RelayControlDirection 只描述转发流。
  control("session_sync", {
    sessions: z8.array(z8.object({
      id: z8.string(),
      kind: z8.enum(sessionKindValues).optional(),
      mode: z8.enum(sessionModeValues),
      provider: z8.enum(providerValues),
      ptyOwner: z8.enum(ptyOwnerValues).optional(),
      cwd: z8.string().optional(),
      name: z8.string().optional(),
      nameLocked: z8.boolean().optional(),
      state: z8.enum(sessionStateValues)
    }))
  }),
  // PTY 会话订阅，client -> proxy，触发 terminal serialize() 返回当前状态
  control("session_subscribe", { sessionId: IdSchema, requestId: IdSchema.optional() }, "client_to_proxy"),
  // PTY 会话快照，proxy -> client，serialize() 的全量终端状态
  control("session_snapshot", {
    sessionId: IdSchema,
    cols: z8.number().int().positive(),
    rows: z8.number().int().positive(),
    data: z8.string(),
    outputSeq: z8.number().int().nonnegative(),
    requestId: IdSchema.optional()
  }, "proxy_to_client")
];
var relayControlSchemas = relayControlDefinitions.map((definition) => definition.schema);
var RelayControlSchema = z8.discriminatedUnion("type", relayControlSchemas);
var ProxyToClientRelayControlTypes = new Set(relayControlDefinitions.filter((definition) => definition.directions.has("proxy_to_client")).map((definition) => definition.type));
var ClientToProxyRelayControlTypes = new Set(relayControlDefinitions.filter((definition) => definition.directions.has("client_to_proxy")).map((definition) => definition.type));

// ../../packages/shared/dist/constants/session.js
var SessionState = {
  IDLE: "idle",
  WORKING: "working",
  COMPACTING: "compacting",
  WAITING_APPROVAL: "waiting_approval",
  ERROR: "error",
  TERMINATED: "terminated"
};

// ../../packages/shared/dist/binary-frame.js
var SID_LEN_BYTES = 1;
var SEQ_BYTES = 4;
var HEADER_FIXED_BYTES = SID_LEN_BYTES + SEQ_BYTES;
var FILE_STREAM_MARKER = 0;
var FILE_STREAM_ID_LEN_BYTES = 1;
var FILE_STREAM_HEADER_FIXED_BYTES = 1 + FILE_STREAM_ID_LEN_BYTES + SEQ_BYTES;
function encodeBinaryFrame(sessionId, outputSeq, data) {
  const sidBytes = new TextEncoder().encode(sessionId);
  if (sidBytes.length === 0 || sidBytes.length > 255) {
    throw new RangeError(`sessionId byte length must be 1-255, got ${sidBytes.length} (sessionId=${sessionId})`);
  }
  if (!Number.isInteger(outputSeq) || outputSeq < 0 || outputSeq > 4294967295) {
    throw new RangeError(`outputSeq must be a uint32, got ${outputSeq}`);
  }
  const frame = new Uint8Array(SID_LEN_BYTES + sidBytes.length + SEQ_BYTES + data.length);
  frame[0] = sidBytes.length;
  frame.set(sidBytes, SID_LEN_BYTES);
  const seqOffset = SID_LEN_BYTES + sidBytes.length;
  new DataView(frame.buffer, frame.byteOffset + seqOffset, SEQ_BYTES).setUint32(0, outputSeq, true);
  frame.set(data, seqOffset + SEQ_BYTES);
  return frame;
}
function decodeBinaryFrame(view) {
  if (view.length < SID_LEN_BYTES + SEQ_BYTES)
    return null;
  const sidLen = view[0];
  if (sidLen === 0)
    return null;
  if (view.length < SID_LEN_BYTES + sidLen + SEQ_BYTES)
    return null;
  const sessionId = new TextDecoder().decode(view.subarray(SID_LEN_BYTES, SID_LEN_BYTES + sidLen));
  const seqOffset = SID_LEN_BYTES + sidLen;
  const outputSeq = new DataView(view.buffer, view.byteOffset + seqOffset, SEQ_BYTES).getUint32(0, true);
  const data = view.subarray(seqOffset + SEQ_BYTES);
  return { sessionId, outputSeq, data };
}
function encodeFileStreamFrame(streamId, chunkSeq, data) {
  const streamIdBytes = new TextEncoder().encode(streamId);
  if (streamIdBytes.length === 0 || streamIdBytes.length > 255) {
    throw new RangeError(`streamId byte length must be 1-255, got ${streamIdBytes.length} (streamId=${streamId})`);
  }
  if (!Number.isInteger(chunkSeq) || chunkSeq < 0 || chunkSeq > 4294967295) {
    throw new RangeError(`chunkSeq must be a uint32, got ${chunkSeq}`);
  }
  const frame = new Uint8Array(1 + FILE_STREAM_ID_LEN_BYTES + streamIdBytes.length + SEQ_BYTES + data.length);
  frame[0] = FILE_STREAM_MARKER;
  frame[1] = streamIdBytes.length;
  frame.set(streamIdBytes, 1 + FILE_STREAM_ID_LEN_BYTES);
  const seqOffset = 1 + FILE_STREAM_ID_LEN_BYTES + streamIdBytes.length;
  new DataView(frame.buffer, frame.byteOffset + seqOffset, SEQ_BYTES).setUint32(0, chunkSeq, true);
  frame.set(data, seqOffset + SEQ_BYTES);
  return frame;
}
function decodeFileStreamFrame(view) {
  if (view.length < FILE_STREAM_HEADER_FIXED_BYTES)
    return null;
  if (view[0] !== FILE_STREAM_MARKER)
    return null;
  const streamIdLen = view[1];
  if (streamIdLen === 0)
    return null;
  if (view.length < 1 + FILE_STREAM_ID_LEN_BYTES + streamIdLen + SEQ_BYTES)
    return null;
  const streamId = new TextDecoder().decode(view.subarray(1 + FILE_STREAM_ID_LEN_BYTES, 1 + FILE_STREAM_ID_LEN_BYTES + streamIdLen));
  const seqOffset = 1 + FILE_STREAM_ID_LEN_BYTES + streamIdLen;
  const chunkSeq = new DataView(view.buffer, view.byteOffset + seqOffset, SEQ_BYTES).getUint32(0, true);
  const data = view.subarray(seqOffset + SEQ_BYTES);
  return { streamId, chunkSeq, data };
}

// src/ipc/ipc-protocol.ts
import { z as z9 } from "zod";

// src/ipc/line-buffer.ts
import { Transform } from "stream";
import { StringDecoder } from "string_decoder";
var LineBuffer = class extends Transform {
  buffer = "";
  decoder = new StringDecoder("utf8");
  _transform(chunk, _encoding, callback) {
    this.buffer += typeof chunk === "string" ? chunk : this.decoder.write(chunk);
    const segments = this.buffer.split("\n");
    this.buffer = segments.pop();
    for (const segment of segments) {
      if (segment.length > 0) {
        this.push(segment);
      }
    }
    callback();
  }
  _flush(callback) {
    const tail = this.decoder.end();
    if (tail.length > 0) this.buffer += tail;
    if (this.buffer.length > 0) {
      this.push(this.buffer);
      this.buffer = "";
    }
    callback();
  }
};

// src/ipc/ipc-protocol.ts
var IPC_BINARY_MARKER = 0;
function encodeBinaryIpcFrame(sessionId, data, outputSeq) {
  const inner = encodeBinaryFrame(sessionId, outputSeq, data);
  const frame = Buffer.alloc(1 + 4 + inner.length);
  frame[0] = IPC_BINARY_MARKER;
  frame.writeUInt32LE(inner.length, 1);
  frame.set(inner, 5);
  return frame;
}
var sessionStateValues2 = Object.values(SessionState);
var ProviderHookContextSchema = z9.object({
  provider: z9.enum(["claude", "codex"]),
  sessionId: z9.string(),
  hookUrl: z9.string(),
  marker: z9.string(),
  token: z9.string()
});
var IpcMessageSchema = z9.discriminatedUnion("type", [
  // 客户端请求创建新会话，sessionId 可选用于重连时复用
  z9.object({
    type: z9.literal("session_create_request"),
    name: z9.string().optional(),
    mode: z9.enum(["pty", "json"]),
    provider: z9.enum(["claude", "codex"]),
    cwd: z9.string(),
    pid: z9.number(),
    sessionId: z9.string().optional(),
    kind: z9.enum(["agent", "terminal"]).optional()
  }),
  // 服务端响应创建会话
  z9.object({
    type: z9.literal("session_create_response"),
    sessionId: z9.string(),
    error: z9.string().optional(),
    hook: ProviderHookContextSchema.optional()
  }),
  // 客户端请求终止会话
  z9.object({
    type: z9.literal("session_terminate_request"),
    sessionId: z9.string()
  }),
  // 服务端响应终止会话
  z9.object({
    type: z9.literal("session_terminate_response"),
    sessionId: z9.string(),
    success: z9.boolean()
  }),
  // 客户端向服务端注册 PTY 会话
  z9.object({
    type: z9.literal("pty_register"),
    sessionId: z9.string(),
    pid: z9.number()
  }),
  // 客户端取消注册 PTY 会话
  z9.object({
    type: z9.literal("pty_deregister"),
    sessionId: z9.string()
  }),
  // 输入，从服务端转发到客户端的 PTY stdin（手机远程输入注入）
  z9.object({
    type: z9.literal("pty_input"),
    sessionId: z9.string(),
    data: z9.string(),
    traceId: z9.string().optional()
  }),
  // serve → terminal：Web 端移除本地终端会话时，只断开远程视图，不杀本地 CLI。
  z9.object({
    type: z9.literal("pty_detach"),
    sessionId: z9.string()
  }),
  // serve → terminal worker：终止 Web 创建的纯终端进程。
  z9.object({
    type: z9.literal("pty_terminate"),
    sessionId: z9.string()
  }),
  // 服务端广播会话状态变更
  z9.object({
    type: z9.literal("session_status_update"),
    sessionId: z9.string(),
    state: z9.enum(sessionStateValues2)
  }),
  // 错误响应
  z9.object({
    type: z9.literal("error"),
    message: z9.string(),
    code: z9.string().optional()
  }),
  // 客户端请求服务状态（含 relay 连接信息和 worker 状态）
  z9.object({
    type: z9.literal("service_status_request")
  }),
  // 服务端响应增强版服务状态
  z9.object({
    type: z9.literal("service_status_response"),
    config: z9.object({
      profile: z9.string().optional(),
      relayName: z9.string(),
      relayNameSource: z9.enum(["cli", "profile"]),
      relayUrl: z9.string().optional(),
      relayUrlSource: z9.enum(["env", "file", "none"]),
      relayTokenSource: z9.enum(["env", "file", "none"]),
      hookPort: z9.number(),
      hookPortSource: z9.enum(["env", "file", "default"])
    }),
    relay: z9.object({
      connected: z9.boolean(),
      proxyId: z9.string(),
      reconnectAttempt: z9.number(),
      queueDepth: z9.number()
    }).nullable(),
    sessions: z9.array(
      z9.object({
        id: z9.string(),
        mode: z9.enum(["pty", "json"]),
        state: z9.enum(sessionStateValues2),
        createdAt: z9.string(),
        name: z9.string().optional(),
        hasWorker: z9.boolean()
      })
    )
  }),
  // terminal → serve：终端标题变化，由 xterm onTitleChange 触发
  z9.object({
    type: z9.literal("pty_title_change"),
    sessionId: z9.string(),
    title: z9.string()
  }),
  // terminal → serve：local runtime 观察到的 PTY 语义事件。
  z9.object({
    type: z9.literal("pty_semantic_event"),
    sessionId: z9.string(),
    state: z9.enum(ptySemanticStateValues),
    seq: z9.number().int().nonnegative(),
    title: z9.string().optional(),
    tool: z9.string().optional()
  }),
  // terminal → serve：终端尺寸变化
  z9.object({
    type: z9.literal("pty_resize"),
    sessionId: z9.string(),
    cols: z9.number(),
    rows: z9.number()
  }),
  // serve → terminal worker：Web owns pure terminal geometry, so resize requests flow down.
  z9.object({
    type: z9.literal("pty_resize_request"),
    sessionId: z9.string(),
    cols: z9.number(),
    rows: z9.number()
  }),
  // serve → terminal：请求 HeadlessTerminal serialize() 快照
  z9.object({
    type: z9.literal("pty_subscribe"),
    sessionId: z9.string(),
    requestId: z9.string().optional()
  }),
  // terminal → serve：serialize() 结果
  z9.object({
    type: z9.literal("pty_snapshot"),
    sessionId: z9.string(),
    cols: z9.number(),
    rows: z9.number(),
    data: z9.string(),
    outputSeq: z9.number().int().nonnegative(),
    requestId: z9.string().optional()
  }),
  // serve → terminal：relay 连接状态变更，供终端给用户显示 remote viewing 是否通畅
  z9.object({
    type: z9.literal("bridge_status"),
    connected: z9.boolean()
  })
]);
var WorkerMessageSchema = z9.discriminatedUnion("type", [
  // serve → worker: 发送用户输入给 claude
  z9.object({
    type: z9.literal("worker_input"),
    content: z9.string()
  }),
  // serve → worker: 停止 claude 进程（终止整个 JSON 会话）
  z9.object({
    type: z9.literal("worker_stop")
  }),
  // serve → worker: 只中断当前 Claude turn，worker 进程必须保活并重建 Claude 子进程。
  z9.object({
    type: z9.literal("worker_interrupt")
  }),
  // serve → worker: 工具审批响应
  z9.object({
    type: z9.literal("worker_approval_response"),
    requestId: z9.string(),
    behavior: z9.enum(["allow", "deny"]),
    message: z9.string().optional()
  }),
  // worker → serve: claude 输出事件（带序列号）
  z9.object({
    type: z9.literal("worker_event"),
    seq: z9.number(),
    event: z9.record(z9.string(), z9.unknown())
  }),
  // worker → serve: claude 进程退出
  z9.object({
    type: z9.literal("worker_exit"),
    code: z9.number()
  }),
  // worker → serve: 当前 turn 已中断，JSON 会话仍可继续接收后续输入。
  z9.object({
    type: z9.literal("worker_interrupted")
  }),
  // worker → serve: 工具审批请求
  z9.object({
    type: z9.literal("worker_approval_request"),
    requestId: z9.string(),
    toolName: z9.string(),
    input: z9.record(z9.string(), z9.unknown())
  }),
  // worker → serve: worker 就绪。Claude 在进程启动后发送；Codex 在 app-server
  // initialize + thread/start|resume 完成后发送，避免 session_create 早于 provider ready。
  z9.object({
    type: z9.literal("worker_ready"),
    pid: z9.number()
  }),
  // worker → serve: 从 stream-json 的 system.init 事件捕获 Claude CLI 侧的 session ID
  // proxy 拿它来读 ~/.claude/projects/.../<id>.jsonl 历史或后续 --resume
  z9.object({
    type: z9.literal("worker_claude_session_id"),
    sessionId: z9.string()
  }),
  // worker → serve: provider 原生会话 ID。Codex app-server 用 thread id 作为
  // historySessionId，Claude 仍保留 worker_claude_session_id 的兼容路径。
  z9.object({
    type: z9.literal("worker_native_session_id"),
    provider: z9.enum(["claude", "codex"]),
    sessionId: z9.string()
  }),
  // serve → worker: 将指定工具加入会话白名单，后续同名工具自动审批
  z9.object({
    type: z9.literal("worker_whitelist_add"),
    toolName: z9.string()
  })
]);
function serializeWorkerMsg(msg) {
  return JSON.stringify(msg) + "\n";
}
function createWorkerReader(stream, onMessage, onProtocolError) {
  const lineBuffer = new LineBuffer();
  lineBuffer.on("data", (line) => {
    const str = typeof line === "string" ? line : line.toString();
    if (str.length === 0) return;
    try {
      const raw = JSON.parse(str);
      const result = WorkerMessageSchema.safeParse(raw);
      if (result.success) {
        onMessage(result.data);
      } else {
        onProtocolError?.(
          new Error(`Worker message validation failed: ${result.error.message}`),
          str
        );
      }
    } catch (err) {
      onProtocolError?.(new Error("Worker message parse error", { cause: err }), str);
    }
  });
  stream.pipe(lineBuffer);
}
function serializeIpc(msg) {
  return JSON.stringify(msg) + "\n";
}
function createIpcReader(stream, onMessage, onBinaryFrame, onProtocolError) {
  let buf = Buffer.alloc(0);
  let disposed = false;
  function drain() {
    while (buf.length > 0) {
      if (buf[0] === IPC_BINARY_MARKER) {
        if (buf.length < 5) return;
        const payloadLen = buf.readUInt32LE(1);
        const totalFrameLen = 1 + 4 + payloadLen;
        if (buf.length < totalFrameLen) return;
        const decoded = decodeBinaryFrame(buf.subarray(5, totalFrameLen));
        if (decoded && onBinaryFrame) {
          onBinaryFrame(decoded.sessionId, Buffer.from(decoded.data), decoded.outputSeq);
        }
        buf = buf.subarray(totalFrameLen);
      } else {
        const newlineIdx = buf.indexOf(10);
        if (newlineIdx === -1) return;
        const line = buf.subarray(0, newlineIdx).toString("utf-8");
        buf = buf.subarray(newlineIdx + 1);
        if (line.length === 0) continue;
        try {
          const raw = JSON.parse(line);
          const result = IpcMessageSchema.safeParse(raw);
          if (result.success) {
            onMessage(result.data);
          } else {
            onProtocolError?.(
              new Error(`IPC message validation failed: ${result.error.message}`),
              line
            );
          }
        } catch (err) {
          onProtocolError?.(new Error("IPC message parse error", { cause: err }), line);
        }
      }
    }
  }
  function onData(chunk) {
    if (disposed) return;
    const incoming = typeof chunk === "string" ? Buffer.from(chunk) : chunk;
    buf = Buffer.concat([buf, incoming]);
    drain();
  }
  stream.on("data", onData);
  return () => {
    disposed = true;
    stream.off("data", onData);
  };
}

export {
  providerValues,
  MessageEnvelopeSchema,
  buildMessage,
  serializeControl,
  isCompactCommandText,
  ControlErrorCode,
  RelayControlSchema,
  SessionState,
  encodeBinaryFrame,
  encodeFileStreamFrame,
  decodeFileStreamFrame,
  createFSM,
  defineFSM,
  LineBuffer,
  encodeBinaryIpcFrame,
  serializeWorkerMsg,
  createWorkerReader,
  serializeIpc,
  createIpcReader
};
//# sourceMappingURL=chunk-IHIFDLM4.js.map