// Force strict mode and setup for ESM
"use strict";
import {
  runNonInteractive
} from "./chunk-BEURET6G.js";
import "./chunk-J4TMCUCZ.js";
import "./chunk-YTI63CQW.js";
import {
  StreamJsonOutputAdapter
} from "./chunk-37K24W4Y.js";
import {
  getAvailableCommands
} from "./chunk-H2S47HYW.js";
import "./chunk-A5AG664O.js";
import "./chunk-XL5WDTO5.js";
import "./chunk-6OOS3TNP.js";
import "./chunk-RMXPR6HS.js";
import "./chunk-KSPVDFE4.js";
import "./chunk-MRO43B25.js";
import "./chunk-VXGPYF7U.js";
import "./chunk-4FRUXVSE.js";
import "./chunk-KYMBIKIW.js";
import "./chunk-HTWHAN44.js";
import "./chunk-JZSY4WP3.js";
import "./chunk-ZHGT5WWW.js";
import "./chunk-3GONHQOA.js";
import "./chunk-V655JORE.js";
import "./chunk-ZI4MGBB5.js";
import "./chunk-L7QPM2YD.js";
import "./chunk-54YZOP7P.js";
import "./chunk-UVNBI7NN.js";
import "./chunk-PFS2I5LF.js";
import "./chunk-KHDZHZMH.js";
import "./chunk-A76FGLIX.js";
import "./chunk-YQARVN3E.js";
import "./chunk-NIOPRZNN.js";
import "./chunk-AHNXYU4O.js";
import "./chunk-RNBYOUGV.js";
import "./chunk-Q5JX2J3K.js";
import "./chunk-BJBWRCSK.js";
import "./chunk-QFVH4WQN.js";
import "./chunk-6BEOH4KK.js";
import "./chunk-S6RLAIUR.js";
import "./chunk-MX2YXRER.js";
import "./chunk-YHTNWGRR.js";
import {
  createMinimalSettings
} from "./chunk-AFPB2TZB.js";
import "./chunk-RYT2ET4O.js";
import "./chunk-TLRYABYP.js";
import "./chunk-4RQIB5UZ.js";
import "./chunk-SEZC2725.js";
import "./chunk-ALX6BUYW.js";
import "./chunk-VRDMOSQS.js";
import "./chunk-3RW4AZJV.js";
import "./chunk-SL2P3JUA.js";
import "./chunk-CJSSVQAR.js";
import "./chunk-Y6Z2O3WR.js";
import "./chunk-QYUE6W3T.js";
import {
  MCPServerConfig,
  TURN_INTERRUPTION_HISTORY_TAIL_COUNT,
  detectTurnInterruption
} from "./chunk-IQ7FOOIH.js";
import "./chunk-5P5XGNYH.js";
import "./chunk-SKAZWEV5.js";
import "./chunk-K5PGHDBN.js";
import "./chunk-CLQPBI4H.js";
import "./chunk-QOMAHFYI.js";
import "./chunk-G7OQ3RFJ.js";
import "./chunk-LKWAVAB5.js";
import "./chunk-5ES5YPED.js";
import "./chunk-2MPVVENX.js";
import "./chunk-ZTQ26VBE.js";
import "./chunk-DMSNJDWG.js";
import "./chunk-MLZQVCF3.js";
import "./chunk-LQ7TMOCE.js";
import "./chunk-E5A7LHNN.js";
import "./chunk-LM3YCCZJ.js";
import "./chunk-GO6LNQXT.js";
import "./chunk-B236XPGF.js";
import "./chunk-NVFJSIAX.js";
import "./chunk-TOAUDIS7.js";
import "./chunk-NPQWQYU6.js";
import "./chunk-4IUH45NF.js";
import "./chunk-E6US47KI.js";
import "./chunk-UWCTAVOD.js";
import "./chunk-OFEVLU4C.js";
import "./chunk-OMX7CUOE.js";
import "./chunk-MOUXUCXQ.js";
import "./chunk-BZHLWC6T.js";
import "./chunk-RZORUN6X.js";
import "./chunk-MJKMIQMK.js";
import "./chunk-TENOUWY2.js";
import "./chunk-GLPV75ES.js";
import "./chunk-22IFUCVR.js";
import "./chunk-T42ACHFI.js";
import "./chunk-SIUQ3YYX.js";
import "./chunk-KYTQOCDE.js";
import "./chunk-YPCPZSZB.js";
import "./chunk-IRJWHZWU.js";
import "./chunk-SYCJMSIJ.js";
import "./chunk-55ZMG67I.js";
import "./chunk-H6BD2ELD.js";
import "./chunk-5IFG2VC4.js";
import "./chunk-64WXLC72.js";
import "./chunk-D5KISTLW.js";
import {
  createDebugLogger
} from "./chunk-AVQDCKNF.js";
import "./chunk-DTPH7UZK.js";
import "./chunk-N2OMTT2Q.js";
import {
  finalizeStartupProfile,
  profileCheckpoint
} from "./chunk-ITOGNELQ.js";
import "./chunk-FXGLL2HL.js";
import "./chunk-ZERZSAZL.js";
import "./chunk-QN5NZ3UQ.js";
import "./chunk-BR4QREVK.js";
import "./chunk-Z2Z3GUXZ.js";
import {
  init_esbuild_shims
} from "./chunk-A4BMJM77.js";
import {
  __name
} from "./chunk-J2S4EL5Y.js";

// packages/cli/src/nonInteractive/session.ts
init_esbuild_shims();

// packages/cli/src/nonInteractive/io/StreamJsonInputReader.ts
init_esbuild_shims();
import { createInterface } from "node:readline/promises";
import process2 from "node:process";
var StreamJsonParseError = class extends Error {
  static {
    __name(this, "StreamJsonParseError");
  }
};
var StreamJsonInputReader = class {
  static {
    __name(this, "StreamJsonInputReader");
  }
  input;
  constructor(input = process2.stdin) {
    this.input = input;
  }
  async *read() {
    const rl = createInterface({
      input: this.input,
      crlfDelay: Number.POSITIVE_INFINITY,
      terminal: false
    });
    try {
      for await (const rawLine of rl) {
        const line = rawLine.trim();
        if (!line) {
          continue;
        }
        yield this.parse(line);
      }
    } finally {
      rl.close();
    }
  }
  parse(line) {
    try {
      const parsed = JSON.parse(line);
      if (!parsed || typeof parsed !== "object") {
        throw new StreamJsonParseError("Parsed value is not an object");
      }
      if (!("type" in parsed) || typeof parsed.type !== "string") {
        throw new StreamJsonParseError('Missing required "type" field');
      }
      return parsed;
    } catch (error) {
      if (error instanceof StreamJsonParseError) {
        throw error;
      }
      const reason = error instanceof Error ? error.message : String(error);
      throw new StreamJsonParseError(
        `Failed to parse stream-json line: ${reason}`
      );
    }
  }
};

// packages/cli/src/nonInteractive/control/ControlContext.ts
init_esbuild_shims();
var ControlContext = class {
  static {
    __name(this, "ControlContext");
  }
  config;
  streamJson;
  sessionId;
  abortSignal;
  debugMode;
  settings;
  permissionMode;
  sdkCanUseToolTimeoutMs;
  sdkMcpServers;
  mcpClients;
  inputClosed;
  onInterrupt;
  onContinueLastTurn;
  constructor(options) {
    this.config = options.config;
    this.streamJson = options.streamJson;
    this.sessionId = options.sessionId;
    this.abortSignal = options.abortSignal;
    this.debugMode = options.config.getDebugMode();
    this.settings = options.settings;
    this.permissionMode = options.permissionMode || "default";
    this.sdkMcpServers = /* @__PURE__ */ new Set();
    this.mcpClients = /* @__PURE__ */ new Map();
    this.inputClosed = false;
    this.onInterrupt = options.onInterrupt;
    this.onContinueLastTurn = options.onContinueLastTurn;
  }
};

// packages/cli/src/nonInteractive/control/ControlDispatcher.ts
init_esbuild_shims();

// packages/cli/src/nonInteractive/control/controllers/systemController.ts
init_esbuild_shims();

// packages/cli/src/nonInteractive/control/controllers/baseController.ts
init_esbuild_shims();
import { randomUUID } from "node:crypto";
var DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
var BaseController = class {
  static {
    __name(this, "BaseController");
  }
  context;
  registry;
  controllerName;
  debugLogger;
  constructor(context, registry, controllerName) {
    this.context = context;
    this.registry = registry;
    this.controllerName = controllerName;
    this.debugLogger = createDebugLogger();
  }
  /**
   * Handle an incoming control request
   *
   * Manages lifecycle: register -> process -> deregister
   */
  async handleRequest(payload, requestId) {
    const requestAbortController = new AbortController();
    const timeoutId = setTimeout(() => {
      requestAbortController.abort();
      this.registry.deregisterIncomingRequest(requestId);
      this.debugLogger.warn(
        `[${this.controllerName}] Request timeout: ${requestId}`
      );
    }, DEFAULT_REQUEST_TIMEOUT_MS);
    this.registry.registerIncomingRequest(
      requestId,
      this.controllerName,
      requestAbortController,
      timeoutId
    );
    try {
      const response = await this.handleRequestPayload(
        payload,
        requestAbortController.signal
      );
      this.registry.deregisterIncomingRequest(requestId);
      return response;
    } catch (error) {
      this.registry.deregisterIncomingRequest(requestId);
      throw error;
    }
  }
  /**
   * Send an outgoing control request to SDK
   *
   * Manages lifecycle: register -> send -> wait for response -> deregister
   * Respects the provided AbortSignal for cancellation.
   */
  async sendControlRequest(payload, timeoutMs = DEFAULT_REQUEST_TIMEOUT_MS, signal) {
    if (this.context.inputClosed) {
      throw new Error("Input closed");
    }
    if (signal?.aborted) {
      throw new Error("Request aborted");
    }
    const requestId = randomUUID();
    return new Promise((resolve, reject) => {
      const abortHandler = /* @__PURE__ */ __name(() => {
        this.registry.deregisterOutgoingRequest(requestId);
        reject(new Error("Request aborted"));
        this.debugLogger.warn(
          `[${this.controllerName}] Outgoing request aborted: ${requestId}`
        );
      }, "abortHandler");
      if (signal) {
        signal.addEventListener("abort", abortHandler, { once: true });
      }
      const timeoutId = setTimeout(() => {
        if (signal) {
          signal.removeEventListener("abort", abortHandler);
        }
        this.registry.deregisterOutgoingRequest(requestId);
        reject(new Error("Control request timeout"));
        this.debugLogger.warn(
          `[${this.controllerName}] Outgoing request timeout: ${requestId}`
        );
      }, timeoutMs);
      const wrappedResolve = /* @__PURE__ */ __name((response) => {
        if (signal) {
          signal.removeEventListener("abort", abortHandler);
        }
        resolve(response);
      }, "wrappedResolve");
      const wrappedReject = /* @__PURE__ */ __name((error) => {
        if (signal) {
          signal.removeEventListener("abort", abortHandler);
        }
        reject(error);
      }, "wrappedReject");
      this.registry.registerOutgoingRequest(
        requestId,
        this.controllerName,
        wrappedResolve,
        wrappedReject,
        timeoutId
      );
      const request = {
        type: "control_request",
        request_id: requestId,
        request: payload
      };
      try {
        this.context.streamJson.send(request);
      } catch (error) {
        if (signal) {
          signal.removeEventListener("abort", abortHandler);
        }
        this.registry.deregisterOutgoingRequest(requestId);
        reject(error);
      }
    });
  }
  /**
   * Cleanup resources
   */
  cleanup() {
  }
};

// packages/cli/src/nonInteractive/control/controllers/systemController.ts
var debugLogger = createDebugLogger("SYSTEM_CONTROLLER");
var MAX_CAN_USE_TOOL_TIMEOUT_MS = 6e5;
var SystemController = class extends BaseController {
  static {
    __name(this, "SystemController");
  }
  /**
   * Handle system control requests
   */
  async handleRequestPayload(payload, signal) {
    if (signal.aborted) {
      throw new Error("Request aborted");
    }
    switch (payload.subtype) {
      case "initialize":
        return this.handleInitialize(
          payload,
          signal
        );
      case "interrupt":
        return this.handleInterrupt();
      case "continue_last_turn":
        return this.handleContinueLastTurn();
      case "set_model":
        return this.handleSetModel(
          payload,
          signal
        );
      case "supported_commands":
        return this.handleSupportedCommands(signal);
      case "get_context_usage":
        return this.handleGetContextUsage(
          payload,
          signal
        );
      default:
        throw new Error(`Unsupported request subtype in SystemController`);
    }
  }
  async handleGetContextUsage(payload, signal) {
    if (signal.aborted) {
      throw new Error("Request aborted");
    }
    try {
      const mod = await import("./contextCommand-GRGWDNOY.js");
      if (signal.aborted) {
        throw new Error("Request aborted");
      }
      if (typeof mod.collectContextData !== "function") {
        throw new Error("collectContextData is not available");
      }
      const showDetails = payload.show_details ?? false;
      const contextUsageItem = await mod.collectContextData(
        this.context.config,
        showDetails
      );
      if (signal.aborted) {
        throw new Error("Request aborted");
      }
      const { type: _type, ...contextData } = contextUsageItem;
      return {
        subtype: "get_context_usage",
        ...contextData
      };
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : "Failed to get context usage";
      debugLogger.error(
        "[SystemController] Failed to get context usage:",
        error
      );
      throw new Error(errorMessage);
    }
  }
  /**
   * Handle initialize request
   *
   * Processes SDK MCP servers config.
   * SDK servers are registered in context.sdkMcpServers
   * and added to config.mcpServers with the sdk type flag.
   * External MCP servers are configured separately in settings.
   */
  async handleInitialize(payload, signal) {
    if (signal.aborted) {
      throw new Error("Request aborted");
    }
    this.context.config.setSdkMode(true);
    const canUseToolTimeout = payload.timeout?.canUseTool;
    if (typeof canUseToolTimeout === "number" && Number.isFinite(canUseToolTimeout) && canUseToolTimeout > 0 && canUseToolTimeout <= MAX_CAN_USE_TOOL_TIMEOUT_MS) {
      this.context.sdkCanUseToolTimeoutMs = canUseToolTimeout;
    }
    if (payload.sdkMcpServers && typeof payload.sdkMcpServers === "object" && payload.sdkMcpServers !== null) {
      const sdkServers = {};
      for (const [key, wireConfig] of Object.entries(payload.sdkMcpServers)) {
        const name = typeof wireConfig?.name === "string" && wireConfig.name.trim().length ? wireConfig.name : key;
        this.context.sdkMcpServers.add(name);
        sdkServers[name] = new MCPServerConfig(
          void 0,
          // command
          void 0,
          // args
          void 0,
          // env
          void 0,
          // cwd
          void 0,
          // url
          void 0,
          // httpUrl
          void 0,
          // headers
          void 0,
          // tcp
          void 0,
          // timeout
          true,
          // trust - SDK servers are trusted
          void 0,
          // description
          void 0,
          // includeTools
          void 0,
          // excludeTools
          void 0,
          // extensionName
          void 0,
          // oauth
          void 0,
          // authProviderType
          void 0,
          // targetAudience
          void 0,
          // targetServiceAccount
          "sdk"
          // type
        );
      }
      const sdkServerCount = Object.keys(sdkServers).length;
      if (sdkServerCount > 0) {
        try {
          this.context.config.addMcpServers(sdkServers);
          debugLogger.debug(
            `[SystemController] Added ${sdkServerCount} SDK MCP servers to config`
          );
        } catch (error) {
          debugLogger.error(
            "[SystemController] Failed to add SDK MCP servers:",
            error
          );
        }
      }
    }
    if (payload.mcpServers && typeof payload.mcpServers === "object" && payload.mcpServers !== null) {
      const externalServers = {};
      for (const [name, serverConfig] of Object.entries(payload.mcpServers)) {
        const normalized = this.normalizeMcpServerConfig(
          name,
          serverConfig
        );
        if (normalized) {
          externalServers[name] = normalized;
        }
      }
      const externalCount = Object.keys(externalServers).length;
      if (externalCount > 0) {
        try {
          this.context.config.addMcpServers(externalServers);
          debugLogger.debug(
            `[SystemController] Added ${externalCount} external MCP servers to config`
          );
        } catch (error) {
          debugLogger.error(
            "[SystemController] Failed to add external MCP servers:",
            error
          );
        }
      }
    }
    if (payload.agents && Array.isArray(payload.agents)) {
      try {
        this.context.config.setSessionSubagents(payload.agents);
        debugLogger.debug(
          `[SystemController] Added ${payload.agents.length} session subagents to config`
        );
      } catch (error) {
        debugLogger.error(
          "[SystemController] Failed to add session subagents:",
          error
        );
      }
    }
    const capabilities = this.buildControlCapabilities();
    debugLogger.debug(
      `[SystemController] Initialized with ${this.context.sdkMcpServers.size} SDK MCP servers`
    );
    return {
      subtype: "initialize",
      session_id: this.context.config.getSessionId(),
      capabilities
    };
  }
  /**
   * Build control capabilities for initialize control response
   *
   * This method constructs the control capabilities object that indicates
   * what control features are available. It is used exclusively in the
   * initialize control response.
   */
  buildControlCapabilities() {
    const capabilities = {
      can_handle_can_use_tool: true,
      can_handle_hook_callback: false,
      can_set_permission_mode: typeof this.context.config.setApprovalMode === "function",
      can_set_model: typeof this.context.config.setModel === "function",
      can_get_context_usage: true,
      // SDK MCP servers are supported - messages routed through control plane
      can_handle_mcp_message: true
    };
    return capabilities;
  }
  normalizeMcpServerConfig(serverName, config) {
    if (!config || typeof config !== "object") {
      debugLogger.warn(
        `[SystemController] Ignoring invalid MCP server config for '${serverName}'`
      );
      return null;
    }
    const authProvider = this.normalizeAuthProviderType(
      config.authProviderType
    );
    const oauthConfig = this.normalizeOAuthConfig(config.oauth);
    return new MCPServerConfig(
      config.command,
      config.args,
      config.env,
      config.cwd,
      config.url,
      config.httpUrl,
      config.headers,
      config.tcp,
      config.timeout,
      config.trust,
      config.description,
      config.includeTools,
      config.excludeTools,
      config.extensionName,
      oauthConfig,
      authProvider,
      config.targetAudience,
      config.targetServiceAccount
    );
  }
  normalizeAuthProviderType(value) {
    if (!value) {
      return void 0;
    }
    switch (value) {
      case "dynamic_discovery" /* DYNAMIC_DISCOVERY */:
      case "google_credentials" /* GOOGLE_CREDENTIALS */:
      case "service_account_impersonation" /* SERVICE_ACCOUNT_IMPERSONATION */:
        return value;
      default:
        debugLogger.warn(
          `[SystemController] Unsupported authProviderType '${value}', skipping`
        );
        return void 0;
    }
  }
  normalizeOAuthConfig(oauth) {
    if (!oauth) {
      return void 0;
    }
    return {
      enabled: oauth.enabled,
      clientId: oauth.clientId,
      clientSecret: oauth.clientSecret,
      authorizationUrl: oauth.authorizationUrl,
      tokenUrl: oauth.tokenUrl,
      scopes: oauth.scopes,
      audiences: oauth.audiences,
      redirectUri: oauth.redirectUri,
      tokenParamName: oauth.tokenParamName,
      registrationUrl: oauth.registrationUrl
    };
  }
  /**
   * Handle interrupt request
   *
   * Triggers the interrupt callback to cancel current operations
   */
  async handleInterrupt() {
    if (this.context.onInterrupt) {
      this.context.onInterrupt();
    }
    if (this.context.abortSignal && !this.context.abortSignal.aborted) {
      debugLogger.debug("[SystemController] Interrupt signal triggered");
    }
    debugLogger.debug("[SystemController] Interrupt handled");
    return { subtype: "interrupt" };
  }
  /**
   * Handle continue_last_turn request
   *
   * Delegates to the session-provided callback, which classifies the last
   * turn from chat history and (when interrupted) schedules a continuation
   * turn. The response reports `{ accepted, interruption }`; the resumed
   * turn's output flows as regular stream messages afterwards.
   */
  async handleContinueLastTurn() {
    if (!this.context.onContinueLastTurn) {
      throw new Error(
        "continue_last_turn callback (onContinueLastTurn) was not registered on ControlContext \u2014 check session wiring"
      );
    }
    const result = await this.context.onContinueLastTurn();
    debugLogger.debug("[SystemController] continue_last_turn handled:", result);
    return { subtype: "continue_last_turn", ...result };
  }
  /**
   * Handle set_model request
   *
   * Implements actual model switching with validation and error handling
   */
  async handleSetModel(payload, signal) {
    if (signal.aborted) {
      throw new Error("Request aborted");
    }
    const model = payload.model;
    if (typeof model !== "string" || model.trim() === "") {
      throw new Error("Invalid model specified for set_model request");
    }
    try {
      await this.context.config.setModel(model);
      debugLogger.info(`[SystemController] Model switched to: ${model}`);
      return {
        subtype: "set_model",
        model
      };
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : "Failed to set model";
      debugLogger.error(
        `[SystemController] Failed to set model ${model}:`,
        error
      );
      throw new Error(errorMessage);
    }
  }
  /**
   * Handle supported_commands request
   *
   * Returns list of supported slash commands loaded dynamically
   */
  async handleSupportedCommands(signal) {
    if (signal.aborted) {
      throw new Error("Request aborted");
    }
    const slashCommands = await this.loadSlashCommandNames(signal);
    return {
      subtype: "supported_commands",
      commands: slashCommands
    };
  }
  /**
   * Load slash command names using getAvailableCommands
   *
   * @param signal - AbortSignal to respect for cancellation
   * @returns Promise resolving to array of slash command names
   */
  async loadSlashCommandNames(signal) {
    if (signal.aborted) {
      return [];
    }
    try {
      const commands = await getAvailableCommands(
        this.context.config,
        signal,
        "non_interactive"
      );
      if (signal.aborted) {
        return [];
      }
      return commands.map((cmd) => cmd.name).sort();
    } catch (error) {
      if (signal.aborted) {
        return [];
      }
      debugLogger.error(
        "[SystemController] Failed to load slash commands:",
        error
      );
      return [];
    }
  }
};

// packages/cli/src/nonInteractive/control/controllers/permissionController.ts
init_esbuild_shims();
var DEFAULT_CAN_USE_TOOL_TIMEOUT_MS = 6e4;
var PermissionController = class extends BaseController {
  static {
    __name(this, "PermissionController");
  }
  pendingOutgoingRequests = /* @__PURE__ */ new Set();
  /**
   * Handle permission control requests
   */
  async handleRequestPayload(payload, signal) {
    if (signal.aborted) {
      throw new Error("Request aborted");
    }
    switch (payload.subtype) {
      case "can_use_tool":
        return this.handleCanUseTool(
          payload,
          signal
        );
      case "set_permission_mode":
        return this.handleSetPermissionMode(
          payload,
          signal
        );
      default:
        throw new Error(`Unsupported request subtype in PermissionController`);
    }
  }
  /**
   * Handle can_use_tool request
   *
   * Comprehensive permission evaluation based on:
   * - Permission mode (approval level)
   * - Tool registry validation
   * - Error handling with safe defaults
   */
  async handleCanUseTool(payload, signal) {
    if (signal.aborted) {
      throw new Error("Request aborted");
    }
    const toolName = payload.tool_name;
    if (!toolName || typeof toolName !== "string" || toolName.trim().length === 0) {
      return {
        subtype: "can_use_tool",
        behavior: "deny",
        message: "Missing or invalid tool_name in can_use_tool request"
      };
    }
    let behavior = "allow";
    let message;
    try {
      const permissionResult = this.checkPermissionMode();
      if (!permissionResult.allowed) {
        behavior = "deny";
        message = permissionResult.message;
      }
      if (behavior === "allow") {
        const registryResult = this.checkToolRegistry(toolName);
        if (!registryResult.allowed) {
          behavior = "deny";
          message = registryResult.message;
        }
      }
    } catch (error) {
      behavior = "deny";
      message = error instanceof Error ? `Failed to evaluate tool permission: ${error.message}` : "Failed to evaluate tool permission";
    }
    const response = {
      subtype: "can_use_tool",
      behavior
    };
    if (message) {
      response["message"] = message;
    }
    return response;
  }
  /**
   * Check permission mode for tool execution
   */
  checkPermissionMode() {
    const mode = this.context.permissionMode;
    switch (mode) {
      case "yolo":
      // Allow all tools
      case "auto-edit":
      // Auto-approve edit operations
      case "auto":
      // Auto-approve via LLM classifier — coreToolScheduler enforces the gate
      case "plan":
        return { allowed: true };
      case "default":
      // TODO: allow all tools for test
      default:
        return {
          allowed: false,
          message: "Tool execution requires manual approval. Update permission mode or approve via host."
        };
    }
  }
  /**
   * Check if tool exists in registry
   */
  checkToolRegistry(toolName) {
    try {
      const config = this.context.config;
      const registryProvider = config;
      if (typeof registryProvider.getToolRegistry === "function") {
        const registry = registryProvider.getToolRegistry();
        if (registry && typeof registry.getTool === "function" && !registry.getTool(toolName)) {
          return {
            allowed: false,
            message: `Tool "${toolName}" is not registered.`
          };
        }
      }
      return { allowed: true };
    } catch (error) {
      return {
        allowed: false,
        message: `Failed to check tool registry: ${error instanceof Error ? error.message : "Unknown error"}`
      };
    }
  }
  /**
   * Handle set_permission_mode request
   *
   * Updates the permission mode in the context
   */
  async handleSetPermissionMode(payload, signal) {
    if (signal.aborted) {
      throw new Error("Request aborted");
    }
    const mode = payload.mode;
    const validModes = [
      "default",
      "plan",
      "auto-edit",
      "auto",
      "yolo"
    ];
    if (!validModes.includes(mode)) {
      throw new Error(
        `Invalid permission mode: ${mode}. Valid values are: ${validModes.join(", ")}`
      );
    }
    this.context.permissionMode = mode;
    this.context.config.setApprovalMode(mode);
    this.debugLogger.info(
      `[PermissionController] Permission mode updated to: ${mode}`
    );
    return { status: "updated", mode };
  }
  /**
   * Build permission suggestions for tool confirmation UI
   *
   * This method creates UI suggestions based on tool confirmation details,
   * helping the host application present appropriate permission options.
   */
  buildPermissionSuggestions(confirmationDetails) {
    if (!confirmationDetails || typeof confirmationDetails !== "object" || !("type" in confirmationDetails)) {
      return null;
    }
    const details = confirmationDetails;
    const type = String(details["type"] ?? "");
    const title = typeof details["title"] === "string" ? details["title"] : void 0;
    const confirmationType = type;
    switch (confirmationType) {
      case "exec":
        return [
          {
            type: "allow",
            label: "Allow Command",
            description: `Execute: ${details["command"]}`
          },
          {
            type: "deny",
            label: "Deny",
            description: "Block this command execution"
          }
        ];
      case "edit":
        return [
          {
            type: "allow",
            label: "Allow Edit",
            description: `Edit file: ${details["fileName"]}`
          },
          {
            type: "deny",
            label: "Deny",
            description: "Block this file edit"
          },
          ...details["hideModify"] === true ? [] : [
            {
              type: "modify",
              label: "Review Changes",
              description: "Review the proposed changes before applying"
            }
          ]
        ];
      case "plan":
        return [
          {
            type: "allow",
            label: "Approve Plan",
            description: title || "Execute the proposed plan"
          },
          {
            type: "deny",
            label: "Reject Plan",
            description: "Do not execute this plan"
          }
        ];
      case "mcp":
        return [
          {
            type: "allow",
            label: "Allow MCP Call",
            description: `${details["serverName"]}: ${details["toolName"]}`
          },
          {
            type: "deny",
            label: "Deny",
            description: "Block this MCP server call"
          }
        ];
      case "info":
        return [
          {
            type: "allow",
            label: "Allow Info Request",
            description: title || "Allow information request"
          },
          {
            type: "deny",
            label: "Deny",
            description: "Block this information request"
          }
        ];
      default:
        return [
          {
            type: "allow",
            label: "Allow",
            description: title || `Allow ${type} operation`
          },
          {
            type: "deny",
            label: "Deny",
            description: `Block ${type} operation`
          }
        ];
    }
  }
  /**
   * Get callback for monitoring tool calls and handling outgoing permission requests
   * This is passed to executeToolCall to hook into CoreToolScheduler updates
   */
  getToolCallUpdateCallback() {
    return (toolCalls) => {
      for (const call of toolCalls) {
        if (call && typeof call === "object" && call.status === "awaiting_approval") {
          const awaiting = call;
          if (typeof awaiting.confirmationDetails?.onConfirm === "function" && !this.pendingOutgoingRequests.has(awaiting.request.callId)) {
            this.pendingOutgoingRequests.add(awaiting.request.callId);
            void this.handleOutgoingPermissionRequest(awaiting);
          }
        }
      }
    };
  }
  /**
   * Handle a teammate tool approval request routed via the
   * TEAMMATE_APPROVAL_REQUEST team event. Stream-json only —
   * non-stream-json sessions handle teammate approvals directly
   * in `nonInteractiveCli.ts` (mode-aware fallback that warns on
   * stderr and cancels). The caller in nonInteractiveCli only
   * forwards events here when `options.controlService` is set,
   * which is itself stream-json-only. Defensive guard remains
   * in case that contract is ever broken.
   */
  async handleTeammateApproval(event) {
    try {
      if (this.context.abortSignal?.aborted) {
        await event.respond("cancel" /* Cancel */);
        return;
      }
      const inputFormat = this.context.config.getInputFormat?.();
      if (inputFormat !== "stream-json" /* STREAM_JSON */) {
        await event.respond("cancel" /* Cancel */);
        return;
      }
      const callId = `teammate-${event.teammateName}-${event.timestamp}`;
      const response = await this.sendControlRequest(
        {
          subtype: "can_use_tool",
          tool_name: event.toolName,
          tool_use_id: callId,
          input: event.toolInput,
          permission_suggestions: [],
          blocked_path: null
        },
        void 0,
        this.context.abortSignal
      );
      if (response.subtype !== "success") {
        await event.respond("cancel" /* Cancel */);
        return;
      }
      const payload = response.response || {};
      const behavior = String(payload["behavior"] || "").toLowerCase();
      if (behavior === "allow") {
        const updatedInput = payload["updatedInput"];
        const respondPayload = updatedInput && typeof updatedInput === "object" && !Array.isArray(updatedInput) ? { updatedInput } : void 0;
        await event.respond(
          "proceed_once" /* ProceedOnce */,
          respondPayload
        );
      } else {
        const cancelMessage = typeof payload["message"] === "string" ? payload["message"] : void 0;
        await event.respond(
          "cancel" /* Cancel */,
          cancelMessage ? { cancelMessage } : void 0
        );
      }
    } catch (error) {
      this.debugLogger.error(
        "[PermissionController] Teammate approval failed:",
        error
      );
      try {
        await event.respond("cancel" /* Cancel */);
      } catch (cancelError) {
        this.debugLogger.error(
          "[PermissionController] Teammate approval cancel failed:",
          cancelError
        );
      }
    }
  }
  /**
   * Handle outgoing permission request
   *
   * Behavior depends on input format:
   * - stream-json mode: Send can_use_tool to SDK and await response
   * - Other modes: Check local approval mode and decide immediately
   */
  async handleOutgoingPermissionRequest(toolCall) {
    try {
      if (this.context.abortSignal?.aborted) {
        await toolCall.confirmationDetails.onConfirm(
          "cancel" /* Cancel */
        );
        return;
      }
      const inputFormat = this.context.config.getInputFormat?.();
      const isStreamJsonMode = inputFormat === "stream-json" /* STREAM_JSON */;
      if (!isStreamJsonMode) {
        const modeCheck = this.checkPermissionMode();
        const outcome = modeCheck.allowed ? "proceed_once" /* ProceedOnce */ : "cancel" /* Cancel */;
        await toolCall.confirmationDetails.onConfirm(outcome);
        return;
      }
      const permissionSuggestions = this.buildPermissionSuggestions(
        toolCall.confirmationDetails
      );
      const response = await this.sendControlRequest(
        {
          subtype: "can_use_tool",
          tool_name: toolCall.request.name,
          tool_use_id: toolCall.request.callId,
          input: toolCall.request.args,
          permission_suggestions: permissionSuggestions,
          blocked_path: null
        },
        this.context.sdkCanUseToolTimeoutMs ?? DEFAULT_CAN_USE_TOOL_TIMEOUT_MS,
        this.context.abortSignal
      );
      if (response.subtype !== "success") {
        await toolCall.confirmationDetails.onConfirm(
          "cancel" /* Cancel */
        );
        return;
      }
      const payload = response.response || {};
      const behavior = String(payload["behavior"] || "").toLowerCase();
      if (behavior === "allow") {
        const updatedInput = payload["updatedInput"];
        if (updatedInput && typeof updatedInput === "object") {
          toolCall.request.args = updatedInput;
        }
        await toolCall.confirmationDetails.onConfirm(
          "proceed_once" /* ProceedOnce */
        );
      } else {
        const cancelMessage = typeof payload["message"] === "string" ? payload["message"] : void 0;
        await toolCall.confirmationDetails.onConfirm(
          "cancel" /* Cancel */,
          cancelMessage ? { cancelMessage } : void 0
        );
      }
    } catch (error) {
      this.debugLogger.error(
        "[PermissionController] Outgoing permission failed:",
        error
      );
      const errorMessage = error instanceof Error ? error.message : String(error);
      const confirmationType = toolCall.confirmationDetails.type;
      if (["edit", "exec", "mcp"].includes(confirmationType)) {
        const execOrMcpDetails = toolCall.confirmationDetails;
        await execOrMcpDetails.onConfirm("cancel" /* Cancel */, {
          cancelMessage: `Error: ${errorMessage}`
        });
      } else {
        await toolCall.confirmationDetails.onConfirm(
          "cancel" /* Cancel */,
          {
            cancelMessage: `Error: ${errorMessage}`
          }
        );
      }
    } finally {
      this.pendingOutgoingRequests.delete(toolCall.request.callId);
    }
  }
};

// packages/cli/src/nonInteractive/control/controllers/sdkMcpController.ts
init_esbuild_shims();
var MCP_REQUEST_TIMEOUT = 3e4;
var SdkMcpController = class extends BaseController {
  static {
    __name(this, "SdkMcpController");
  }
  /**
   * Handle SDK MCP control requests from ControlDispatcher
   *
   * Note: mcp_message requests are NOT handled here. CLI MCP clients
   * send messages via the sendSdkMcpMessage callback directly, not
   * through the control dispatcher.
   */
  async handleRequestPayload(payload, signal) {
    if (signal.aborted) {
      throw new Error("Request aborted");
    }
    switch (payload.subtype) {
      case "mcp_server_status":
        return this.handleMcpStatus();
      default:
        throw new Error(`Unsupported request subtype in SdkMcpController`);
    }
  }
  /**
   * Handle mcp_server_status request
   *
   * Returns status of all registered SDK MCP servers.
   * SDK servers are considered "connected" if they are registered.
   */
  async handleMcpStatus() {
    const status = {};
    for (const serverName of this.context.sdkMcpServers) {
      status[serverName] = "connected";
    }
    return {
      subtype: "mcp_server_status",
      status
    };
  }
  /**
   * Send MCP message to SDK server via control plane
   *
   * @param serverName - Name of the SDK MCP server
   * @param message - MCP JSON-RPC message to send
   * @returns MCP JSON-RPC response from SDK server
   */
  async sendMcpMessageToSdk(serverName, message) {
    this.debugLogger.debug(
      `[SdkMcpController] Sending MCP message to SDK server '${serverName}':`,
      JSON.stringify(message)
    );
    const response = await this.sendControlRequest(
      {
        subtype: "mcp_message",
        server_name: serverName,
        message
      },
      MCP_REQUEST_TIMEOUT,
      this.context.abortSignal
    );
    const responsePayload = response.response;
    const mcpResponse = responsePayload?.["mcp_response"];
    if (!mcpResponse) {
      throw new Error(
        `Invalid MCP response from SDK for server '${serverName}'`
      );
    }
    this.debugLogger.debug(
      `[SdkMcpController] Received MCP response from SDK server '${serverName}':`,
      JSON.stringify(mcpResponse)
    );
    return mcpResponse;
  }
  /**
   * Create a callback function for sending MCP messages to SDK servers.
   *
   * This callback is used by McpClientManager/SdkControlClientTransport to send
   * MCP messages from CLI MCP clients to SDK MCP servers via the control plane.
   *
   * @returns A function that sends MCP messages to SDK and returns the response
   */
  createSendSdkMcpMessage() {
    return (serverName, message) => this.sendMcpMessageToSdk(serverName, message);
  }
};

// packages/cli/src/nonInteractive/control/ControlDispatcher.ts
var debugLogger2 = createDebugLogger("CONTROL_DISPATCHER");
var ControlDispatcher = class {
  static {
    __name(this, "ControlDispatcher");
  }
  context;
  // Make controllers publicly accessible
  systemController;
  permissionController;
  sdkMcpController;
  // Central pending request registries
  pendingIncomingRequests = /* @__PURE__ */ new Map();
  pendingOutgoingRequests = /* @__PURE__ */ new Map();
  abortHandler = null;
  constructor(context) {
    this.context = context;
    this.systemController = new SystemController(
      context,
      this,
      "SystemController"
    );
    this.permissionController = new PermissionController(
      context,
      this,
      "PermissionController"
    );
    this.sdkMcpController = new SdkMcpController(
      context,
      this,
      "SdkMcpController"
    );
    this.abortHandler = () => {
      this.shutdown();
    };
    this.context.abortSignal.addEventListener("abort", this.abortHandler);
  }
  /**
   * Routes an incoming request to the appropriate controller and sends response
   */
  async dispatch(request) {
    const { request_id, request: payload } = request;
    try {
      const controller = this.getControllerForRequest(payload.subtype);
      const response = await controller.handleRequest(payload, request_id);
      this.sendSuccessResponse(request_id, response);
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : String(error);
      this.sendErrorResponse(request_id, errorMessage);
    }
  }
  /**
   * Processes response from SDK for an outgoing request
   */
  handleControlResponse(response) {
    const responsePayload = response.response;
    const requestId = responsePayload.request_id;
    const pending = this.pendingOutgoingRequests.get(requestId);
    if (!pending) {
      debugLogger2.debug(
        `[ControlDispatcher] No pending outgoing request for: ${requestId}`
      );
      return;
    }
    this.deregisterOutgoingRequest(requestId);
    if (responsePayload.subtype === "success") {
      pending.resolve(responsePayload);
    } else {
      const errorMessage = typeof responsePayload.error === "string" ? responsePayload.error : responsePayload.error?.message ?? "Unknown error";
      pending.reject(new Error(errorMessage));
    }
  }
  /**
   * Sends a control request to SDK and waits for response
   */
  async sendControlRequest(payload, timeoutMs) {
    return this.systemController.sendControlRequest(payload, timeoutMs);
  }
  /**
   * Cancels a specific request or all pending requests
   */
  handleCancel(requestId) {
    if (requestId) {
      const pending = this.pendingIncomingRequests.get(requestId);
      if (pending) {
        pending.abortController.abort();
        this.deregisterIncomingRequest(requestId);
        this.sendErrorResponse(requestId, "Request cancelled");
        debugLogger2.debug(
          `[ControlDispatcher] Cancelled incoming request: ${requestId}`
        );
      }
    } else {
      const requestIds = Array.from(this.pendingIncomingRequests.keys());
      for (const id of requestIds) {
        const pending = this.pendingIncomingRequests.get(id);
        if (pending) {
          pending.abortController.abort();
          this.deregisterIncomingRequest(id);
          this.sendErrorResponse(id, "All requests cancelled");
        }
      }
      debugLogger2.debug(
        `[ControlDispatcher] Cancelled all ${requestIds.length} pending incoming requests`
      );
    }
  }
  /**
   * Marks stdin as closed and rejects all pending outgoing requests.
   * After this is called, new outgoing requests will be rejected immediately.
   * This should be called when stdin closes to avoid waiting for responses.
   */
  markInputClosed() {
    if (this.context.inputClosed) {
      return;
    }
    this.context.inputClosed = true;
    const requestIds = Array.from(this.pendingOutgoingRequests.keys());
    if (this.context.debugMode) {
      debugLogger2.debug(
        `[ControlDispatcher] Input closed, rejecting ${requestIds.length} pending outgoing requests`
      );
    }
    for (const id of requestIds) {
      const pending = this.pendingOutgoingRequests.get(id);
      if (pending) {
        this.deregisterOutgoingRequest(id);
        pending.reject(new Error("Input closed"));
      }
    }
  }
  /**
   * Stops all pending requests and cleans up all controllers
   */
  shutdown() {
    debugLogger2.debug("[ControlDispatcher] Shutting down");
    if (this.abortHandler) {
      this.context.abortSignal.removeEventListener("abort", this.abortHandler);
      this.abortHandler = null;
    }
    for (const [
      _requestId,
      pending
    ] of this.pendingIncomingRequests.entries()) {
      pending.abortController.abort();
      clearTimeout(pending.timeoutId);
    }
    this.pendingIncomingRequests.clear();
    for (const [
      _requestId,
      pending
    ] of this.pendingOutgoingRequests.entries()) {
      clearTimeout(pending.timeoutId);
      pending.reject(new Error("Dispatcher shutdown"));
    }
    this.pendingOutgoingRequests.clear();
    this.systemController.cleanup();
    this.permissionController.cleanup();
    this.sdkMcpController.cleanup();
  }
  /**
   * Registers an incoming request in the pending registry.
   */
  registerIncomingRequest(requestId, controller, abortController, timeoutId) {
    this.pendingIncomingRequests.set(requestId, {
      controller,
      abortController,
      timeoutId
    });
  }
  /**
   * Removes an incoming request from the pending registry
   */
  deregisterIncomingRequest(requestId) {
    const pending = this.pendingIncomingRequests.get(requestId);
    if (pending) {
      clearTimeout(pending.timeoutId);
      this.pendingIncomingRequests.delete(requestId);
    }
  }
  /**
   * Registers an outgoing request in the pending registry
   */
  registerOutgoingRequest(requestId, controller, resolve, reject, timeoutId) {
    this.pendingOutgoingRequests.set(requestId, {
      controller,
      resolve,
      reject,
      timeoutId
    });
  }
  /**
   * Removes an outgoing request from the pending registry
   */
  deregisterOutgoingRequest(requestId) {
    const pending = this.pendingOutgoingRequests.get(requestId);
    if (pending) {
      clearTimeout(pending.timeoutId);
      this.pendingOutgoingRequests.delete(requestId);
    }
  }
  /**
   * Get count of pending incoming requests (for debugging)
   */
  getPendingIncomingRequestCount() {
    return this.pendingIncomingRequests.size;
  }
  /**
   * Wait for all incoming request handlers to complete.
   *
   * Uses polling since we don't have direct Promise references to handlers.
   * The pendingIncomingRequests map is managed by BaseController:
   * - Registered when handler starts (in handleRequest)
   * - Deregistered when handler completes (success or error)
   *
   * @param pollIntervalMs - How often to check (default 50ms)
   * @param timeoutMs - Maximum wait time (default 30s)
   */
  async waitForPendingIncomingRequests(pollIntervalMs = 50, timeoutMs = 3e4) {
    const startTime = Date.now();
    while (this.pendingIncomingRequests.size > 0) {
      if (Date.now() - startTime > timeoutMs) {
        debugLogger2.warn(
          `[ControlDispatcher] Timeout waiting for ${this.pendingIncomingRequests.size} pending incoming requests`
        );
        break;
      }
      await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
    }
    if (this.pendingIncomingRequests.size === 0) {
      debugLogger2.debug("[ControlDispatcher] All incoming requests completed");
    }
  }
  /**
   * Returns the controller that handles the given request subtype
   */
  getControllerForRequest(subtype) {
    switch (subtype) {
      case "initialize":
      case "interrupt":
      case "continue_last_turn":
      case "set_model":
      case "supported_commands":
      case "get_context_usage":
        return this.systemController;
      case "can_use_tool":
      case "set_permission_mode":
        return this.permissionController;
      case "mcp_server_status":
        return this.sdkMcpController;
      default:
        throw new Error(`Unknown control request subtype: ${subtype}`);
    }
  }
  /**
   * Sends a success response back to SDK
   */
  sendSuccessResponse(requestId, response) {
    const controlResponse = {
      type: "control_response",
      response: {
        subtype: "success",
        request_id: requestId,
        response
      }
    };
    this.context.streamJson.send(controlResponse);
  }
  /**
   * Sends an error response back to SDK
   */
  sendErrorResponse(requestId, error) {
    const controlResponse = {
      type: "control_response",
      response: {
        subtype: "error",
        request_id: requestId,
        error
      }
    };
    this.context.streamJson.send(controlResponse);
  }
};

// packages/cli/src/nonInteractive/control/ControlService.ts
init_esbuild_shims();
var ControlService = class {
  static {
    __name(this, "ControlService");
  }
  dispatcher;
  /**
   * Construct ControlService
   *
   * @param context - Control context (unused directly, passed to dispatcher)
   * @param dispatcher - Control dispatcher that owns the controller instances
   */
  constructor(context, dispatcher) {
    this.dispatcher = dispatcher;
  }
  /**
   * Permission Domain API
   *
   * Handles tool execution permissions, approval checks, and callbacks.
   * Delegates to the shared PermissionController instance.
   */
  get permission() {
    const controller = this.dispatcher.permissionController;
    return {
      /**
       * Build UI suggestions for tool confirmation dialogs
       *
       * Creates actionable permission suggestions based on tool confirmation details.
       *
       * @param confirmationDetails - Tool confirmation details
       * @returns Array of permission suggestions or null
       */
      buildPermissionSuggestions: controller.buildPermissionSuggestions.bind(controller),
      /**
       * Get callback for monitoring tool call status updates
       *
       * Returns callback function for integration with CoreToolScheduler.
       *
       * @returns Callback function for tool call updates
       */
      getToolCallUpdateCallback: controller.getToolCallUpdateCallback.bind(controller),
      /**
       * Handle a teammate tool approval request (stream-json sessions).
       */
      handleTeammateApproval: controller.handleTeammateApproval.bind(controller)
    };
  }
  /**
   * System Domain API
   *
   * Handles system-level operations and session management.
   * Delegates to the shared SystemController instance.
   */
  get system() {
    const controller = this.dispatcher.systemController;
    return {
      /**
       * Get control capabilities
       *
       * Returns the control capabilities object indicating what control
       * features are available. Used exclusively for the initialize
       * control response. System messages do not include capabilities.
       *
       * @returns Control capabilities object
       */
      getControlCapabilities: /* @__PURE__ */ __name(() => controller.buildControlCapabilities(), "getControlCapabilities")
    };
  }
  /**
   * MCP Domain API
   *
   * Handles Model Context Protocol server interactions.
   * Delegates to the shared MCPController instance.
   */
  // get mcp(): McpServiceAPI {
  //   return {
  //     /**
  //      * Get or create MCP client for a server (lazy initialization)
  //      *
  //      * Returns existing client or creates new connection.
  //      *
  //      * @param serverName - Name of the MCP server
  //      * @returns Promise with client and config
  //      */
  //     getMcpClient: async (serverName: string) => {
  //       // MCPController has a private method getOrCreateMcpClient
  //       // We need to expose it via the API
  //       // For now, throw error as placeholder
  //       // The actual implementation will be added when we update MCPController
  //       throw new Error(
  //         `getMcpClient not yet implemented in ControlService. Server: ${serverName}`,
  //       );
  //     },
  //
  //     /**
  //      * List all available MCP servers
  //      *
  //      * Returns names of configured/connected MCP servers.
  //      *
  //      * @returns Array of server names
  //      */
  //     listServers: () => {
  //       // Get servers from context
  //       const sdkServers = Array.from(
  //         this.dispatcher.mcpController['context'].sdkMcpServers,
  //       );
  //       const cliServers = Array.from(
  //         this.dispatcher.mcpController['context'].mcpClients.keys(),
  //       );
  //       return [...new Set([...sdkServers, ...cliServers])];
  //     },
  //   };
  // }
  /**
   * Hook Domain API
   *
   * Handles hook callback processing (placeholder for future expansion).
   * Delegates to the shared HookController instance.
   */
  // get hook(): HookServiceAPI {
  //   // HookController has no public methods yet - controller access reserved for future use
  //   return {};
  // }
  /**
   * Cleanup all controllers
   *
   * Should be called on session shutdown. Delegates to dispatcher's shutdown
   * method to ensure all controllers are properly cleaned up.
   */
  cleanup() {
    this.dispatcher.shutdown();
  }
};

// packages/cli/src/nonInteractive/types.ts
init_esbuild_shims();
function isCLIUserMessage(msg) {
  return msg && typeof msg === "object" && msg.type === "user" && "message" in msg;
}
__name(isCLIUserMessage, "isCLIUserMessage");
function isCLIAssistantMessage(msg) {
  return msg && typeof msg === "object" && msg.type === "assistant" && "uuid" in msg && "message" in msg && "session_id" in msg && "parent_tool_use_id" in msg;
}
__name(isCLIAssistantMessage, "isCLIAssistantMessage");
function isCLISystemMessage(msg) {
  return msg && typeof msg === "object" && msg.type === "system" && "subtype" in msg && "uuid" in msg && "session_id" in msg;
}
__name(isCLISystemMessage, "isCLISystemMessage");
function isCLIResultMessage(msg) {
  return msg && typeof msg === "object" && msg.type === "result" && "subtype" in msg && "duration_ms" in msg && "is_error" in msg && "uuid" in msg && "session_id" in msg;
}
__name(isCLIResultMessage, "isCLIResultMessage");
function isCLIPartialAssistantMessage(msg) {
  return msg && typeof msg === "object" && msg.type === "stream_event" && "uuid" in msg && "session_id" in msg && "event" in msg && "parent_tool_use_id" in msg;
}
__name(isCLIPartialAssistantMessage, "isCLIPartialAssistantMessage");
function isControlRequest(msg) {
  return msg && typeof msg === "object" && msg.type === "control_request" && "request_id" in msg && "request" in msg;
}
__name(isControlRequest, "isControlRequest");
function isControlResponse(msg) {
  return msg && typeof msg === "object" && msg.type === "control_response" && "response" in msg;
}
__name(isControlResponse, "isControlResponse");
function isControlCancel(msg) {
  return msg && typeof msg === "object" && msg.type === "control_cancel_request" && "request_id" in msg;
}
__name(isControlCancel, "isControlCancel");

// packages/cli/src/nonInteractive/session.ts
var debugLogger3 = createDebugLogger("NON_INTERACTIVE_SESSION");
var Session = class {
  static {
    __name(this, "Session");
  }
  userMessageQueue = [];
  monitorStartedQueue = [];
  monitorQueue = [];
  pendingContinueTurn = false;
  continueTurnInProgress = false;
  abortController;
  config;
  sessionId;
  promptIdCounter = 0;
  inputReader;
  outputAdapter;
  controlContext = null;
  dispatcher = null;
  controlService = null;
  controlSystemEnabled = null;
  shutdownHandler = null;
  initialPrompt = null;
  processingPromise = null;
  isShuttingDown = false;
  configInitialized = false;
  monitorNotificationsRegistered = false;
  monitorRegistrationsRegistered = false;
  settings;
  // Single initialization promise that resolves when session is ready for user messages.
  // Created lazily once initialization actually starts.
  initializationPromise = null;
  initializationResolve = null;
  initializationReject = null;
  constructor(config, initialPrompt, settings = createMinimalSettings()) {
    this.config = config;
    this.settings = settings;
    this.sessionId = config.getSessionId();
    this.abortController = new AbortController();
    this.initialPrompt = initialPrompt ?? null;
    this.inputReader = new StreamJsonInputReader();
    this.outputAdapter = new StreamJsonOutputAdapter(
      config,
      config.getIncludePartialMessages()
    );
    this.setupSignalHandlers();
  }
  ensureInitializationPromise() {
    if (this.initializationPromise) {
      return;
    }
    this.initializationPromise = new Promise((resolve, reject) => {
      this.initializationResolve = () => {
        resolve();
        this.initializationResolve = null;
        this.initializationReject = null;
      };
      this.initializationReject = (error) => {
        reject(error);
        this.initializationResolve = null;
        this.initializationReject = null;
      };
    });
  }
  getNextPromptId() {
    this.promptIdCounter++;
    return `${this.sessionId}########${this.promptIdCounter}`;
  }
  async ensureConfigInitialized(options) {
    if (this.configInitialized) {
      return;
    }
    debugLogger3.debug("[Session] Initializing config");
    try {
      profileCheckpoint("config_initialize_start");
      await this.config.initialize(options);
      profileCheckpoint("config_initialize_end");
      await this.config.waitForMcpReady();
      const failedMcpServers = typeof this.config.getFailedMcpServerNames === "function" ? this.config.getFailedMcpServerNames() : [];
      if (failedMcpServers.length > 0) {
        process.stderr.write(
          `Warning: MCP server(s) failed to start: ${failedMcpServers.join(", ")}. Continuing with built-in tools and any servers that did connect.
`
        );
      }
      finalizeStartupProfile(this.config.getSessionId());
      this.configInitialized = true;
      this.registerMonitorRegistrations();
      this.registerMonitorNotifications();
    } catch (error) {
      debugLogger3.error("[Session] Failed to initialize config:", error);
      throw error;
    }
  }
  registerMonitorNotifications() {
    if (this.monitorNotificationsRegistered) {
      return;
    }
    const registry = this.config.getMonitorRegistry();
    registry.setNotificationCallback((displayText, modelText, meta) => {
      if (this.isShuttingDown || this.abortController.signal.aborted) {
        return;
      }
      if (meta.status === "running" && typeof registry.get === "function") {
        const entry = registry.get(meta.monitorId);
        if (!entry || entry.status !== "running") return;
      }
      this.enqueueMonitorNotification({
        displayText,
        modelText,
        sdkNotification: {
          task_id: meta.monitorId,
          tool_use_id: meta.toolUseId,
          status: meta.status
        }
      });
    });
    this.monitorNotificationsRegistered = true;
  }
  registerMonitorRegistrations() {
    if (this.monitorRegistrationsRegistered) {
      return;
    }
    const registry = this.config.getMonitorRegistry();
    registry.setRegisterCallback((entry) => {
      if (this.isShuttingDown || this.abortController.signal.aborted) {
        return;
      }
      this.enqueueMonitorStarted({
        task_id: entry.monitorId,
        tool_use_id: entry.toolUseId,
        description: entry.description
      });
    });
    this.monitorRegistrationsRegistered = true;
  }
  /**
   * Mark initialization as complete
   */
  completeInitialization() {
    if (this.initializationResolve) {
      debugLogger3.debug("[Session] Initialization complete");
      this.initializationResolve();
      this.initializationResolve = null;
      this.initializationReject = null;
    }
  }
  /**
   * Mark initialization as failed
   */
  failInitialization(error) {
    if (this.initializationReject) {
      debugLogger3.error("[Session] Initialization failed:", error);
      this.initializationReject(error);
      this.initializationResolve = null;
      this.initializationReject = null;
    }
  }
  /**
   * Wait for session to be ready for user messages
   */
  async waitForInitialization() {
    if (!this.initializationPromise) {
      return;
    }
    await this.initializationPromise;
  }
  ensureControlSystem() {
    if (this.controlContext && this.dispatcher && this.controlService) {
      return;
    }
    this.controlContext = new ControlContext({
      config: this.config,
      streamJson: this.outputAdapter,
      sessionId: this.sessionId,
      abortSignal: this.abortController.signal,
      settings: this.settings,
      permissionMode: this.config.getApprovalMode(),
      onInterrupt: /* @__PURE__ */ __name(() => this.handleInterrupt(), "onInterrupt"),
      onContinueLastTurn: /* @__PURE__ */ __name(() => this.requestContinueLastTurn(), "onContinueLastTurn")
    });
    this.dispatcher = new ControlDispatcher(this.controlContext);
    this.controlService = new ControlService(
      this.controlContext,
      this.dispatcher
    );
  }
  getDispatcher() {
    if (this.controlSystemEnabled !== true) {
      return null;
    }
    if (!this.dispatcher) {
      this.ensureControlSystem();
    }
    return this.dispatcher;
  }
  /**
   * Handle the first message to determine session mode (SDK vs direct).
   * This is synchronous from the message loop's perspective - it starts
   * async work but does not return a promise that the loop awaits.
   *
   * The initialization completes asynchronously and resolves initializationPromise
   * when ready for user messages.
   */
  handleFirstMessage(message) {
    if (isControlRequest(message)) {
      const request = message;
      this.controlSystemEnabled = true;
      this.ensureControlSystem();
      if (request.request.subtype === "initialize") {
        void this.initializeSdkMode(request);
        return;
      }
      debugLogger3.debug(
        "[Session] Ignoring non-initialize control request during initialization"
      );
      return;
    }
    if (isCLIUserMessage(message)) {
      this.controlSystemEnabled = false;
      void this.initializeDirectMode(message);
      return;
    }
    this.controlSystemEnabled = false;
  }
  /**
   * SDK mode initialization flow
   * Dispatches initialize request and initializes config with MCP support
   */
  async initializeSdkMode(request) {
    this.ensureInitializationPromise();
    try {
      await this.dispatcher?.dispatch(request);
      const sendSdkMcpMessage = this.dispatcher?.sdkMcpController.createSendSdkMcpMessage();
      await this.ensureConfigInitialized({ sendSdkMcpMessage });
      this.completeInitialization();
    } catch (error) {
      debugLogger3.error("[Session] SDK mode initialization failed:", error);
      this.failInitialization(
        error instanceof Error ? error : new Error(String(error))
      );
    }
  }
  /**
   * Direct mode initialization flow
   * Initializes config and enqueues the first user message
   */
  async initializeDirectMode(userMessage) {
    this.ensureInitializationPromise();
    try {
      await this.ensureConfigInitialized();
      this.completeInitialization();
      this.enqueueUserMessage(userMessage);
    } catch (error) {
      debugLogger3.error("[Session] Direct mode initialization failed:", error);
      this.failInitialization(
        error instanceof Error ? error : new Error(String(error))
      );
    }
  }
  /**
   * Handle control request asynchronously (fire-and-forget from main loop).
   * Errors are handled internally and responses sent by dispatcher.
   */
  handleControlRequestAsync(request) {
    const dispatcher = this.getDispatcher();
    if (!dispatcher) {
      debugLogger3.warn("[Session] Control system not enabled");
      return;
    }
    void dispatcher.dispatch(request).catch((error) => {
      debugLogger3.error("[Session] Control request dispatch error:", error);
    });
  }
  /**
   * Handle control response - MUST be synchronous
   * This resolves pending outgoing requests, breaking the deadlock cycle.
   */
  handleControlResponse(response) {
    const dispatcher = this.getDispatcher();
    if (!dispatcher) {
      return;
    }
    dispatcher.handleControlResponse(response);
  }
  handleControlCancel(cancelRequest) {
    const dispatcher = this.getDispatcher();
    if (!dispatcher) {
      return;
    }
    dispatcher.handleCancel(cancelRequest.request_id);
  }
  async processUserMessage(userMessage) {
    const input = extractUserMessageText(userMessage);
    if (!input) {
      debugLogger3.debug("[Session] No text content in user message");
      return;
    }
    await this.waitForInitialization();
    const promptId = this.getNextPromptId();
    try {
      await runNonInteractive(this.config, this.settings, input, promptId, {
        abortController: this.abortController,
        adapter: this.outputAdapter,
        controlService: this.controlService ?? void 0,
        captureMonitorNotifications: false,
        captureMonitorRegistrations: false
      });
    } catch (error) {
      debugLogger3.error("[Session] Query execution error:", error);
    }
  }
  /**
   * Handle a continue_last_turn control request: classify the last turn
   * from chat history and, when it was interrupted, schedule a
   * continuation turn on the work queue. Returns the control reply
   * payload; the continuation itself runs serialized with user messages.
   */
  async requestContinueLastTurn() {
    await this.waitForInitialization();
    if (this.isShuttingDown || this.abortController.signal.aborted) {
      debugLogger3.debug(
        "[Session] continue_last_turn rejected: session is shutting down"
      );
      return { accepted: false, interruption: "none" };
    }
    const geminiClient = this.config.getGeminiClient();
    if (!geminiClient || !geminiClient.isInitialized()) {
      debugLogger3.debug(
        "[Session] continue_last_turn rejected: gemini client is not ready"
      );
      return { accepted: false, interruption: "none" };
    }
    const chat = geminiClient.getChat();
    const historyTail = chat.getHistoryTailShallow?.(TURN_INTERRUPTION_HISTORY_TAIL_COUNT) ?? chat.getHistoryTail(TURN_INTERRUPTION_HISTORY_TAIL_COUNT);
    const detection = detectTurnInterruption(historyTail);
    debugLogger3.info("[Session] requestContinueLastTurn detection", {
      sessionId: this.sessionId,
      kind: detection.kind
    });
    if (detection.kind === "none") {
      debugLogger3.debug(
        "[Session] continue_last_turn rejected: no interrupted turn"
      );
      return { accepted: false, interruption: "none" };
    }
    if (this.pendingContinueTurn || this.continueTurnInProgress) {
      debugLogger3.debug(
        "[Session] continue_last_turn rejected: continuation already pending",
        { kind: detection.kind }
      );
      return { accepted: false, interruption: detection.kind };
    }
    this.pendingContinueTurn = true;
    this.ensureProcessingStarted();
    debugLogger3.info("[Session] continue_last_turn accepted", {
      sessionId: this.sessionId,
      kind: detection.kind
    });
    return { accepted: true, interruption: detection.kind };
  }
  /**
   * Run a scheduled continuation turn. The authoritative interruption
   * re-detection happens inside runNonInteractive (history may have moved
   * since the request was accepted); a turn that became clean by then is
   * a no-op result message.
   */
  async processContinueTurn() {
    this.continueTurnInProgress = true;
    let resultAlreadyEmitted = false;
    try {
      await this.waitForInitialization();
      const promptId = this.getNextPromptId();
      await runNonInteractive(this.config, this.settings, "", promptId, {
        abortController: this.abortController,
        adapter: this.outputAdapter,
        controlService: this.controlService ?? void 0,
        continueInterrupted: true,
        captureMonitorNotifications: false,
        captureMonitorRegistrations: false,
        onResultEmitted: /* @__PURE__ */ __name(() => {
          resultAlreadyEmitted = true;
        }, "onResultEmitted")
      });
    } catch (error) {
      debugLogger3.error("[Session] Continue turn execution error:", error);
      const message = error instanceof Error ? error.message : String(error);
      if (resultAlreadyEmitted) {
        this.outputAdapter.emitSystemMessage("continue_turn_failed", {
          error: message
        });
        return;
      }
      throw new Error(`Continue turn failed: ${message}`, { cause: error });
    } finally {
      this.continueTurnInProgress = false;
    }
  }
  async processMonitorNotificationBatch(batch) {
    await this.waitForInitialization();
    for (const item of batch) {
      this.outputAdapter.emitUserMessage([{ text: item.displayText }]);
      this.outputAdapter.emitSystemMessage(
        "task_notification",
        item.sdkNotification
      );
    }
    const combinedModelText = batch.map((n) => n.modelText).join("\n\n");
    const combinedDisplayText = batch.map((n) => n.displayText).join("; ");
    const promptId = this.getNextPromptId();
    await runNonInteractive(
      this.config,
      this.settings,
      combinedModelText,
      promptId,
      {
        abortController: this.abortController,
        adapter: this.outputAdapter,
        controlService: this.controlService ?? void 0,
        sendMessageType: "notification" /* Notification */,
        notificationDisplayText: combinedDisplayText,
        captureMonitorNotifications: false,
        captureMonitorRegistrations: false
      }
    );
  }
  async processPendingWork() {
    if (this.isShuttingDown || this.abortController.signal.aborted) {
      return;
    }
    while ((this.pendingContinueTurn || this.userMessageQueue.length > 0 || this.monitorStartedQueue.length > 0 || this.monitorQueue.length > 0) && !this.isShuttingDown && !this.abortController.signal.aborted) {
      if (this.pendingContinueTurn) {
        this.pendingContinueTurn = false;
        try {
          await this.processContinueTurn();
        } catch (error) {
          debugLogger3.error("[Session] Error processing continue turn:", error);
          this.emitErrorResult(error);
        }
        continue;
      }
      if (this.userMessageQueue.length > 0) {
        const userMessage = this.userMessageQueue.shift();
        try {
          await this.processUserMessage(userMessage);
        } catch (error) {
          debugLogger3.error("[Session] Error processing user message:", error);
          this.emitErrorResult(error);
        }
        continue;
      }
      const started = this.monitorStartedQueue.shift();
      if (started) {
        this.outputAdapter.emitSystemMessage("task_started", started);
        continue;
      }
      if (this.monitorQueue.length === 0) {
        continue;
      }
      const batch = this.monitorQueue.splice(0);
      try {
        await this.processMonitorNotificationBatch(batch);
      } catch (error) {
        debugLogger3.error(
          "[Session] Error processing monitor notification batch:",
          error
        );
        this.emitErrorResult(error);
      }
    }
  }
  enqueueUserMessage(userMessage) {
    this.userMessageQueue.push(userMessage);
    this.ensureProcessingStarted();
  }
  enqueueMonitorStarted(started) {
    this.monitorStartedQueue.push(started);
    this.ensureProcessingStarted();
  }
  enqueueMonitorNotification(notification) {
    this.monitorQueue.push(notification);
    this.ensureProcessingStarted();
  }
  ensureProcessingStarted() {
    if (this.processingPromise) {
      return;
    }
    this.processingPromise = this.processPendingWork().finally(() => {
      this.processingPromise = null;
      if ((this.pendingContinueTurn || this.userMessageQueue.length > 0 || this.monitorStartedQueue.length > 0 || this.monitorQueue.length > 0) && !this.isShuttingDown && !this.abortController.signal.aborted) {
        this.ensureProcessingStarted();
      }
    });
  }
  emitErrorResult(error, numTurns = 0, durationMs = 0, apiDurationMs = 0) {
    const message = error instanceof Error ? error.message : String(error);
    this.outputAdapter.emitResult({
      isError: true,
      errorMessage: message,
      durationMs,
      apiDurationMs,
      numTurns,
      usage: void 0
    });
  }
  handleInterrupt() {
    debugLogger3.info("[Session] Interrupt requested");
    this.abortController.abort();
  }
  setupSignalHandlers() {
    this.shutdownHandler = () => {
      debugLogger3.info("[Session] Shutdown signal received");
      this.isShuttingDown = true;
      this.abortController.abort();
    };
    process.on("SIGINT", this.shutdownHandler);
    process.on("SIGTERM", this.shutdownHandler);
  }
  /**
   * Wait for all pending work to complete before shutdown
   */
  async waitForAllPendingWork() {
    try {
      await this.waitForInitialization();
    } catch (error) {
      debugLogger3.error(
        "[Session] Initialization error during shutdown:",
        error
      );
    }
    if (this.dispatcher) {
      const pendingCount = this.dispatcher.getPendingIncomingRequestCount();
      if (pendingCount > 0) {
        debugLogger3.debug(
          `[Session] Waiting for ${pendingCount} pending control request handlers`
        );
      }
      await this.dispatcher.waitForPendingIncomingRequests();
    }
    while (this.processingPromise) {
      debugLogger3.debug("[Session] Waiting for user message processing");
      try {
        await this.processingPromise;
      } catch (error) {
        debugLogger3.error("[Session] Error in user message processing:", error);
      }
    }
    if (this.pendingContinueTurn) {
      this.pendingContinueTurn = false;
      this.emitErrorResult(
        new Error("Continuation abandoned: session shut down before it ran")
      );
    }
  }
  async shutdown() {
    debugLogger3.debug("[Session] Shutting down");
    this.isShuttingDown = true;
    this.abortTaskRegistries();
    this.stopMonitorCallbacks();
    await this.waitForAllPendingWork();
    this.abortTaskRegistries();
    this.finishShutdown();
  }
  async drainAndShutdown() {
    debugLogger3.debug("[Session] Draining pending work before shutdown");
    this.abortTaskRegistries();
    this.stopMonitorCallbacks();
    await this.waitForAllPendingWork();
    this.abortTaskRegistries();
    this.finishShutdown();
  }
  abortTaskRegistries() {
    this.config.getMonitorRegistry().abortAll({ notify: false });
    this.config.getBackgroundShellRegistry().abortAll();
    this.config.getBackgroundTaskRegistry().abortAll();
  }
  finishShutdown() {
    this.dispatcher?.shutdown();
    this.cleanupSignalHandlers();
  }
  stopMonitorCallbacks() {
    if (!this.monitorNotificationsRegistered && !this.monitorRegistrationsRegistered) {
      return;
    }
    const registry = this.config.getMonitorRegistry();
    if (this.monitorNotificationsRegistered) {
      registry.setNotificationCallback(void 0);
      this.monitorNotificationsRegistered = false;
    }
    if (this.monitorRegistrationsRegistered) {
      registry.setRegisterCallback(void 0);
      this.monitorRegistrationsRegistered = false;
    }
  }
  cleanupSignalHandlers() {
    if (this.shutdownHandler) {
      process.removeListener("SIGINT", this.shutdownHandler);
      process.removeListener("SIGTERM", this.shutdownHandler);
      this.shutdownHandler = null;
    }
  }
  /**
   * Main message processing loop
   *
   * CRITICAL: This loop must NEVER await handlers that might need to
   * send control requests and wait for responses. Such handlers must
   * be started in fire-and-forget mode, allowing the loop to continue
   * reading responses that resolve pending requests.
   *
   * Message handling order:
   * 1. control_response - FIRST, synchronously resolves pending requests
   * 2. First message - determines mode, starts async initialization
   * 3. control_request - fire-and-forget, tracked by dispatcher
   * 4. control_cancel - synchronous
   * 5. user_message - enqueued for processing
   */
  async run() {
    try {
      debugLogger3.info("[Session] Starting session", this.sessionId);
      if (this.initialPrompt !== null) {
        this.handleFirstMessage(this.initialPrompt);
      }
      try {
        for await (const message of this.inputReader.read()) {
          if (this.abortController.signal.aborted) {
            break;
          }
          if (isControlResponse(message)) {
            this.handleControlResponse(message);
            continue;
          }
          if (this.controlSystemEnabled === null) {
            this.handleFirstMessage(message);
            continue;
          }
          if (isControlRequest(message)) {
            this.handleControlRequestAsync(message);
          } else if (isControlCancel(message)) {
            this.handleControlCancel(message);
          } else if (isCLIUserMessage(message)) {
            this.enqueueUserMessage(message);
          } else if (!isCLIAssistantMessage(message) && !isCLISystemMessage(message) && !isCLIResultMessage(message) && !isCLIPartialAssistantMessage(message)) {
            debugLogger3.warn(
              "[Session] Unknown message type:",
              JSON.stringify(message, null, 2)
            );
          }
          if (this.isShuttingDown) {
            break;
          }
        }
      } catch (streamError) {
        debugLogger3.error("[Session] Stream reading error:", streamError);
        throw streamError;
      }
      if (this.dispatcher) {
        this.dispatcher.markInputClosed();
      }
      await this.drainAndShutdown();
    } catch (error) {
      debugLogger3.error("[Session] Error:", error);
      await this.shutdown();
      throw error;
    } finally {
      this.cleanupSignalHandlers();
    }
  }
};
function extractUserMessageText(message) {
  const content = message.message.content;
  if (typeof content === "string") {
    return content;
  }
  if (Array.isArray(content)) {
    const parts = content.map((block) => {
      if (!block || typeof block !== "object") {
        return "";
      }
      if ("type" in block && block.type === "text" && "text" in block) {
        return typeof block.text === "string" ? block.text : "";
      }
      return JSON.stringify(block);
    }).filter((part) => part.length > 0);
    return parts.length > 0 ? parts.join("\n") : null;
  }
  return null;
}
__name(extractUserMessageText, "extractUserMessageText");
async function runNonInteractiveStreamJson(config, input, settings = createMinimalSettings()) {
  let initialPrompt = void 0;
  if (input && input.trim().length > 0) {
    const sessionId = config.getSessionId();
    initialPrompt = {
      type: "user",
      session_id: sessionId,
      message: {
        role: "user",
        content: input.trim()
      },
      parent_tool_use_id: null
    };
  }
  const manager = new Session(config, initialPrompt, settings);
  await manager.run();
}
__name(runNonInteractiveStreamJson, "runNonInteractiveStreamJson");
export {
  runNonInteractiveStreamJson
};
/**
 * @license
 * Copyright 2025 Qwen Team
 * SPDX-License-Identifier: Apache-2.0
 */
