import { spawn } from 'node:child_process';
import readline from 'node:readline';
import { inspect } from 'node:util';
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';

// src/platform/ai-services/internal/execute-attempt.ts

// src/platform/core/cancellation.ts
var USER_CANCELLED_ERROR_CODE = "JUHONG_E_USER_CANCELLED";
var USER_TERMINATED_ERROR_CODE = "JUHONG_E_USER_TERMINATED";
function createCancellationError(name, code, message) {
  const error = new Error(message);
  error.name = name;
  error.code = code;
  return error;
}
function createUserCancelledError(message = "\uC0AC\uC6A9\uC790\uAC00 \uD604\uC7AC \uC791\uC5C5\uC744 \uCDE8\uC18C\uD588\uC2B5\uB2C8\uB2E4.") {
  return createCancellationError("UserCancelledError", USER_CANCELLED_ERROR_CODE, message);
}
function createUserTerminatedError(message = "\uC0AC\uC6A9\uC790\uAC00 \uC138\uC158 \uC885\uB8CC\uB97C \uC694\uCCAD\uD588\uC2B5\uB2C8\uB2E4.") {
  return createCancellationError("UserTerminatedError", USER_TERMINATED_ERROR_CODE, message);
}
function shellQuote(value) {
  return `'${value.replace(/'/g, `'\\''`)}'`;
}
function safeExcerpt(content, limit = 3e3) {
  if (!content) {
    return "";
  }
  if (content.length <= limit) {
    return content;
  }
  return `${content.slice(0, limit)}
... (truncated ${content.length - limit} chars)`;
}
function stringifyUnknown(value) {
  if (value === void 0 || value === null) {
    return "";
  }
  if (typeof value === "string") {
    return value;
  }
  if (Buffer.isBuffer(value)) {
    return value.toString("utf8");
  }
  if (value instanceof Error) {
    return value.stack || value.message;
  }
  return inspect(value, { depth: 6, breakLength: 120 });
}
function getErrorSummary(error) {
  if (error instanceof Error) {
    return `${error.name}: ${error.message}`;
  }
  return stringifyUnknown(error) || "Unknown error";
}
function prepareCodexLastMessageCapture(args) {
  const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "ju-hong-e-codex-"));
  const capturePath = path.join(tempDir, "last-message.txt");
  return {
    args: [...args, "--output-last-message", capturePath],
    finalizeStdout: (currentStdout) => {
      try {
        if (!fs.existsSync(capturePath)) {
          return currentStdout;
        }
        return fs.readFileSync(capturePath, "utf8");
      } catch {
        return currentStdout;
      }
    },
    cleanup: () => {
      try {
        fs.rmSync(tempDir, { force: true, recursive: true });
      } catch {
      }
    }
  };
}
function prepareAttemptOutputCapture(attempt) {
  if (attempt.stdoutCaptureMode === "codex-last-message-file") {
    return prepareCodexLastMessageCapture(attempt.args);
  }
  return {
    args: attempt.args,
    finalizeStdout: (currentStdout) => currentStdout,
    cleanup: () => {
    }
  };
}

// src/platform/ai-services/internal/structured-output-helpers.ts
function asRecord(value) {
  return value && typeof value === "object" ? value : void 0;
}
function normalizeWhitespace(text) {
  return text.replace(/\s+/g, " ").trim();
}
function truncateText(text, max = 120) {
  return text.length <= max ? text : `${text.slice(0, max - 1)}\u2026`;
}
function pickFirstString(value, keys) {
  for (const key of keys) {
    if (typeof value[key] === "string") {
      return value[key];
    }
  }
  return "";
}
function formatPathForDisplay(rawPath) {
  const normalized = rawPath.replace(/\\/g, "/");
  const segments = normalized.split("/").filter(Boolean);
  if (segments.length <= 2) {
    return normalized;
  }
  return `.../${segments.slice(-2).join("/")}`;
}
function summarizeValue(value) {
  if (typeof value === "string") {
    return truncateText(normalizeWhitespace(value));
  }
  if (typeof value === "number" || typeof value === "boolean") {
    return String(value);
  }
  if (Array.isArray(value)) {
    const items = value.map((item) => summarizeValue(item)).filter(Boolean);
    if (items.length === 0) {
      return "";
    }
    const head = items.slice(0, 2).join(", ");
    return items.length > 2 ? `${head} \uC678 ${items.length - 2}\uAC1C` : head;
  }
  const record = asRecord(value);
  if (!record) {
    return "";
  }
  const pathValue = pickFirstString(record, ["file_path", "filePath", "path", "target_path", "uri"]);
  if (pathValue) {
    return formatPathForDisplay(pathValue);
  }
  const commandValue = pickFirstString(record, ["command", "commandLine", "command_line", "cmd"]);
  if (commandValue) {
    return truncateText(normalizeWhitespace(commandValue));
  }
  const textValue = pickFirstString(record, ["q", "query", "prompt", "text", "description", "label", "name"]);
  if (textValue) {
    return truncateText(normalizeWhitespace(textValue));
  }
  return "";
}
function renderStatusLine(label, detail) {
  return detail ? `[${label}] ${detail}
` : `[${label}]
`;
}
function renderToolUseLine(name, input) {
  const detail = summarizeValue(input);
  return renderStatusLine("\uB3C4\uAD6C", detail ? `${name} ${detail}` : name);
}
function renderToolResultLine(label, detail, success = true) {
  const status = success ? "\uC644\uB8CC" : "\uC2E4\uD328";
  return renderStatusLine("\uB3C4\uAD6C \uACB0\uACFC", detail ? `${label} ${status}: ${detail}` : `${label} ${status}`);
}
function renderErrorLine(detail) {
  return renderStatusLine("\uC624\uB958", detail);
}
function extractTextFromContentBlocks(content) {
  if (!Array.isArray(content)) {
    return "";
  }
  return content.flatMap((block) => {
    if (typeof block === "string") {
      return [block];
    }
    const normalized = asRecord(block);
    if (!normalized) {
      return [];
    }
    if (typeof normalized.text === "string") {
      return [normalized.text];
    }
    if (typeof normalized.content === "string") {
      return [normalized.content];
    }
    return [];
  }).join("");
}
function createLineBufferedProcessor(processLine, finalizeState) {
  let incompleteLineBuffer = "";
  return {
    processStdoutChunk(chunk) {
      incompleteLineBuffer += chunk;
      let stdoutFragment = "";
      let streamFragment = "";
      let lineBreakIndex = incompleteLineBuffer.indexOf("\n");
      while (lineBreakIndex >= 0) {
        const currentLine = incompleteLineBuffer.slice(0, lineBreakIndex);
        const processed = processLine(currentLine);
        stdoutFragment += processed.stdoutFragment || "";
        streamFragment += processed.streamFragment || "";
        incompleteLineBuffer = incompleteLineBuffer.slice(lineBreakIndex + 1);
        lineBreakIndex = incompleteLineBuffer.indexOf("\n");
      }
      return {
        stdoutFragment,
        streamFragment
      };
    },
    finalize() {
      let stdoutFragment = "";
      let streamFragment = "";
      if (incompleteLineBuffer.trim()) {
        const processed = processLine(incompleteLineBuffer);
        stdoutFragment += processed.stdoutFragment || "";
        streamFragment += processed.streamFragment || "";
      }
      incompleteLineBuffer = "";
      const finalized = finalizeState();
      return {
        stdoutFragment: finalized.stdoutFragment ?? stdoutFragment,
        streamFragment: `${streamFragment}${finalized.streamFragment || ""}` || void 0
      };
    }
  };
}

// src/platform/ai-services/internal/claude-stream-json-output-processor.ts
function extractClaudeAssistantText(value) {
  const message = asRecord(asRecord(value)?.message);
  return extractTextFromContentBlocks(message?.content).replace(/\n{3,}/g, "\n\n");
}
function extractClaudeAssistantMessageId(value) {
  const message = asRecord(asRecord(value)?.message);
  if (typeof message?.id === "string") {
    return message.id;
  }
  return typeof asRecord(value)?.uuid === "string" ? asRecord(value)?.uuid : void 0;
}
function extractClaudeToolResultSummary(value) {
  const record = asRecord(value);
  const file = asRecord(record?.file);
  if (file && typeof file.filePath === "string") {
    const lineCount = typeof file.numLines === "number" ? `${file.numLines}\uC904` : "";
    return [formatPathForDisplay(file.filePath), lineCount].filter(Boolean).join(" ");
  }
  return summarizeValue(record?.content) || summarizeValue(record?.message) || summarizeValue(value);
}
function createClaudeStreamJsonOutputProcessor() {
  const assistantMessageOrder = [];
  const assistantMessageTexts = /* @__PURE__ */ new Map();
  const seenToolUseIds = /* @__PURE__ */ new Set();
  let anonymousAssistantIndex = 0;
  let fallbackStdout = "";
  let finalResultText = "";
  return createLineBufferedProcessor(
    (line) => {
      const trimmedLine = line.trim();
      if (!trimmedLine) {
        return {};
      }
      try {
        const parsed = JSON.parse(trimmedLine);
        if (parsed.type === "assistant") {
          const messageText = extractClaudeAssistantText(parsed);
          const messageId = extractClaudeAssistantMessageId(parsed) || `anonymous-assistant-${anonymousAssistantIndex++}`;
          if (messageText) {
            if (!assistantMessageTexts.has(messageId)) {
              assistantMessageOrder.push(messageId);
            }
            assistantMessageTexts.set(messageId, messageText);
          }
          const content = asRecord(parsed.message)?.content;
          const toolUseBlocks = Array.isArray(content) ? content.map((block) => asRecord(block)).filter(Boolean) : [];
          const streamFragment = toolUseBlocks.filter((block) => block?.type === "tool_use" && typeof block.id === "string" && !seenToolUseIds.has(block.id)).map((block) => {
            seenToolUseIds.add(block.id);
            return renderToolUseLine(String(block.name || "Claude \uB3C4\uAD6C"), block.input);
          }).join("");
          return { streamFragment };
        }
        if (parsed.type === "user") {
          return {
            streamFragment: renderToolResultLine("Claude \uB3C4\uAD6C", extractClaudeToolResultSummary(parsed.tool_use_result))
          };
        }
        if (parsed.type === "stream_event") {
          const event = asRecord(parsed.event);
          const delta = asRecord(event?.delta);
          if (event?.type === "content_block_start") {
            const contentBlock = asRecord(event.content_block);
            if (contentBlock?.type === "tool_use" && typeof contentBlock.id === "string" && !seenToolUseIds.has(contentBlock.id)) {
              seenToolUseIds.add(contentBlock.id);
              return {
                streamFragment: renderToolUseLine(String(contentBlock.name || "Claude \uB3C4\uAD6C"), contentBlock.input)
              };
            }
          }
          if (event?.type === "content_block_delta" && delta?.type === "text_delta" && typeof delta.text === "string") {
            return {
              stdoutFragment: delta.text,
              streamFragment: delta.text
            };
          }
          return {};
        }
        if (parsed.type === "result" && typeof parsed.result === "string") {
          finalResultText = parsed.result;
        } else if (parsed.type === "result" && typeof parsed.error === "string" && !finalResultText) {
          finalResultText = parsed.error;
        }
        return {};
      } catch {
        fallbackStdout += `${line}
`;
        return {
          stdoutFragment: `${line}
`,
          streamFragment: `${line}
`
        };
      }
    },
    () => {
      const assistantStdout = assistantMessageOrder.map((messageId) => assistantMessageTexts.get(messageId) || "").filter(Boolean).join("\n\n");
      return {
        stdoutFragment: finalResultText || assistantStdout || fallbackStdout.trimEnd()
      };
    }
  );
}

// src/platform/ai-services/internal/codex-stream-json-output-processor.ts
function normalizeKind(value) {
  return value.replace(/[^a-z]/gi, "").toLowerCase();
}
function extractCodexAssistantText(value) {
  const record = asRecord(value);
  if (!record) {
    return "";
  }
  if (typeof record.delta === "string") {
    return record.delta;
  }
  if (typeof record.text === "string") {
    return record.text;
  }
  if (typeof record.content === "string") {
    return record.content;
  }
  const contentText = extractTextFromContentBlocks(record.content);
  if (contentText) {
    return contentText;
  }
  return extractCodexAssistantText(record.message) || extractCodexAssistantText(record.item);
}
function renderCodexItemLine(eventType, itemType, item) {
  if (itemType === "reasoning") {
    return "";
  }
  if (itemType === "commandexecution") {
    return renderStatusLine(eventType === "item.completed" ? "\uBA85\uB839 \uC644\uB8CC" : "\uBA85\uB839", summarizeValue(item) || "\uC178 \uBA85\uB839\uC744 \uC2E4\uD589\uD588\uC2B5\uB2C8\uB2E4.");
  }
  if (itemType === "filechange") {
    return renderStatusLine("\uD30C\uC77C \uBCC0\uACBD", summarizeValue(item.files) || summarizeValue(item) || "\uD30C\uC77C\uC744 \uC218\uC815\uD588\uC2B5\uB2C8\uB2E4.");
  }
  if (itemType === "mcptoolcall") {
    return renderStatusLine("MCP", summarizeValue(item) || "MCP \uB3C4\uAD6C\uB97C \uD638\uCD9C\uD588\uC2B5\uB2C8\uB2E4.");
  }
  if (itemType === "plan") {
    return renderStatusLine("\uACC4\uD68D", summarizeValue(item) || "\uC791\uC5C5 \uACC4\uD68D\uC744 \uC5C5\uB370\uC774\uD2B8\uD588\uC2B5\uB2C8\uB2E4.");
  }
  if (itemType === "websearch") {
    return renderStatusLine("\uAC80\uC0C9", summarizeValue(item) || "\uC6F9 \uAC80\uC0C9\uC744 \uC2E4\uD589\uD588\uC2B5\uB2C8\uB2E4.");
  }
  return "";
}
function createCodexStreamJsonOutputProcessor() {
  let accumulatedText = "";
  let fallbackStdout = "";
  return createLineBufferedProcessor(
    (line) => {
      const trimmedLine = line.trim();
      if (!trimmedLine) {
        return {};
      }
      try {
        const parsed = JSON.parse(trimmedLine);
        const eventType = typeof parsed.type === "string" ? parsed.type : "";
        if (eventType === "thread.started") {
          return { streamFragment: renderStatusLine("\uC138\uC158", "Codex \uC791\uC5C5\uC744 \uC2DC\uC791\uD588\uC2B5\uB2C8\uB2E4.") };
        }
        if (eventType === "turn.started") {
          return { streamFragment: renderStatusLine("\uC9C4\uD589", "\uC751\uB2F5 \uC0DD\uC131\uC744 \uC2DC\uC791\uD588\uC2B5\uB2C8\uB2E4.") };
        }
        if (eventType === "turn.failed" || eventType === "error") {
          return {
            streamFragment: renderErrorLine(summarizeValue(parsed.message) || summarizeValue(parsed.error) || "Codex \uC2E4\uD589\uC774 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4.")
          };
        }
        if (eventType === "item.started" || eventType === "item.completed") {
          const item = asRecord(parsed.item);
          const itemType = item ? normalizeKind(pickFirstString(item, ["type", "item_type"])) : "";
          if (itemType === "agentmessage") {
            const text = extractCodexAssistantText(item);
            if (!text) {
              return {};
            }
            accumulatedText += text;
            return {
              stdoutFragment: text,
              streamFragment: text
            };
          }
          return {
            streamFragment: item ? renderCodexItemLine(eventType, itemType, item) : ""
          };
        }
        return {};
      } catch {
        fallbackStdout += `${line}
`;
        return {
          stdoutFragment: `${line}
`,
          streamFragment: `${line}
`
        };
      }
    },
    () => ({
      stdoutFragment: accumulatedText || fallbackStdout.trimEnd()
    })
  );
}

// src/platform/ai-services/internal/gemini-stream-json-output-processor.ts
function extractGeminiAgentText(value) {
  const parsed = asRecord(value);
  const role = typeof parsed?.role === "string" ? parsed.role : "";
  if (parsed?.type !== "message" || !["agent", "assistant", "model"].includes(role)) {
    return "";
  }
  if (typeof parsed.delta === "string") {
    return parsed.delta;
  }
  if (typeof parsed.text === "string") {
    return parsed.text;
  }
  if (typeof parsed.content === "string") {
    return parsed.content;
  }
  return extractTextFromContentBlocks(parsed.content);
}
function createGeminiStreamJsonOutputProcessor() {
  let accumulatedText = "";
  let fallbackStdout = "";
  return createLineBufferedProcessor(
    (line) => {
      const trimmedLine = line.trim();
      if (!trimmedLine) {
        return {};
      }
      try {
        const parsed = JSON.parse(trimmedLine);
        if (parsed.type === "message") {
          const text = extractGeminiAgentText(parsed);
          if (!text) {
            return {};
          }
          accumulatedText += text;
          return {
            stdoutFragment: text,
            streamFragment: text
          };
        }
        if (parsed.type === "tool_use") {
          return {
            streamFragment: renderToolUseLine(String(parsed.tool_name || parsed.name || "Gemini \uB3C4\uAD6C"), parsed.parameters || parsed.input)
          };
        }
        if (parsed.type === "tool_result") {
          const success = parsed.status !== "error";
          const detail = summarizeValue(parsed.output) || summarizeValue(parsed.error);
          return {
            streamFragment: renderToolResultLine(String(parsed.tool_id || parsed.tool_name || "Gemini \uB3C4\uAD6C"), detail, success)
          };
        }
        if (parsed.type === "error") {
          return {
            streamFragment: renderErrorLine(summarizeValue(parsed.message) || "Gemini \uC2E4\uD589 \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.")
          };
        }
        return {};
      } catch {
        fallbackStdout += `${line}
`;
        return {
          stdoutFragment: `${line}
`,
          streamFragment: `${line}
`
        };
      }
    },
    () => ({
      stdoutFragment: accumulatedText || fallbackStdout.trimEnd()
    })
  );
}

// src/platform/ai-services/internal/output-processors.ts
function createPlainTextOutputProcessor() {
  return {
    processStdoutChunk(chunk) {
      return {
        stdoutFragment: chunk,
        streamFragment: chunk
      };
    },
    finalize() {
      return {};
    }
  };
}
function createServiceOutputProcessor(protocol = "plain-text") {
  if (protocol === "claude-stream-json") {
    return createClaudeStreamJsonOutputProcessor();
  }
  if (protocol === "codex-stream-json") {
    return createCodexStreamJsonOutputProcessor();
  }
  if (protocol === "gemini-stream-json") {
    return createGeminiStreamJsonOutputProcessor();
  }
  return createPlainTextOutputProcessor();
}

// src/platform/ai-services/internal/shared.ts
function quoteArgs(args) {
  return args.map((arg) => shellQuote(arg)).join(" ");
}

// src/platform/ai-services/internal/execute-attempt.ts
function killServiceProcessTree(child, signal) {
  if (!child.pid) {
    return;
  }
  if (process.platform !== "win32") {
    try {
      process.kill(-child.pid, signal ?? "SIGTERM");
      return;
    } catch {
    }
  }
  try {
    child.kill(signal);
  } catch {
  }
}
function writeStreamChunk(chunk, options, stream, writer, updateTrailingState) {
  if (!options.enabled) {
    return;
  }
  if (chunk && options.onChunk) {
    options.onChunk(chunk, stream);
  }
  if (options.writeToTerminal === false) {
    return;
  }
  writer.write(chunk);
  updateTrailingState(!chunk.endsWith("\n"), writer);
}
function shouldPrintCapturedFinalStdout(currentStdout, finalizedStdout) {
  const normalizedFinal = finalizedStdout.trim();
  if (!normalizedFinal) {
    return false;
  }
  const normalizedCurrent = currentStdout.trim();
  if (!normalizedCurrent) {
    return true;
  }
  return !normalizedCurrent.includes(normalizedFinal);
}
function executeServiceCommandAttempt(command, attempt, trace, streamOutputOptions = false) {
  return new Promise((resolve, reject) => {
    const normalizedStreamOutputOptions = typeof streamOutputOptions === "boolean" ? {
      enabled: streamOutputOptions,
      writeToTerminal: streamOutputOptions
    } : {
      writeToTerminal: true,
      ...streamOutputOptions
    };
    const streamOutput = normalizedStreamOutputOptions.enabled;
    const { abortSignal } = normalizedStreamOutputOptions;
    const outputCapture = prepareAttemptOutputCapture(attempt);
    const child = spawn(command, outputCapture.args, {
      cwd: process.cwd(),
      detached: process.platform !== "win32",
      env: process.env,
      stdio: ["ignore", "pipe", "pipe"]
    });
    const stdoutProcessor = createServiceOutputProcessor(attempt.outputProtocol);
    const { stdin } = process;
    const manageStdin = normalizedStreamOutputOptions.manageStdin !== false;
    const rawState = "isRaw" in stdin ? Boolean(stdin.isRaw) : false;
    let stopReason = null;
    let settled = false;
    let stdout = "";
    let stderr = "";
    let forceKillTimer;
    let lastStreamWriter;
    let needsTrailingNewline = false;
    const flushTrailingNewline = () => {
      if (!streamOutput || normalizedStreamOutputOptions.writeToTerminal === false || !needsTrailingNewline) {
        return;
      }
      (lastStreamWriter || process.stdout).write("\n");
      needsTrailingNewline = false;
      lastStreamWriter = void 0;
    };
    const cleanup = () => {
      abortSignal?.removeEventListener("abort", onAbort);
      if (forceKillTimer) {
        clearTimeout(forceKillTimer);
      }
      if (manageStdin) {
        stdin.removeListener("keypress", onKeyPress);
        if (stdin.isTTY) {
          stdin.setRawMode(rawState);
        }
        stdin.pause();
      }
    };
    const finish = (handler) => {
      if (settled) {
        return;
      }
      settled = true;
      flushTrailingNewline();
      cleanup();
      try {
        handler();
      } finally {
        outputCapture.cleanup();
      }
    };
    const requestStop = (reason) => {
      if (stopReason) {
        return;
      }
      stopReason = reason;
      trace(`service-command:${reason}:requested`, `${command} ${quoteArgs(outputCapture.args)}`);
      killServiceProcessTree(child, process.platform === "win32" ? void 0 : "SIGTERM");
      forceKillTimer = setTimeout(() => {
        if (!settled) {
          killServiceProcessTree(child, "SIGKILL");
        }
      }, 1500);
      forceKillTimer.unref?.();
    };
    const onKeyPress = (_input, key) => {
      if (key.name === "escape") {
        requestStop("cancel");
      }
      if (key.ctrl && key.name === "c") {
        requestStop("terminate");
      }
    };
    const onAbort = () => {
      requestStop("cancel");
    };
    child.stdout?.setEncoding("utf8");
    child.stdout?.on("data", (chunk) => {
      const processed = stdoutProcessor.processStdoutChunk(chunk);
      stdout += processed.stdoutFragment || "";
      writeStreamChunk(processed.streamFragment || "", normalizedStreamOutputOptions, "stdout", process.stdout, (nextNeedsTrailingNewline, nextWriter) => {
        needsTrailingNewline = nextNeedsTrailingNewline;
        lastStreamWriter = nextWriter;
      });
    });
    child.stderr?.setEncoding("utf8");
    child.stderr?.on("data", (chunk) => {
      stderr += chunk;
      writeStreamChunk(chunk, normalizedStreamOutputOptions, "stderr", process.stderr, (nextNeedsTrailingNewline, nextWriter) => {
        needsTrailingNewline = nextNeedsTrailingNewline;
        lastStreamWriter = nextWriter;
      });
    });
    child.on("error", (error) => {
      finish(() => {
        const finalized = stdoutProcessor.finalize();
        const currentStdout = finalized.stdoutFragment || stdout;
        const finalizedStdout = outputCapture.finalizeStdout(currentStdout);
        stdout = finalizedStdout;
        writeStreamChunk(finalized.streamFragment || "", normalizedStreamOutputOptions, "stdout", process.stdout, (nextNeedsTrailingNewline, nextWriter) => {
          needsTrailingNewline = nextNeedsTrailingNewline;
          lastStreamWriter = nextWriter;
        });
        if (streamOutput && shouldPrintCapturedFinalStdout(currentStdout, finalizedStdout)) {
          writeStreamChunk(`${needsTrailingNewline ? "\n" : ""}${finalizedStdout}`, normalizedStreamOutputOptions, "stdout", process.stdout, (nextNeedsTrailingNewline, nextWriter) => {
            needsTrailingNewline = nextNeedsTrailingNewline;
            lastStreamWriter = nextWriter;
          });
        }
        flushTrailingNewline();
        if (stopReason === "cancel") {
          reject(createUserCancelledError("ESC \uC785\uB825\uC73C\uB85C \uD604\uC7AC AI \uC791\uC5C5\uC744 \uCDE8\uC18C\uD588\uC2B5\uB2C8\uB2E4."));
          return;
        }
        if (stopReason === "terminate") {
          reject(createUserTerminatedError("Ctrl+C \uC785\uB825\uC73C\uB85C \uC138\uC158 \uC885\uB8CC\uB97C \uC694\uCCAD\uD588\uC2B5\uB2C8\uB2E4."));
          return;
        }
        resolve({
          status: null,
          stderr: getErrorSummary(error),
          streamedOutput: streamOutput,
          stdout
        });
      });
    });
    child.on("close", (status) => {
      finish(() => {
        const finalized = stdoutProcessor.finalize();
        const currentStdout = finalized.stdoutFragment || stdout;
        const finalizedStdout = outputCapture.finalizeStdout(currentStdout);
        stdout = finalizedStdout;
        writeStreamChunk(finalized.streamFragment || "", normalizedStreamOutputOptions, "stdout", process.stdout, (nextNeedsTrailingNewline, nextWriter) => {
          needsTrailingNewline = nextNeedsTrailingNewline;
          lastStreamWriter = nextWriter;
        });
        if (streamOutput && shouldPrintCapturedFinalStdout(currentStdout, finalizedStdout)) {
          writeStreamChunk(`${needsTrailingNewline ? "\n" : ""}${finalizedStdout}`, normalizedStreamOutputOptions, "stdout", process.stdout, (nextNeedsTrailingNewline, nextWriter) => {
            needsTrailingNewline = nextNeedsTrailingNewline;
            lastStreamWriter = nextWriter;
          });
        }
        flushTrailingNewline();
        if (stopReason === "cancel") {
          reject(createUserCancelledError("ESC \uC785\uB825\uC73C\uB85C \uD604\uC7AC AI \uC791\uC5C5\uC744 \uCDE8\uC18C\uD588\uC2B5\uB2C8\uB2E4."));
          return;
        }
        if (stopReason === "terminate") {
          reject(createUserTerminatedError("Ctrl+C \uC785\uB825\uC73C\uB85C \uC138\uC158 \uC885\uB8CC\uB97C \uC694\uCCAD\uD588\uC2B5\uB2C8\uB2E4."));
          return;
        }
        resolve({
          status,
          stderr,
          streamedOutput: streamOutput,
          stdout
        });
      });
    });
    if (manageStdin) {
      readline.emitKeypressEvents(stdin);
      if (stdin.isTTY) {
        stdin.setRawMode(true);
      }
      stdin.resume();
      stdin.on("keypress", onKeyPress);
    }
    if (abortSignal) {
      if (abortSignal.aborted) {
        requestStop("cancel");
      } else {
        abortSignal.addEventListener("abort", onAbort);
      }
    }
  });
}
function createAttemptFailureError(service, failures) {
  const failureSummary = failures.map(({ attempt, failureKind, result }, index) => {
    const status = result.status === null ? "spawn-error" : String(result.status);
    const excerpt = safeExcerpt(result.stderr || result.stdout || `exit status ${status}`, 1200);
    return [`[${index + 1}/${failures.length}] ${attempt.label}`, `kind: ${failureKind}`, `status: ${status}`, excerpt].join("\n");
  }).join("\n\n");
  const lastFailure = failures.at(-1);
  const allCapacityFailures = failures.length > 0 && failures.every(({ failureKind }) => failureKind === "capacity");
  const headline = allCapacityFailures ? `\uBAA8\uB4E0 ${service} \uBAA8\uB378 \uC2DC\uB3C4\uAC00 \uC0AC\uC6A9\uB7C9 \uD55C\uB3C4 \uB610\uB294 rate limit \uC73C\uB85C \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4. \uC7A0\uC2DC \uD6C4 \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uAC70\uB098 /change-service \uB85C \uB2E4\uB978 \uC11C\uBE44\uC2A4\uB97C \uC120\uD0DD\uD558\uC138\uC694.` : `\uBAA8\uB4E0 ${service} \uBAA8\uB378 \uC2DC\uB3C4\uAC00 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4.`;
  const errorMessage = `${headline}

${failureSummary}`;
  const error = new Error(errorMessage);
  Object.assign(error, {
    failureKind: allCapacityFailures ? "capacity" : "generic",
    status: lastFailure?.result.status ?? 1,
    stderr: errorMessage,
    stdout: lastFailure?.result.stdout || ""
  });
  return error;
}

export { createAttemptFailureError, executeServiceCommandAttempt };
