#!/usr/bin/env node
import {
  daemonRelayArgs
} from "./chunk-3HJM2NFD.js";
import {
  appendPtySemanticTextTail,
  decidePtySemanticTransition,
  extractOscSequences,
  extractOscSignals,
  extractTextSignals,
  shouldReleaseTextApprovalOnInput
} from "./chunk-W6275ZRJ.js";
import {
  spawnScript
} from "./chunk-IHUQNJF6.js";
import {
  CLAUDE_PROVIDER,
  CODEX_PROVIDER
} from "./chunk-ZRDKF4BU.js";
import {
  createFSM,
  createIpcReader,
  encodeBinaryIpcFrame,
  serializeIpc
} from "./chunk-OU3TG45P.js";
import {
  terminalLogger
} from "./chunk-LWDOXOWY.js";
import {
  PROFILE_NAME,
  SERVICE_LOG_PATH,
  SOCK_PATH,
  STOPPED_PATH,
  tildify
} from "./chunk-7RSBFN2G.js";

// src/terminal.ts
import { setTimeout as sleep2 } from "timers/promises";

// src/terminal/tty.ts
function readTtySize(stream) {
  const { columns, rows } = stream;
  if (columns === void 0 || rows === void 0) {
    throw new Error(
      "stdout is not an interactive TTY (columns/rows undefined); dev-anywhere requires running in a real terminal"
    );
  }
  return { cols: columns, rows };
}
function notifyUser(message) {
  process.stderr.write(`\x1B]9;${message}\x07`);
}
function restoreHostTerminalModes(stream) {
  if (!stream.isTTY) return;
  const restoreSequences = [
    "\x1B[?1l",
    // application cursor keys off
    "\x1B>",
    // application keypad off
    "\x1B[?1000l",
    "\x1B[?1002l",
    "\x1B[?1003l",
    "\x1B[?1004l",
    "\x1B[?1006l",
    "\x1B[?1015l",
    "\x1B[?2004l",
    // bracketed paste off
    "\x1B[>4;0m",
    // xterm modifyOtherKeys off
    "\x1B[<u"
    // kitty keyboard protocol off
  ].join("");
  stream.write(restoreSequences);
}

// src/terminal/pty-manager.ts
import * as pty from "node-pty";
var PtyManager = class {
  child = null;
  resizeTimer = null;
  provider;
  providerArgs;
  cwd;
  hook;
  tap;
  stdin;
  stdout;
  onSessionExit;
  onResize;
  constructor(options) {
    this.provider = options.provider;
    this.providerArgs = options.providerArgs;
    this.cwd = options.cwd;
    this.hook = options.hook;
    this.tap = options.tap;
    this.stdin = options.stdin;
    this.stdout = options.stdout;
    this.onSessionExit = options.onSessionExit;
    this.onResize = options.onResize;
  }
  start() {
    const { cols, rows } = readTtySize(this.stdout);
    const command = this.provider.buildTerminalCommand(
      { args: this.providerArgs, hook: this.hook },
      process.env
    );
    const child = pty.spawn(command.command, command.args, {
      name: process.env.TERM ?? "xterm-256color",
      cols,
      rows,
      cwd: this.cwd,
      env: command.env
    });
    this.child = child;
    const isInteractive = this.stdin.isTTY === true;
    if (isInteractive) {
      this.stdin.setRawMode(true);
    }
    this.stdin.resume();
    this.stdin.on("data", (data) => {
      child.write(data.toString());
    });
    child.onData((data) => this.handleData(data));
    this.stdout.on("resize", () => {
      if (this.resizeTimer) clearTimeout(this.resizeTimer);
      this.resizeTimer = setTimeout(() => {
        this.resizeTimer = null;
        if (!this.child) return;
        const { cols: newCols, rows: newRows } = readTtySize(this.stdout);
        this.child.resize(newCols, newRows);
        this.onResize?.(newCols, newRows);
      }, 50);
    });
    child.onExit(({ exitCode, signal }) => {
      if (isInteractive) this.disableRawModeQuiet();
      restoreHostTerminalModes(this.stdout);
      const code = signal ? 128 + signal : exitCode;
      this.onSessionExit?.(code);
    });
    this.stdin.on("end", () => {
      child.write("");
    });
  }
  /**
   * PTY 数据到达时的统一处理：OSC 9 修复 + 输出到终端 + 传给 tap
   */
  handleData(data) {
    const fixed = data.replace(
      // eslint-disable-next-line no-control-regex
      /\x1b\]9;([\s\S]*?)\x07/g,
      (_, content) => `\x1B]9;${content.replace(/\r\n/g, "\n")}\x07`
    );
    this.stdout.write(fixed);
    this.tap(data);
  }
  // 向 PTY 子进程写入数据，用于远程输入注入
  write(data) {
    this.child?.write(data);
  }
  // 关闭 raw mode 并吞掉 stdin 已关闭场景下的异常。退出 / cleanup 两条路径共用。
  disableRawModeQuiet() {
    try {
      this.stdin.setRawMode(false);
    } catch {
    }
  }
  cleanup(exitCode) {
    if (this.resizeTimer) {
      clearTimeout(this.resizeTimer);
      this.resizeTimer = null;
    }
    if (this.stdin.isTTY) this.disableRawModeQuiet();
    restoreHostTerminalModes(this.stdout);
    if (this.child) {
      try {
        this.child.kill();
      } catch {
      }
      this.child = null;
    }
    this.onSessionExit?.(exitCode);
  }
};

// src/terminal/cwd.ts
import { statSync } from "fs";
function isDirectory(path) {
  if (!path) return false;
  try {
    return statSync(path).isDirectory();
  } catch {
    return false;
  }
}
function resolveTerminalCwd(env = process.env) {
  const candidates = [env.DEV_ANYWHERE_CWD, env.INIT_CWD, env.PWD, process.cwd()];
  return candidates.find(isDirectory) ?? process.cwd();
}

// src/terminal/serve-bootstrap.ts
import { connect } from "net";
import { existsSync, unlinkSync } from "fs";
import { setTimeout as sleep } from "timers/promises";
var ENSURE_SERVICE_MAX_RETRIES = 20;
var ENSURE_SERVICE_INITIAL_DELAY_MS = 100;
var ENSURE_SERVICE_MAX_DELAY_MS = 2e3;
var WAIT_FOR_MESSAGE_TIMEOUT_MS = 1e4;
function tryConnect(sockPath) {
  return new Promise((resolve) => {
    const s = connect(sockPath);
    s.on("connect", () => resolve(s));
    s.on("error", () => resolve(null));
  });
}
async function ensureService(autoStart = true) {
  const existing = await tryConnect(SOCK_PATH);
  if (existing) {
    terminalLogger.info("Connected to existing service");
    return existing;
  }
  if (!autoStart) throw new Error("Service is not running");
  if (existsSync(STOPPED_PATH)) unlinkSync(STOPPED_PATH);
  terminalLogger.info("Auto-starting serve daemon");
  const child = spawnScript("serve", ["--profile", PROFILE_NAME, ...daemonRelayArgs()], {
    env: { ...process.env },
    logger: terminalLogger
  });
  let childFailed = false;
  let exitCode = null;
  let exitSignal = null;
  let spawnError = null;
  child.once("exit", (code, signal) => {
    childFailed = true;
    exitCode = code;
    exitSignal = signal;
  });
  child.once("error", (err) => {
    childFailed = true;
    spawnError = err;
  });
  for (let i = 0; i < ENSURE_SERVICE_MAX_RETRIES; i++) {
    const delay = Math.min(ENSURE_SERVICE_INITIAL_DELAY_MS * (i + 1), ENSURE_SERVICE_MAX_DELAY_MS);
    await sleep(delay);
    if (childFailed) {
      terminalLogger.error(
        { code: exitCode, signal: exitSignal, err: spawnError && String(spawnError) },
        "Serve daemon failed to start"
      );
      const detail = spawnError ? `spawn error=${String(spawnError)}` : `code=${exitCode}, signal=${exitSignal}`;
      throw new Error(
        `Serve daemon failed to start (${detail}). Check ${SERVICE_LOG_PATH} for details.`
      );
    }
    const socket = await tryConnect(SOCK_PATH);
    if (socket) {
      terminalLogger.info({ attempt: i + 1 }, "Connected to service after retry");
      return socket;
    }
  }
  terminalLogger.error({ maxRetries: ENSURE_SERVICE_MAX_RETRIES }, "Failed to connect to service");
  throw new Error(
    `Failed to connect to dev-anywhere service after ${ENSURE_SERVICE_MAX_RETRIES} retries. Check ${SERVICE_LOG_PATH} for details.`
  );
}
function waitForMessage(socket, messageType) {
  return new Promise((resolve, reject) => {
    let timeout = null;
    const dispose = createIpcReader(socket, (msg) => {
      if (msg.type === messageType) {
        if (timeout) clearTimeout(timeout);
        dispose();
        resolve(msg);
      }
    });
    timeout = setTimeout(() => {
      dispose();
      reject(new Error(`Timeout waiting for ${messageType}`));
    }, WAIT_FOR_MESSAGE_TIMEOUT_MS);
  });
}

// src/terminal/idle-checker.ts
function createIdleChecker(options) {
  let timer = null;
  const tick = () => {
    const last = options.getLastOutputTime();
    if (last <= 0) return;
    if (Date.now() - last <= options.thresholdMs) return;
    options.setLastOutputTime(0);
    if (options.getCurrentState() !== "working") return;
    options.onIdle();
  };
  return {
    start() {
      if (timer) clearInterval(timer);
      timer = setInterval(tick, options.intervalMs);
    },
    stop() {
      if (timer) {
        clearInterval(timer);
        timer = null;
      }
    }
  };
}

// src/terminal/serve-socket-swap.ts
function swapServeSocket(prev, next) {
  prev.removeAllListeners();
  return next;
}

// src/terminal.ts
import pkg from "@xterm/headless";
import { SerializeAddon } from "@xterm/addon-serialize";
import { UnicodeGraphemesAddon } from "@xterm/addon-unicode-graphemes";

// src/terminal/state.ts
var TerminalState = {
  INIT: "init",
  CONNECTING_SERVICE: "connecting_service",
  CREATING_SESSION: "creating_session",
  RUNNING: "running",
  RECONNECTING: "reconnecting",
  EXITED: "exited"
};
var TERMINAL_TRANSITIONS = {
  init: ["connecting_service"],
  connecting_service: ["creating_session", "exited"],
  creating_session: ["running", "reconnecting", "exited"],
  running: ["reconnecting", "exited"],
  reconnecting: ["creating_session", "running", "exited"],
  exited: []
};
function createExitHandler(deps) {
  const exit = deps.exit ?? ((code) => process.exit(code));
  return (code) => {
    if (deps.fsm.is(TerminalState.EXITED)) return;
    deps.fsm.transitionTo(TerminalState.EXITED);
    deps.stopIdleChecker();
    deps.disposeRenderResources?.();
    const socket = deps.getSocket();
    const sessionId = deps.getSessionId();
    if (socket.writable && sessionId) {
      socket.end(serializeIpc({ type: "pty_deregister", sessionId }), () => exit(code));
    } else {
      exit(code);
    }
  };
}

// src/terminal.ts
import { existsSync as existsSync2 } from "fs";
var { Terminal: HeadlessTerminal } = pkg;
var IDLE_CHECK_INTERVAL_MS = 3e3;
var IDLE_THRESHOLD_MS = 3e3;
var RECONNECT_INITIAL_DELAY_MS = 1e3;
var RECONNECT_MAX_DELAY_MS = 5e3;
var SPAWN_FAILURE_THRESHOLD = 3;
var PROVIDERS = {
  claude: CLAUDE_PROVIDER,
  codex: CODEX_PROVIDER
};
var TerminalSession = class {
  constructor(provider, providerArgs) {
    this.provider = provider;
    this.providerArgs = providerArgs;
  }
  provider;
  providerArgs;
  fsm = createFSM({
    initial: TerminalState.INIT,
    transitions: TERMINAL_TRANSITIONS,
    onTransition: (from, to) => terminalLogger.info({ from, to }, "Terminal state transition")
  });
  sessionCwd = resolveTerminalCwd();
  // socket 在 run() 中连上 serve 后首次赋值；reconnect 会重新赋值为新实例
  socket;
  sessionId = null;
  hookContext = null;
  ptyManager = null;
  lastOutputTime = 0;
  idleChecker = null;
  currentPtyState = "turn_complete";
  semanticTextTail = "";
  textApprovalWaitActive = false;
  // headless terminal 在本进程维护，用于按需 serialize() 给远程 client
  headlessTerminal = null;
  serializeAddon = null;
  outputSeq = 0;
  remoteDetached = false;
  // 记录上次 bridge 连接状态，避免重连抖动重复打印 banner；
  // 初值 null 确保首次状态变更（无论 true/false）都触发一次输出
  lastBridgeConnected = null;
  // 收尾函数在 run() 里创建一次，PTY 退出与 SIGTERM 共用；内部通过 fsm EXITED 检查短路
  cleanupAndExit;
  async run() {
    terminalLogger.info("Terminal starting");
    this.fsm.transitionTo(TerminalState.CONNECTING_SERVICE);
    this.socket = await ensureService();
    await this.createSession();
    this.initHeadlessTerminal();
    this.cleanupAndExit = createExitHandler({
      fsm: this.fsm,
      getSocket: () => this.socket,
      getSessionId: () => this.sessionId,
      stopIdleChecker: () => this.idleChecker?.stop(),
      disposeRenderResources: () => {
        this.headlessTerminal?.dispose();
        this.headlessTerminal = null;
        this.serializeAddon = null;
      }
    });
    this.setupSocketHandlers();
    this.startPtyManager();
    this.socket.write(
      serializeIpc({ type: "pty_register", sessionId: this.sessionId, pid: process.pid })
    );
    this.replayCurrentPtyState();
    this.fsm.transitionTo(TerminalState.RUNNING);
    this.setupIdleCheck();
    process.on("SIGTERM", () => {
      terminalLogger.info({ sessionId: this.sessionId }, "SIGTERM received, shutting down");
      this.cleanupAndExit(143);
    });
  }
  async createSession() {
    this.fsm.transitionTo(TerminalState.CREATING_SESSION);
    const responsePromise = waitForMessage(this.socket, "session_create_response");
    this.socket.write(
      serializeIpc({
        type: "session_create_request",
        mode: "pty",
        provider: this.provider.id,
        cwd: this.sessionCwd,
        name: tildify(this.sessionCwd),
        pid: process.pid
      })
    );
    const response = await responsePromise;
    if (response.error) {
      throw new Error(`Failed to create session: ${response.error}`);
    }
    this.sessionId = response.sessionId;
    this.hookContext = response.hook ?? null;
  }
  initHeadlessTerminal() {
    const { cols, rows } = readTtySize(process.stdout);
    terminalLogger.info(
      { sessionId: this.sessionId, cols, rows },
      "Session created, initializing headless terminal"
    );
    this.headlessTerminal = new HeadlessTerminal({
      cols,
      rows,
      scrollback: 5e3,
      allowProposedApi: true
    });
    this.serializeAddon = new SerializeAddon();
    this.headlessTerminal.loadAddon(this.serializeAddon);
    this.headlessTerminal.loadAddon(new UnicodeGraphemesAddon());
  }
  startPtyManager() {
    this.ptyManager = new PtyManager({
      provider: this.provider,
      providerArgs: this.providerArgs,
      cwd: this.sessionCwd,
      hook: this.hookContext ?? void 0,
      tap: (data) => this.handlePtyData(data),
      stdin: process.stdin,
      stdout: process.stdout,
      onResize: (newCols, newRows) => {
        if (this.headlessTerminal) this.headlessTerminal.resize(newCols, newRows);
        if (this.socket.writable && this.sessionId) {
          this.socket.write(
            serializeIpc({
              type: "pty_resize",
              sessionId: this.sessionId,
              cols: newCols,
              rows: newRows
            })
          );
        }
      },
      onSessionExit: (code) => {
        terminalLogger.info({ sessionId: this.sessionId, exitCode: code }, "PTY exited, cleaning up");
        this.cleanupAndExit(code);
      }
    });
    this.ptyManager.start();
    terminalLogger.info({ sessionId: this.sessionId }, "PTY started with headless terminal");
  }
  // PTY 的每一帧输出都要：追到 headless terminal 状态、推 binary IPC、提取 provider 语义事件
  handlePtyData(data) {
    this.lastOutputTime = Date.now();
    this.outputSeq += 1;
    if (this.headlessTerminal) this.headlessTerminal.write(data);
    if (!this.remoteDetached && this.socket.writable && this.sessionId) {
      this.socket.write(
        encodeBinaryIpcFrame(this.sessionId, Buffer.from(data, "utf-8"), this.outputSeq)
      );
    }
    const oscSequences = extractOscSequences(data);
    const oscSignal = extractOscSignals(data, this.provider.id);
    this.semanticTextTail = appendPtySemanticTextTail(this.semanticTextTail, data);
    const textSignal = oscSignal ? null : extractTextSignals(this.semanticTextTail, this.provider.id);
    const signal = oscSignal ?? textSignal;
    if (textSignal?.state === "approval_wait") {
      this.textApprovalWaitActive = true;
      this.semanticTextTail = "";
    }
    if (oscSequences.length > 0) {
      terminalLogger.debug(
        {
          sessionId: this.sessionId,
          oscSequences,
          signal
        },
        "PTY OSC sequences parsed"
      );
    }
    if (signal?.title) {
      this.sendTerminalTitle(signal.title);
    }
    const decision = decidePtySemanticTransition({
      currentState: this.currentPtyState,
      signal: signal ?? null,
      allowTitleOnlyApprovalRelease: !this.textApprovalWaitActive
    });
    this.currentPtyState = decision.nextState;
    if (decision.nextState !== "approval_wait") {
      this.textApprovalWaitActive = false;
    }
    if (decision.emit) {
      this.sendPtyState(decision.nextState, decision.meta);
    }
  }
  sendTerminalTitle(title) {
    if (this.remoteDetached || !this.socket.writable || !this.sessionId) return;
    this.socket.write(
      serializeIpc({
        type: "pty_title_change",
        sessionId: this.sessionId,
        title
      })
    );
  }
  sendPtyState(state, meta) {
    if (this.remoteDetached || !this.socket.writable || !this.sessionId) return;
    this.socket.write(
      serializeIpc({
        type: "pty_semantic_event",
        sessionId: this.sessionId,
        state,
        ...meta?.title !== void 0 ? { title: meta.title } : {},
        ...meta?.tool !== void 0 ? { tool: meta.tool } : {}
      })
    );
    terminalLogger.info(
      { sessionId: this.sessionId, state, title: meta?.title, tool: meta?.tool },
      "PTY semantic event pushed"
    );
  }
  releaseTextApprovalOnInput(data) {
    if (!this.textApprovalWaitActive || this.currentPtyState !== "approval_wait") return;
    if (!shouldReleaseTextApprovalOnInput(data)) return;
    this.textApprovalWaitActive = false;
    this.currentPtyState = "working";
    this.sendPtyState("working");
  }
  replayCurrentPtyState() {
    if (this.currentPtyState === "turn_complete") return;
    this.sendPtyState(this.currentPtyState);
  }
  handleBridgeStatus(connected) {
    if (this.remoteDetached) return;
    if (this.lastBridgeConnected === connected) return;
    this.lastBridgeConnected = connected;
    terminalLogger.info({ connected }, "Bridge status changed, notifying user");
    notifyUser(connected ? "relay online" : "relay offline \u2014 remote viewing unavailable");
  }
  setupSocketHandlers() {
    createIpcReader(
      this.socket,
      (msg) => {
        if (msg.type === "pty_input" && msg.sessionId === this.sessionId) {
          terminalLogger.debug(
            { sessionId: this.sessionId, traceId: msg.traceId, bytes: msg.data.length },
            "Remote input received"
          );
          this.releaseTextApprovalOnInput(msg.data);
          this.ptyManager?.write(msg.data);
        } else if (msg.type === "pty_detach" && msg.sessionId === this.sessionId) {
          this.detachRemoteView();
        } else if (msg.type === "bridge_status") {
          this.handleBridgeStatus(msg.connected);
        } else if (msg.type === "pty_subscribe" && msg.sessionId === this.sessionId) {
          if (this.serializeAddon && this.headlessTerminal) {
            const data = this.serializeAddon.serialize();
            this.socket.write(
              serializeIpc({
                type: "pty_snapshot",
                sessionId: msg.sessionId,
                cols: this.headlessTerminal.cols,
                rows: this.headlessTerminal.rows,
                data,
                outputSeq: this.outputSeq,
                requestId: msg.requestId
              })
            );
            terminalLogger.info(
              {
                sessionId: this.sessionId,
                cols: this.headlessTerminal.cols,
                rows: this.headlessTerminal.rows,
                bytes: data.length
              },
              "Snapshot sent via IPC"
            );
          }
        }
      },
      void 0,
      (err, line) => {
        terminalLogger.warn(
          { err: err.message, lineLen: line.length },
          "Serve IPC message dropped (parse/schema error)"
        );
      }
    );
    this.socket.on("close", () => {
      terminalLogger.info("Serve socket closed");
      if (this.remoteDetached) {
        terminalLogger.info("Remote view detached, skipping serve reconnect");
        return;
      }
      if (!this.fsm.isIn([TerminalState.RECONNECTING, TerminalState.EXITED])) {
        this.fsm.transitionTo(TerminalState.RECONNECTING);
        this.reconnectToServe();
      }
    });
    this.socket.on("error", (err) => {
      terminalLogger.warn({ err: err.message }, "Serve socket error");
    });
  }
  // 超过 IDLE_THRESHOLD_MS 无 PTY 输出则从 working 翻回 turn_complete
  setupIdleCheck() {
    this.idleChecker?.stop();
    this.idleChecker = createIdleChecker({
      intervalMs: IDLE_CHECK_INTERVAL_MS,
      thresholdMs: IDLE_THRESHOLD_MS,
      getLastOutputTime: () => this.lastOutputTime,
      setLastOutputTime: (value) => {
        this.lastOutputTime = value;
      },
      getCurrentState: () => this.currentPtyState,
      onIdle: () => {
        this.currentPtyState = "turn_complete";
        this.sendPtyState("turn_complete");
      }
    });
    this.idleChecker.start();
  }
  async reconnectToServe() {
    terminalLogger.info("Serve connection lost, starting reconnection");
    let consecutiveSpawnFailures = 0;
    for (let i = 0; ; i++) {
      if (this.remoteDetached) return;
      await sleep2(Math.min(RECONNECT_INITIAL_DELAY_MS * (i + 1), RECONNECT_MAX_DELAY_MS));
      const stopped = existsSync2(STOPPED_PATH);
      const degraded = consecutiveSpawnFailures >= SPAWN_FAILURE_THRESHOLD;
      const passive = stopped || degraded;
      try {
        terminalLogger.debug({ attempt: i + 1, stopped, degraded }, "Reconnect attempt");
        const newSocket = passive ? await tryConnect(SOCK_PATH) : await ensureService();
        if (!newSocket) continue;
        if (degraded) notifyUser("serve daemon reachable, reconnected");
        consecutiveSpawnFailures = 0;
        this.socket = swapServeSocket(this.socket, newSocket);
        terminalLogger.info({ attempt: i + 1, sessionId: this.sessionId }, "Reconnected to serve");
        this.setupSocketHandlers();
        if (this.sessionId) {
          this.fsm.transitionTo(TerminalState.CREATING_SESSION);
          this.socket.write(
            serializeIpc({
              type: "session_create_request",
              mode: "pty",
              provider: this.provider.id,
              cwd: this.sessionCwd,
              name: tildify(this.sessionCwd),
              pid: process.pid,
              sessionId: this.sessionId
            })
          );
          const resp = await waitForMessage(this.socket, "session_create_response");
          if (!resp.error) {
            this.sessionId = resp.sessionId;
            this.socket.write(
              serializeIpc({ type: "pty_register", sessionId: this.sessionId, pid: process.pid })
            );
            this.replayCurrentPtyState();
            this.fsm.transitionTo(TerminalState.RUNNING);
            terminalLogger.info({ sessionId: this.sessionId }, "Session re-registered after reconnect");
          }
        } else {
          this.fsm.transitionTo(TerminalState.RUNNING);
        }
        return;
      } catch (err) {
        if (!passive) {
          consecutiveSpawnFailures++;
          if (consecutiveSpawnFailures === SPAWN_FAILURE_THRESHOLD) {
            notifyUser(
              `serve daemon spawn failed ${SPAWN_FAILURE_THRESHOLD}x \u2014 auto-spawn disabled; check environment or run 'dev-anywhere start'`
            );
          }
        }
        terminalLogger.debug(
          { err: err instanceof Error ? err.message : err, attempt: i + 1, degraded },
          "Reconnect attempt failed"
        );
      }
    }
  }
  detachRemoteView() {
    const sessionId = this.sessionId;
    if (!sessionId) return;
    this.remoteDetached = true;
    this.sessionId = null;
    this.hookContext = null;
    this.currentPtyState = "turn_complete";
    terminalLogger.info({ sessionId }, "Remote view detached; local PTY keeps running");
    notifyUser("remote viewing detached");
    if (this.socket.writable) this.socket.end();
  }
};
function providerFromEnv() {
  return process.env.DEV_ANYWHERE_PROVIDER === "codex" ? "codex" : "claude";
}
async function startTerminal(providerArgs, providerId = providerFromEnv()) {
  await new TerminalSession(PROVIDERS[providerId], providerArgs).run();
}
export {
  startTerminal
};
//# sourceMappingURL=terminal-DIIMRERW.js.map