'use strict';

var fs3 = require('fs');
var path3 = require('path');
var child_process = require('child_process');
var util = require('util');
var fs6 = require('fs/promises');
var os = require('os');
var url = require('url');
var readline = require('readline');

function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }

var fs3__default = /*#__PURE__*/_interopDefault(fs3);
var path3__default = /*#__PURE__*/_interopDefault(path3);
var fs6__default = /*#__PURE__*/_interopDefault(fs6);
var os__default = /*#__PURE__*/_interopDefault(os);
var readline__default = /*#__PURE__*/_interopDefault(readline);

// src/features/token-optimizer/infrastructure/config.ts
var DEFAULT_TOKEN_OPTIMIZER_STATE = {
  enabled: false
};
var tokenOptimizerRuntimeState = globalThis.__JU_HONG_E_TOKEN_OPTIMIZER_STATE__ ?? (globalThis.__JU_HONG_E_TOKEN_OPTIMIZER_STATE__ = {
  ...DEFAULT_TOKEN_OPTIMIZER_STATE
});
function normalizeTokenOptimizerState(value) {
  if (!value || typeof value !== "object") {
    return { ...DEFAULT_TOKEN_OPTIMIZER_STATE };
  }
  const enabled = "enabled" in value ? Boolean(value.enabled) : DEFAULT_TOKEN_OPTIMIZER_STATE.enabled;
  return {
    enabled
  };
}
function readTokenOptimizerConfig(paths) {
  if (!fs3__default.default.existsSync(paths.tokenOptimizerConfigPath)) {
    return { ...DEFAULT_TOKEN_OPTIMIZER_STATE };
  }
  try {
    const parsed = JSON.parse(fs3__default.default.readFileSync(paths.tokenOptimizerConfigPath, "utf8"));
    return normalizeTokenOptimizerState(parsed);
  } catch {
    return { ...DEFAULT_TOKEN_OPTIMIZER_STATE };
  }
}
function hydrateTokenOptimizerState(paths) {
  const nextState = readTokenOptimizerConfig(paths);
  tokenOptimizerRuntimeState.enabled = nextState.enabled;
  return tokenOptimizerRuntimeState.enabled;
}
function isTokenOptimizerEnabled(paths) {
  return tokenOptimizerRuntimeState.enabled;
}

// 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 hasCancellationErrorCode(error, code) {
  return Boolean(
    error && typeof error === "object" && "code" in error && error.code === code
  );
}
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 isUserCancelledError(error) {
  return hasCancellationErrorCode(error, USER_CANCELLED_ERROR_CODE);
}
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 isUserTerminatedError(error) {
  return hasCancellationErrorCode(error, USER_TERMINATED_ERROR_CODE);
}
function runGitCommand(rootDir, command) {
  return child_process.execSync(command, {
    cwd: rootDir,
    encoding: "utf8",
    maxBuffer: 1024 * 1024 * 20,
    stdio: ["ignore", "pipe", "pipe"]
  }).trim();
}
function isGitRepository(rootDir) {
  try {
    runGitCommand(rootDir, "git rev-parse --show-toplevel");
    return true;
  } catch {
    return false;
  }
}
function captureWorkspaceSnapshot(rootDir) {
  if (!isGitRepository(rootDir)) {
    return {
      available: false,
      branch: "",
      diffNameStatus: "",
      diffStat: "",
      gitRoot: "",
      note: "\uD604\uC7AC \uC791\uC5C5 \uACBD\uB85C\uAC00 Git \uC800\uC7A5\uC18C\uAC00 \uC544\uB2D9\uB2C8\uB2E4.",
      recentCommits: [],
      statusLines: []
    };
  }
  const gitRoot = runGitCommand(rootDir, "git rev-parse --show-toplevel");
  const branch = runGitCommand(rootDir, "git branch --show-current");
  const statusOutput = runGitCommand(rootDir, "git status --short");
  const diffStat = runGitCommand(rootDir, "git diff --stat");
  const diffNameStatus = runGitCommand(rootDir, "git diff --name-status");
  const recentCommits = runGitCommand(rootDir, "git log --oneline -5");
  return {
    available: true,
    branch,
    diffNameStatus,
    diffStat,
    gitRoot,
    note: "",
    recentCommits: recentCommits ? recentCommits.split("\n").filter(Boolean) : [],
    statusLines: statusOutput ? statusOutput.split("\n").filter(Boolean) : []
  };
}
function statusLineToPath(statusLine) {
  const normalized = statusLine.trim();
  if (!normalized) {
    return "";
  }
  const pathValue = normalized.slice(3).split(" -> ").pop();
  return pathValue?.trim() || normalized;
}
function diffWorkspaceSnapshots(before, after) {
  const beforeSet = new Set(before.statusLines);
  const afterSet = new Set(after.statusLines);
  const beforeOnly = before.statusLines.filter((line) => !afterSet.has(line));
  const afterOnly = after.statusLines.filter((line) => !beforeSet.has(line));
  const touchedFiles = Array.from(
    new Set([...beforeOnly.map(statusLineToPath), ...afterOnly.map(statusLineToPath)].filter(Boolean))
  );
  return {
    afterOnly,
    beforeOnly,
    touchedFiles
  };
}
function formatCodeBlock(content, language = "") {
  return `\`\`\`${language}
${content || "(\uC5C6\uC74C)"}
\`\`\``;
}
function formatWorkspaceSnapshot(snapshot) {
  if (!snapshot.available) {
    return snapshot.note;
  }
  return [
    `- Git Root: \`${snapshot.gitRoot}\``,
    `- Branch: \`${snapshot.branch || "(detached)"}\``,
    "",
    "### git status --short",
    formatCodeBlock(snapshot.statusLines.join("\n")),
    "",
    "### git diff --stat",
    formatCodeBlock(snapshot.diffStat),
    "",
    "### git diff --name-status",
    formatCodeBlock(snapshot.diffNameStatus),
    "",
    "### \uCD5C\uADFC \uCEE4\uBC0B",
    formatCodeBlock(snapshot.recentCommits.join("\n"))
  ].join("\n");
}
function formatWorkspaceDelta(delta) {
  return [
    "### \uC0C8\uB85C \uAC10\uC9C0\uB41C \uC0C1\uD0DC",
    formatCodeBlock(delta.afterOnly.join("\n")),
    "",
    "### \uC0AC\uB77C\uC9C4 \uC774\uC804 \uC0C1\uD0DC",
    formatCodeBlock(delta.beforeOnly.join("\n")),
    "",
    "### \uC601\uD5A5 \uD30C\uC77C",
    formatCodeBlock(delta.touchedFiles.join("\n"))
  ].join("\n");
}
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 util.inspect(value, { depth: 6, breakLength: 120 });
}
function getErrorSummary(error) {
  if (error instanceof Error) {
    return `${error.name}: ${error.message}`;
  }
  return stringifyUnknown(error) || "Unknown error";
}

// src/platform/core/timestamp-helpers.ts
function padTimestampPart(value) {
  return String(value).padStart(2, "0");
}
function getTimestampParts(now = /* @__PURE__ */ new Date()) {
  return {
    year: now.getFullYear(),
    month: padTimestampPart(now.getMonth() + 1),
    day: padTimestampPart(now.getDate()),
    hour: padTimestampPart(now.getHours()),
    minute: padTimestampPart(now.getMinutes()),
    second: padTimestampPart(now.getSeconds())
  };
}
function getFileTimestamp(now = /* @__PURE__ */ new Date()) {
  const { year, month, day, hour, minute, second } = getTimestampParts(now);
  return `${year}-${month}-${day}_${hour}-${minute}-${second}`;
}
function getHumanReadableNow(now = /* @__PURE__ */ new Date()) {
  const { year, month, day, hour, minute, second } = getTimestampParts(now);
  return `${year}-${month}-${day} ${hour}:${minute}:${second}`;
}

// src/platform/core/history-helpers.ts
var DEFAULT_HISTORY_LIMIT = 5;
var DEFAULT_HISTORY_CHAR_LIMIT = 14e3;
var CONVERSATION_HISTORY_SCOPES = [
  "chat",
  "shell-command",
  "commit",
  "review",
  "gen-html",
  "gen-storybook",
  "minify-md",
  "local-server",
  "mcp",
  "security-policy",
  "show-stream",
  "token-optimizer",
  "service-change"
];
var aiServicesRef = [];
function setAiServicesRef(services) {
  aiServicesRef = services;
}
function isConversationHistoryScope(value) {
  return CONVERSATION_HISTORY_SCOPES.includes(value);
}
function parseConversationHistoryEntry(raw) {
  try {
    const parsed = JSON.parse(raw);
    if (!parsed || typeof parsed !== "object") {
      return void 0;
    }
    if (typeof parsed.timestamp !== "string" || typeof parsed.title !== "string" || typeof parsed.summary !== "string" || typeof parsed.scope !== "string" || typeof parsed.service !== "string") {
      return void 0;
    }
    if (!isConversationHistoryScope(parsed.scope) || !aiServicesRef.includes(parsed.service)) {
      return void 0;
    }
    const previousService = typeof parsed.previousService === "string" && (parsed.previousService === "" || aiServicesRef.includes(parsed.previousService)) ? parsed.previousService : void 0;
    const nextService = typeof parsed.nextService === "string" && aiServicesRef.includes(parsed.nextService) ? parsed.nextService : void 0;
    return {
      input: typeof parsed.input === "string" ? parsed.input : void 0,
      nextService,
      output: typeof parsed.output === "string" ? parsed.output : void 0,
      previousService,
      scope: parsed.scope,
      service: parsed.service,
      summary: parsed.summary,
      timestamp: parsed.timestamp,
      title: parsed.title
    };
  } catch {
    return void 0;
  }
}
function appendConversationHistory(paths, entry) {
  const normalizedEntry = {
    ...entry,
    summary: entry.summary.trim() || entry.title.trim(),
    timestamp: entry.timestamp || getHumanReadableNow(),
    title: entry.title.trim()
  };
  fs3__default.default.appendFileSync(paths.conversationHistoryPath, `${JSON.stringify(normalizedEntry)}
`, "utf8");
  return normalizedEntry;
}
function loadConversationHistory(paths, limit = DEFAULT_HISTORY_LIMIT) {
  if (!fs3__default.default.existsSync(paths.conversationHistoryPath)) {
    return [];
  }
  const lines = fs3__default.default.readFileSync(paths.conversationHistoryPath, "utf8").split("\n").map((line) => line.trim()).filter(Boolean);
  if (lines.length === 0) {
    return [];
  }
  return lines.map(parseConversationHistoryEntry).filter((entry) => entry !== void 0).slice(-limit);
}
function formatConversationHistoryEntry(entry, limit) {
  const inputLimit = Math.max(180, Math.floor(limit * 0.35));
  const outputLimit = Math.max(220, limit - inputLimit);
  const lines = [`## ${entry.timestamp} | ${entry.scope} | ${entry.service}`, `\uC81C\uBAA9: ${entry.title}`];
  if (entry.scope === "service-change") {
    lines.push(`\uC11C\uBE44\uC2A4 \uBCC0\uACBD: ${entry.previousService || "(\uC5C6\uC74C)"} -> ${entry.nextService || entry.service}`);
    lines.push(`\uC694\uC57D: ${safeExcerpt(entry.summary, outputLimit)}`);
    return lines.join("\n");
  }
  if (entry.input) {
    lines.push("");
    lines.push("\uC0AC\uC6A9\uC790 \uC785\uB825");
    lines.push(formatCodeBlock(safeExcerpt(entry.input, inputLimit)));
  }
  if (entry.output) {
    lines.push("");
    lines.push("\uC774\uC804 \uACB0\uACFC \uC694\uC57D");
    lines.push(formatCodeBlock(safeExcerpt(entry.output, outputLimit)));
  } else if (entry.summary) {
    lines.push("");
    lines.push("\uACB0\uACFC \uC694\uC57D");
    lines.push(formatCodeBlock(safeExcerpt(entry.summary, outputLimit)));
  }
  return lines.join("\n");
}
function formatConversationHistory(entries, charLimit) {
  if (entries.length === 0) {
    return "";
  }
  const entryLimit = Math.max(400, Math.floor(charLimit / Math.max(entries.length, 1)));
  const content = entries.map((entry) => formatConversationHistoryEntry(entry, entryLimit)).join("\n\n");
  return safeExcerpt(content, charLimit);
}
function loadRecentHistoryContext(paths, limit = DEFAULT_HISTORY_LIMIT, charLimit = DEFAULT_HISTORY_CHAR_LIMIT) {
  const conversationEntries = loadConversationHistory(paths, limit);
  return formatConversationHistory(conversationEntries, charLimit);
}

// src/platform/types/app.ts
var AI_SERVICE = {
  CLAUDE: "claude",
  CODEX: "codex",
  GEMINI: "gemini"
};
function getAvailableFilePath(directory, baseName, extension) {
  const first = path3__default.default.join(directory, `${baseName}${extension}`);
  if (!fs3__default.default.existsSync(first)) {
    return first;
  }
  let next = first;
  let count = 1;
  while (fs3__default.default.existsSync(next)) {
    next = path3__default.default.join(directory, `${baseName}-${count}${extension}`);
    if (!fs3__default.default.existsSync(next)) {
      break;
    }
    count += 1;
  }
  return next;
}
function appendHistoryIndex(paths, summary, relativeFilePath) {
  const line = `- ${getHumanReadableNow()} | ${summary} | file: \`${relativeFilePath}\`
`;
  fs3__default.default.appendFileSync(paths.historyIndexPath, line, "utf8");
}
function renderSections(sections = []) {
  if (sections.length === 0) {
    return "";
  }
  return sections.map((section) => `
## ${section.heading}

${section.markdown}
`).join("\n");
}
function serializeError(error) {
  const serialized = {
    summary: getErrorSummary(error)
  };
  if (error instanceof Error) {
    serialized.name = error.name;
    serialized.message = error.message;
    serialized.stack = error.stack;
  } else {
    serialized.value = stringifyUnknown(error);
  }
  if (error && typeof error === "object") {
    const errorLike = error;
    ["code", "errno", "syscall", "path", "cmd", "status", "signal"].forEach((key) => {
      if (errorLike[key] !== void 0) {
        serialized[key] = errorLike[key];
      }
    });
    const stdout = stringifyUnknown(errorLike.stdout);
    if (stdout) {
      serialized.stdout = stdout;
    }
    const stderr = stringifyUnknown(errorLike.stderr);
    if (stderr) {
      serialized.stderr = stderr;
    }
  }
  return serialized;
}
function writeTurnHistory(paths, record) {
  const baseName = `${getFileTimestamp()}-${record.scope}`;
  const filePath = getAvailableFilePath(paths.turnsDir, baseName, ".md");
  const markdown = `# ${record.title}

- \uC2DC\uAC01: ${getHumanReadableNow()}
- scope: \`${record.scope}\`
- service: \`${record.service}\`
- skipped: \`${record.skipped}\`

## \uC0AC\uC6A9\uC790 \uC785\uB825

${formatCodeBlock(record.input)}

## AI \uC751\uB2F5

${record.output || "(\uC751\uB2F5 \uC5C6\uC74C)"}

## \uCD5C\uADFC \uD788\uC2A4\uD1A0\uB9AC \uC8FC\uC785

${formatCodeBlock(record.historyContext)}

## \uC2E4\uD589 \uBA85\uB839\uC5B4 \uBBF8\uB9AC\uBCF4\uAE30

${formatCodeBlock(record.previewCommand, "sh")}

## \uC791\uC5C5 \uC804 \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4

${formatWorkspaceSnapshot(record.workspaceBefore)}

## \uC791\uC5C5 \uD6C4 \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4

${formatWorkspaceSnapshot(record.workspaceAfter)}

## \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uBCC0\uD654

${formatWorkspaceDelta(record.workspaceDelta)}${renderSections(record.extraSections)}
`;
  fs3__default.default.writeFileSync(filePath, markdown, "utf8");
  appendHistoryIndex(paths, `${record.scope} | ${record.service} | ${record.title}`, path3__default.default.relative(paths.rootDir, filePath));
  return filePath;
}
function writeErrorReport(paths, error, options) {
  const filePath = getAvailableFilePath(paths.errorDir, `${getFileTimestamp()}-error`, ".md");
  const serializedError = serializeError(error);
  const traceMessages = options.traceMessages ?? [];
  const markdown = `# Error Report

- \uC2DC\uAC01: ${getHumanReadableNow()}
- scope: \`${options.scope}\`
- \uC791\uC5C5 \uACBD\uB85C: \`${paths.rootDir}\`
- \uC2E4\uD589 \uC778\uC790: \`${JSON.stringify(options.args ?? process.argv.slice(2))}\`

## Summary

${serializedError.summary || "Unknown error"}

## Error

\`\`\`json
${JSON.stringify(serializedError, null, 2)}
\`\`\`

## Trace

\`\`\`json
${JSON.stringify(traceMessages, null, 2)}
\`\`\`${renderSections(options.extraSections)}
`;
  fs3__default.default.writeFileSync(filePath, markdown, "utf8");
  return filePath;
}

// src/platform/core/helpers.ts
var AI_SERVICES = Object.values(AI_SERVICE);
setAiServicesRef(AI_SERVICES);

// src/features/security-policy/domain/policy.ts
var DEFAULT_SECURITY_POLICY_MODE = "prompt-with-resources";
var SECURITY_POLICY_OPTIONS = [
  {
    description: "\uBCF4\uC548 \uAC80\uC0AC\uB97C \uC644\uC804\uD788 \uBE44\uD65C\uC131\uD654\uD569\uB2C8\uB2E4. \uBBFC\uAC10\uC815\uBCF4\uAC00 \uD3EC\uD568\uB418\uC5B4\uB3C4 \uCC28\uB2E8\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
    label: "\uBCF4\uC548 \uAC80\uC0AC \uC0AC\uC6A9 \uC548 \uD568",
    mode: "disabled",
    summary: "\uBCF4\uC548 \uAC80\uC0AC \uBE44\uD65C\uC131\uD654"
  },
  {
    description: "\uC0AC\uC6A9\uC790 \uC785\uB825\uACFC \uBA85\uB839 \uC778\uC790\uB9CC \uAC80\uC0AC\uD569\uB2C8\uB2E4. \uD504\uB86C\uD504\uD2B8 \uBCF8\uBB38\uACFC \uCC38\uC870 \uB9AC\uC18C\uC2A4\uB294 \uC77D\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
    label: "\uC785\uB825/\uBA85\uB839\uB9CC \uAC80\uC0AC",
    mode: "input-only",
    summary: "\uC785\uB825/\uBA85\uB839 \uBB38\uC790\uC5F4\uB9CC \uAC80\uC0AC"
  },
  {
    description: "\uC785\uB825\uACFC AI \uD504\uB86C\uD504\uD2B8 \uBB38\uC790\uC5F4\uAE4C\uC9C0 \uAC80\uC0AC\uD569\uB2C8\uB2E4. \uACBD\uB85C/URL\uC774 \uAC00\uB9AC\uD0A4\uB294 \uB0B4\uC6A9\uC740 \uC77D\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
    label: "\uD504\uB86C\uD504\uD2B8 \uD14D\uC2A4\uD2B8\uAE4C\uC9C0 \uAC80\uC0AC",
    mode: "prompt-only",
    summary: "\uD504\uB86C\uD504\uD2B8 \uBB38\uC790\uC5F4\uAE4C\uC9C0 \uAC80\uC0AC"
  },
  {
    description: "\uC785\uB825, \uD504\uB86C\uD504\uD2B8, \uACBD\uB85C/URL\uC774 \uAC00\uB9AC\uD0A4\uB294 \uCC38\uC870 \uB9AC\uC18C\uC2A4 \uB0B4\uC6A9\uAE4C\uC9C0 \uD568\uAED8 \uAC80\uC0AC\uD569\uB2C8\uB2E4.",
    label: "\uD504\uB86C\uD504\uD2B8\uC640 \uCC38\uC870 \uB9AC\uC18C\uC2A4\uAE4C\uC9C0 \uC2EC\uCE35 \uAC80\uC0AC",
    mode: "prompt-with-resources",
    summary: "\uD504\uB86C\uD504\uD2B8\uC640 \uCC38\uC870 \uB9AC\uC18C\uC2A4\uAE4C\uC9C0 \uC2EC\uCE35 \uAC80\uC0AC"
  }
];
function createDefaultSecurityPolicy() {
  return {
    mode: DEFAULT_SECURITY_POLICY_MODE
  };
}
function isSecurityPolicyMode(value) {
  return SECURITY_POLICY_OPTIONS.some((option) => option.mode === value);
}
function getSecurityPolicyOption(mode) {
  return SECURITY_POLICY_OPTIONS.find((option) => option.mode === mode) || SECURITY_POLICY_OPTIONS.at(-1);
}
function describeSecurityPolicyMode(mode) {
  return getSecurityPolicyOption(mode).label;
}
function isSecurityPolicyEnabled(mode) {
  return mode !== "disabled";
}
function resolveSecurityValidationOptions(mode) {
  switch (mode) {
    case "disabled":
      return {
        inspectPrompt: false,
        inspectResources: false,
        mode
      };
    case "input-only":
      return {
        inspectPrompt: false,
        inspectResources: false,
        mode
      };
    case "prompt-only":
      return {
        inspectPrompt: true,
        inspectResources: false,
        mode
      };
    case "prompt-with-resources":
    default:
      return {
        inspectPrompt: true,
        inspectResources: true,
        mode
      };
  }
}
function readSecurityPolicy(paths) {
  if (!paths?.securityPolicyPath || !fs3__default.default.existsSync(paths.securityPolicyPath)) {
    return createDefaultSecurityPolicy();
  }
  try {
    const parsed = JSON.parse(fs3__default.default.readFileSync(paths.securityPolicyPath, "utf8"));
    if (!isSecurityPolicyMode(parsed.mode)) {
      return createDefaultSecurityPolicy();
    }
    return {
      mode: parsed.mode
    };
  } catch {
    return createDefaultSecurityPolicy();
  }
}
var execFileAsync = util.promisify(child_process.execFile);
var MAX_REFERENCED_RESOURCES = 16;
var MAX_TEXT_LENGTH = 12e4;
var MAX_FILE_BUFFER = 1024 * 1024 * 4;
var MAX_REMOTE_BUFFER = 1024 * 1024 * 5;
var COMMAND_TIMEOUT_MS = 15e3;
var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
  ".cjs",
  ".conf",
  ".css",
  ".csv",
  ".d.ts",
  ".env",
  ".html",
  ".htm",
  ".ini",
  ".java",
  ".js",
  ".json",
  ".jsx",
  ".kt",
  ".less",
  ".log",
  ".md",
  ".mjs",
  ".php",
  ".py",
  ".rb",
  ".rs",
  ".scss",
  ".sh",
  ".sql",
  ".svg",
  ".swift",
  ".ts",
  ".tsx",
  ".txt",
  ".xml",
  ".yaml",
  ".yml",
  ".zsh"
]);
var IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([".bmp", ".gif", ".heic", ".jpeg", ".jpg", ".png", ".tif", ".tiff", ".webp"]);
var TEXTUTIL_EXTENSIONS = /* @__PURE__ */ new Set([".doc", ".docx", ".odt", ".rtf", ".rtfd", ".webarchive"]);
var REMOTE_URL_PATTERN = /\bhttps?:\/\/[^\s<>()"'`]+/gi;
var FILE_URL_PATTERN = /\bfile:\/\/[^\s<>()"'`]+/gi;
var LOCAL_PATH_WITH_PREFIX_PATTERN = /(?:^|[\s("'`])((?:~|\.{1,2}\/|\/)[^\s<>()"'`]+)/g;
var RELATIVE_PATH_WITH_SEPARATOR_PATTERN = /(?:^|[\s("'`])((?:[A-Za-z0-9._-]+\/)+[A-Za-z0-9._-]+\.[A-Za-z0-9._-]+)/g;
function trimTrailingPunctuation(value) {
  return value.replace(/[),.;:!?`'"\]}]+$/g, "").trim();
}
function limitTextContent(value) {
  if (!value) {
    return "";
  }
  const normalized = value.replace(/\0/g, "").trim();
  if (normalized.length <= MAX_TEXT_LENGTH) {
    return normalized;
  }
  return normalized.slice(0, MAX_TEXT_LENGTH);
}
function isLikelyTextMimeType(mimeType) {
  return mimeType.startsWith("text/") || mimeType.includes("json") || mimeType.includes("javascript") || mimeType.includes("xml") || mimeType.includes("yaml") || mimeType.includes("svg");
}
function isLikelyImageMimeType(mimeType) {
  return mimeType.startsWith("image/");
}
function collectMatches(text, pattern) {
  const values = [];
  for (const match of text.matchAll(pattern)) {
    const candidate = trimTrailingPunctuation((match[1] || match[0] || "").trim());
    if (!candidate) {
      continue;
    }
    values.push(candidate);
  }
  return values;
}
function resolveLocalResource(value, rootDir) {
  try {
    if (value.startsWith("file://")) {
      return path3__default.default.normalize(url.fileURLToPath(value));
    }
  } catch {
    return void 0;
  }
  if (value.startsWith("~")) {
    return path3__default.default.normalize(path3__default.default.join(os__default.default.homedir(), value.slice(1)));
  }
  if (path3__default.default.isAbsolute(value)) {
    return path3__default.default.normalize(value);
  }
  if (!rootDir) {
    return void 0;
  }
  return path3__default.default.normalize(path3__default.default.resolve(rootDir, value));
}
function toReferencedResources(values, rootDir) {
  const seen = /* @__PURE__ */ new Set();
  const resources = [];
  for (const value of values) {
    for (const candidate of collectMatches(value, REMOTE_URL_PATTERN)) {
      const normalized = trimTrailingPunctuation(candidate);
      if (!normalized || seen.has(normalized)) {
        continue;
      }
      seen.add(normalized);
      resources.push({
        kind: "remote-url",
        location: normalized
      });
    }
    for (const candidate of [...collectMatches(value, FILE_URL_PATTERN), ...collectMatches(value, LOCAL_PATH_WITH_PREFIX_PATTERN), ...collectMatches(value, RELATIVE_PATH_WITH_SEPARATOR_PATTERN)]) {
      const resolved = resolveLocalResource(candidate, rootDir);
      if (!resolved || seen.has(resolved)) {
        continue;
      }
      seen.add(resolved);
      resources.push({
        kind: "local-file",
        location: resolved
      });
    }
    if (resources.length >= MAX_REFERENCED_RESOURCES) {
      return resources.slice(0, MAX_REFERENCED_RESOURCES);
    }
  }
  return resources;
}
async function detectLocalMimeType(filePath) {
  try {
    const { stdout } = await execFileAsync("file", ["--brief", "--mime-type", filePath], {
      maxBuffer: 64 * 1024,
      timeout: COMMAND_TIMEOUT_MS
    });
    return stdout.trim().toLowerCase();
  } catch {
    return "";
  }
}
async function readTextFile(filePath) {
  try {
    const stat = await fs6__default.default.stat(filePath);
    if (stat.size > MAX_FILE_BUFFER) {
      const handle = await fs6__default.default.open(filePath, "r");
      try {
        const buffer2 = Buffer.alloc(MAX_FILE_BUFFER);
        await handle.read(buffer2, 0, MAX_FILE_BUFFER, 0);
        return limitTextContent(buffer2.toString("utf8"));
      } finally {
        await handle.close();
      }
    }
    const buffer = await fs6__default.default.readFile(filePath);
    return limitTextContent(buffer.toString("utf8"));
  } catch {
    return "";
  }
}
async function readTextViaTextutil(filePath) {
  try {
    const { stdout } = await execFileAsync("textutil", ["-convert", "txt", "-stdout", filePath], {
      maxBuffer: MAX_FILE_BUFFER,
      timeout: COMMAND_TIMEOUT_MS
    });
    return limitTextContent(stdout);
  } catch {
    return "";
  }
}
async function readTextViaMetadata(filePath) {
  try {
    const { stdout } = await execFileAsync("mdls", ["-raw", "-name", "kMDItemTextContent", filePath], {
      maxBuffer: MAX_FILE_BUFFER,
      timeout: COMMAND_TIMEOUT_MS
    });
    const normalized = stdout.trim();
    if (!normalized || normalized === "(null)") {
      return "";
    }
    return limitTextContent(normalized);
  } catch {
    return "";
  }
}
async function readTextViaStrings(filePath) {
  try {
    const { stdout } = await execFileAsync("strings", ["-n", "6", filePath], {
      maxBuffer: MAX_FILE_BUFFER,
      timeout: COMMAND_TIMEOUT_MS
    });
    return limitTextContent(stdout);
  } catch {
    return "";
  }
}
async function readTextViaTesseract(filePath) {
  try {
    const { stdout } = await execFileAsync("tesseract", [filePath, "stdout", "--psm", "6"], {
      maxBuffer: MAX_FILE_BUFFER,
      timeout: COMMAND_TIMEOUT_MS
    });
    return limitTextContent(stdout);
  } catch {
    return "";
  }
}
async function readLocalResourceText(filePath) {
  try {
    const stats = await fs6__default.default.stat(filePath);
    if (!stats.isFile()) {
      return "";
    }
  } catch {
    return "";
  }
  const extension = path3__default.default.extname(filePath).toLowerCase();
  const mimeType = await detectLocalMimeType(filePath);
  if (IMAGE_EXTENSIONS.has(extension) || isLikelyImageMimeType(mimeType)) {
    return await readTextViaTesseract(filePath) || await readTextViaMetadata(filePath);
  }
  if (TEXT_EXTENSIONS.has(extension) || isLikelyTextMimeType(mimeType)) {
    return readTextFile(filePath);
  }
  if (TEXTUTIL_EXTENSIONS.has(extension)) {
    return await readTextViaTextutil(filePath) || await readTextViaMetadata(filePath);
  }
  return await readTextViaMetadata(filePath) || await readTextViaStrings(filePath);
}
async function readRemoteBuffer(location) {
  const controller = new AbortController();
  const timer = setTimeout(() => controller.abort(), COMMAND_TIMEOUT_MS);
  try {
    const response = await fetch(location, {
      redirect: "follow",
      signal: controller.signal
    });
    if (!response.ok) {
      return void 0;
    }
    const contentLength = Number(response.headers.get("content-length") || "0");
    if (contentLength > MAX_REMOTE_BUFFER) {
      return void 0;
    }
    const arrayBuffer = await response.arrayBuffer();
    const buffer = Buffer.from(arrayBuffer);
    if (buffer.byteLength > MAX_REMOTE_BUFFER) {
      return void 0;
    }
    return {
      buffer,
      contentType: (response.headers.get("content-type") || "").toLowerCase()
    };
  } catch {
    return void 0;
  } finally {
    clearTimeout(timer);
  }
}
async function withTemporaryFile(extension, buffer, task) {
  const tempPath = path3__default.default.join(os__default.default.tmpdir(), `ju-hong-e-security-${Date.now()}-${Math.random().toString(16).slice(2)}${extension}`);
  try {
    await fs6__default.default.writeFile(tempPath, buffer);
    return await task(tempPath);
  } finally {
    await fs6__default.default.rm(tempPath, { force: true });
  }
}
async function readRemoteResourceText(location) {
  const response = await readRemoteBuffer(location);
  if (!response) {
    return "";
  }
  let extension = "";
  try {
    extension = path3__default.default.extname(new URL(location).pathname).toLowerCase();
  } catch {
    extension = "";
  }
  if (IMAGE_EXTENSIONS.has(extension) || isLikelyImageMimeType(response.contentType)) {
    return withTemporaryFile(extension || ".img", response.buffer, readTextViaTesseract);
  }
  if (TEXT_EXTENSIONS.has(extension) || isLikelyTextMimeType(response.contentType)) {
    return limitTextContent(response.buffer.toString("utf8"));
  }
  if (TEXTUTIL_EXTENSIONS.has(extension)) {
    return withTemporaryFile(extension, response.buffer, async (filePath) => await readTextViaTextutil(filePath) || await readTextViaMetadata(filePath));
  }
  return "";
}
async function collectReferencedResourceContents(values, rootDir) {
  const resources = toReferencedResources(values, rootDir);
  const contents = [];
  for (const resource of resources) {
    const content = resource.kind === "local-file" ? await readLocalResourceText(resource.location) : await readRemoteResourceText(resource.location);
    if (!content) {
      continue;
    }
    contents.push({
      location: resource.location,
      value: content
    });
  }
  return contents;
}

// src/platform/request-security/registry.ts
var securityRegistryState = globalThis.__JUHONG_E_SECURITY_REGISTRY__ ?? (globalThis.__JUHONG_E_SECURITY_REGISTRY__ = {
  patternRules: /* @__PURE__ */ new Map(),
  validatorRules: /* @__PURE__ */ new Map()
});
var GLOBAL_PATTERN_RULES = securityRegistryState.patternRules;
var GLOBAL_VALIDATOR_RULES = securityRegistryState.validatorRules;
function resetRegex(pattern) {
  pattern.lastIndex = 0;
  return pattern;
}
function collectStringValues(value) {
  if (typeof value === "string") {
    return value.trim() ? [value] : [];
  }
  if (Array.isArray(value)) {
    return value.flatMap((item) => collectStringValues(item));
  }
  if (value && typeof value === "object") {
    return Object.values(value).flatMap((item) => collectStringValues(item));
  }
  return [];
}
function collectCandidateValues(value, source) {
  return collectStringValues(value).map((entry) => ({
    source,
    value: entry
  }));
}
async function collectSecurityStringValues(payload, options) {
  const directValues = [
    ...collectCandidateValues(payload.input, "input"),
    ...collectCandidateValues(payload.rawCommand, "rawCommand"),
    ...collectCandidateValues(payload.rawArgs, "rawArgs"),
    ...collectCandidateValues(payload.args, "args"),
    ...options.inspectPrompt ? collectCandidateValues(payload.prompt, "prompt") : []
  ];
  if (!options.inspectResources) {
    return directValues;
  }
  const referencedContents = await collectReferencedResourceContents(
    directValues.map((entry) => entry.value),
    payload.promptRootDir
  );
  return [
    ...directValues,
    ...referencedContents.map(
      (entry) => ({
        location: entry.location,
        source: "resource",
        value: entry.value
      })
    )
  ];
}
function getPatternRules(config) {
  return [...GLOBAL_PATTERN_RULES.values(), ...config?.patterns || []];
}
function getValidatorRules(config) {
  return [...GLOBAL_VALIDATOR_RULES.values(), ...config?.validators || []];
}
function addGlobalSecurityPattern(rule) {
  GLOBAL_PATTERN_RULES.set(rule.name, rule);
}
async function validateSecurityPayload(payload, config, options = {
  inspectPrompt: true,
  inspectResources: true,
  mode: "prompt-with-resources"
}) {
  const stringValues = await collectSecurityStringValues(payload, options);
  for (const rule of getPatternRules(config)) {
    const matched = findMatchedCandidate(stringValues, rule);
    if (matched) {
      return {
        detail: {
          location: matched.location,
          matchedText: matched.matchedText,
          source: matched.source
        },
        message: rule.message,
        ok: false,
        ruleName: rule.name
      };
    }
  }
  for (const rule of getValidatorRules(config)) {
    const result = await rule.validate(payload);
    if (result === true) {
      continue;
    }
    return {
      detail: {
        source: payload.prompt ? "prompt" : payload.input ? "input" : "args"
      },
      message: typeof result === "string" && result.trim() ? result : rule.message,
      ok: false,
      ruleName: rule.name
    };
  }
  return {
    ok: true
  };
}
function findMatchedCandidate(stringValues, rule) {
  for (const candidate of stringValues) {
    const matchedText = extractMatchedText(candidate.value, rule);
    if (!matchedText) {
      continue;
    }
    return {
      location: candidate.location,
      matchedText,
      source: candidate.source
    };
  }
  return void 0;
}
function extractMatchedText(value, rule) {
  const match = resetRegex(rule.pattern).exec(value);
  if (!match?.[0]) {
    return "";
  }
  const formattedMatch = rule.formatMatch ? rule.formatMatch(match[0]) : match[0];
  return safeExcerpt(formattedMatch, 120);
}

// src/platform/request-security/default-rules.ts
var initialized = false;
function formatResidentRegistrationNumber(matchedText) {
  const digits = matchedText.replace(/\D/g, "");
  if (digits.length !== 13) {
    return `${matchedText.slice(0, 3)}***`;
  }
  return `${digits.slice(0, 6)}-${digits[6]}******`;
}
function ensureDefaultSecurityRules() {
  if (initialized) {
    return;
  }
  initialized = true;
  addGlobalSecurityPattern({
    formatMatch: formatResidentRegistrationNumber,
    message: "\uBCF4\uC548 \uC815\uCC45\uC5D0 \uC758\uD574 \uC8FC\uBBFC\uB4F1\uB85D\uBC88\uD638 \uD615\uD0DC\uC758 \uAC12\uC774 \uD3EC\uD568\uB41C \uC785\uB825\uC740 \uC2E4\uD589\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
    name: "resident-registration-number",
    pattern: /\b\d{6}[- ]?[1-4]\d{6}\b/
  });
}

// src/platform/request-security/guard.ts
function toSecuritySourceLabel(source, location) {
  switch (source) {
    case "input":
      return "\uC0AC\uC6A9\uC790 \uC785\uB825";
    case "rawCommand":
      return "\uC6D0\uBCF8 \uBA85\uB839\uC5B4";
    case "rawArgs":
      return "\uC6D0\uBCF8 \uBA85\uB839 \uC778\uC790";
    case "args":
      return "\uBA85\uB839 \uC778\uC790";
    case "prompt":
      return "AI \uD504\uB86C\uD504\uD2B8";
    case "resource":
      return location ? `\uCC38\uC870 \uB9AC\uC18C\uC2A4 (${location})` : "\uCC38\uC870 \uB9AC\uC18C\uC2A4";
    default:
      return source;
  }
}
function buildSecurityBlockSections(result, policyModeLabel) {
  const detailLines = [`- policyMode: ${policyModeLabel}`, `- rule: \`${result.ruleName}\``, `- message: ${result.message}`];
  if (result.detail) {
    detailLines.push(`- source: ${toSecuritySourceLabel(result.detail.source, result.detail.location)}`);
    if (result.detail.matchedText) {
      detailLines.push(`- matched: \`${result.detail.matchedText}\``);
    }
  }
  return [
    {
      heading: "Security Block",
      markdown: detailLines.join("\n")
    }
  ];
}
function buildSecurityBlockUserMessage(result, policyModeLabel, errorReportPath) {
  const lines = ["\uBCF4\uC548 \uC815\uCC45\uC5D0 \uC758\uD574 \uC694\uCCAD\uC744 \uC911\uB2E8\uD588\uC2B5\uB2C8\uB2E4.", result.message, `- \uD604\uC7AC \uC815\uCC45: ${policyModeLabel}`, `- \uBCF4\uC548 \uADDC\uCE59: \`${result.ruleName}\``];
  if (result.detail) {
    lines.push(`- \uAC10\uC9C0 \uC704\uCE58: ${toSecuritySourceLabel(result.detail.source, result.detail.location)}`);
    if (result.detail.matchedText) {
      lines.push(`- \uAC10\uC9C0 \uB0B4\uC6A9: \`${result.detail.matchedText}\``);
    }
  }
  if (errorReportPath) {
    lines.push(`- \uC5D0\uB7EC \uB9AC\uD3EC\uD2B8: ${errorReportPath}`);
  }
  return lines.join("\n");
}
async function guardSecurityPayload(options) {
  ensureDefaultSecurityRules();
  const policy = readSecurityPolicy(options.paths);
  const policyModeLabel = describeSecurityPolicyMode(policy.mode);
  if (!isSecurityPolicyEnabled(policy.mode)) {
    options.trace("security:skip", `${options.traceLabel} | ${policy.mode}`);
    return {
      ok: true
    };
  }
  const validationOptions = resolveSecurityValidationOptions(policy.mode);
  const result = await validateSecurityPayload(options.payload, options.config, validationOptions);
  if (!result.ok) {
    options.trace("security:block", `${options.traceLabel} | ${result.ruleName}`);
    const errorReportPath = options.paths ? writeErrorReport(
      options.paths,
      {
        detail: result.detail,
        message: result.message,
        name: "SecurityPolicyBlockedError",
        payload: {
          command: options.payload.command,
          service: options.payload.service
        },
        ruleName: result.ruleName
      },
      {
        extraSections: buildSecurityBlockSections(result, policyModeLabel),
        scope: options.reportScope || `security:${options.traceLabel}`
      }
    ) : void 0;
    const userMessage = buildSecurityBlockUserMessage(result, policyModeLabel, errorReportPath);
    console.error(userMessage);
    return {
      ...result,
      errorReportPath,
      userMessage
    };
  }
  return result;
}

// src/platform/token-optimizer/strip-ansi.ts
var ANSI_REGEX = new RegExp(
  String.raw`\u001B\[[0-9;]*[a-zA-Z]|\u001B\].*?(?:\u0007|\u001B\\)`,
  "g"
);
var stripAnsi = (text) => {
  return text.replace(ANSI_REGEX, "");
};

// src/platform/token-optimizer/token-counter.ts
var countTokens = (text) => {
  if (!text) {
    return 0;
  }
  return text.split(/\s+/).filter(Boolean).length;
};

// src/platform/token-optimizer/truncate.ts
var truncateText = (text, maxLength) => {
  const charCount = [...text].length;
  if (charCount <= maxLength) {
    return text;
  }
  if (maxLength < 3) {
    return "...";
  }
  return [...text].slice(0, maxLength - 3).join("") + "...";
};
var truncateLines = (text, options) => {
  const { maxCharsPerLine, headLines, tailLines, maxLines } = options;
  let lines = text.split("\n");
  if (headLines !== void 0 && tailLines !== void 0 && lines.length > headLines + tailLines) {
    const head = lines.slice(0, headLines);
    const tail = lines.slice(-tailLines);
    const omittedCount = lines.length - headLines - tailLines;
    lines = [...head, `... (${omittedCount}\uC904 \uC0DD\uB7B5)`, ...tail];
  } else if (headLines !== void 0 && lines.length > headLines) {
    const omittedCount = lines.length - headLines;
    lines = [...lines.slice(0, headLines), `... (${omittedCount}\uC904 \uC0DD\uB7B5)`];
  } else if (tailLines !== void 0 && lines.length > tailLines) {
    const omittedCount = lines.length - tailLines;
    lines = [`... (${omittedCount}\uC904 \uC0DD\uB7B5)`, ...lines.slice(-tailLines)];
  }
  if (maxCharsPerLine !== void 0) {
    lines = lines.map((line) => truncateText(line, maxCharsPerLine));
  }
  if (maxLines !== void 0 && lines.length > maxLines) {
    if (maxLines <= 0) {
      return "";
    }
    const preservedLineCount = Math.max(maxLines - 1, 0);
    const omittedCount = lines.length - preservedLineCount;
    lines = preservedLineCount === 0 ? [`... (${omittedCount}\uC904 \uC0DD\uB7B5)`] : [...lines.slice(0, preservedLineCount), `... (${omittedCount}\uC904 \uC0DD\uB7B5)`];
  }
  return lines.join("\n");
};

// src/platform/token-optimizer/line-filter.ts
function matchesLine(pattern, line) {
  const safePattern = pattern.global || pattern.sticky ? new RegExp(pattern.source, pattern.flags) : pattern;
  safePattern.lastIndex = 0;
  return safePattern.test(line);
}
var filterLines = (text, options) => {
  const { keepPatterns, stripPatterns, stripEmptyLines } = options;
  let lines = text.split("\n");
  if (keepPatterns && keepPatterns.length > 0) {
    lines = lines.filter((line) => keepPatterns.some((pattern) => matchesLine(pattern, line)));
  }
  if (stripPatterns && stripPatterns.length > 0) {
    lines = lines.filter((line) => !stripPatterns.some((pattern) => matchesLine(pattern, line)));
  }
  if (stripEmptyLines) {
    lines = lines.filter((line) => line.trim().length > 0);
  }
  return lines.join("\n");
};

// src/platform/token-optimizer/deduplication.ts
var NORMALIZATION_RULES = [
  // ISO 타임스탬프 (2026-04-09T10:00:01.123 또는 2026-04-09 10:00:01)
  [/\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}[.\d]*/g, "<TIMESTAMP>"],
  // 대괄호 타임스탬프 ([10:00:01], [2026-04-09 10:00:01])
  [/\[\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}[.\d]*\]/g, "[<TIMESTAMP>]"],
  // UUID
  [/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi, "<UUID>"],
  // IP 주소
  [/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/g, "<IP>"],
  // 16진수 해시 (7자 이상)
  [/\b[0-9a-f]{7,}\b/gi, "<HEX>"],
  // 큰 숫자 (4자리 이상)
  [/\b\d{4,}\b/g, "<NUM>"]
];
var normalizeLine = (line) => {
  let normalized = line;
  for (const [pattern, replacement] of NORMALIZATION_RULES) {
    normalized = normalized.replace(pattern, replacement);
  }
  return normalized;
};
var deduplicateLines = (text) => {
  const lines = text.split("\n");
  const groups = /* @__PURE__ */ new Map();
  const orderedKeys = [];
  for (const line of lines) {
    if (line.trim().length === 0) {
      const emptyKey = `__EMPTY_${orderedKeys.length}__`;
      groups.set(emptyKey, { count: 1, originalLine: line });
      orderedKeys.push(emptyKey);
      continue;
    }
    const normalized = normalizeLine(line);
    if (groups.has(normalized)) {
      groups.get(normalized).count += 1;
    } else {
      groups.set(normalized, { count: 1, originalLine: line });
      orderedKeys.push(normalized);
    }
  }
  return orderedKeys.map((key) => {
    const group = groups.get(key);
    if (group.count > 1) {
      return `[x${group.count}] ${normalizeLine(group.originalLine)}`;
    }
    return group.originalLine;
  }).join("\n");
};

// src/platform/token-optimizer/optimize.ts
var optimizeText = (text, options = {}) => {
  const originalTokens = countTokens(text);
  if (!text) {
    return { text: "", originalTokens: 0, optimizedTokens: 0, savingsPercent: 0 };
  }
  const {
    stripAnsi: shouldStripAnsi = true,
    maxCharsPerLine,
    maxLines,
    headLines,
    tailLines,
    deduplicate = false,
    keepPatterns,
    stripPatterns,
    stripEmptyLines = true
  } = options;
  let result = shouldStripAnsi ? stripAnsi(text) : text;
  const hasFilterOptions = keepPatterns && keepPatterns.length > 0 || stripPatterns && stripPatterns.length > 0 || stripEmptyLines;
  if (hasFilterOptions) {
    result = filterLines(result, { keepPatterns, stripPatterns, stripEmptyLines });
  }
  if (deduplicate) {
    result = deduplicateLines(result);
  }
  const hasTruncateOptions = maxCharsPerLine !== void 0 || maxLines !== void 0 || headLines !== void 0 || tailLines !== void 0;
  if (hasTruncateOptions) {
    result = truncateLines(result, { maxCharsPerLine, maxLines, headLines, tailLines });
  }
  const optimizedTokens = countTokens(result);
  const savingsPercent = originalTokens > 0 ? Math.round((1 - optimizedTokens / originalTokens) * 1e3) / 10 : 0;
  return {
    text: result,
    originalTokens,
    optimizedTokens,
    savingsPercent
  };
};
function createPromptHistoryReferences(paths) {
  return {
    aiHistoryDirectoryPath: paths.historyDir,
    promptHistoryFilePath: paths.promptHistoryPath
  };
}
function createPromptHistoryReferenceSection(historyReferences) {
  if (!historyReferences) {
    return void 0;
  }
  return {
    heading: "\uD788\uC2A4\uD1A0\uB9AC \uCC38\uC870",
    markdown: [
      "- \uD604\uC7AC \uC694\uCCAD\uC774 \uC774\uC804 \uC791\uC5C5\uC758 \uC5F0\uC7A5, \uC218\uC815, \uD6C4\uC18D \uC9C8\uBB38, \uC0DD\uB7B5\uB41C \uB9E5\uB77D \uBCF5\uC6D0\uCC98\uB7FC \uBCF4\uC774\uBA74 \uC0AC\uC6A9\uC790\uAC00 \uBA85\uC2DC\uD558\uC9C0 \uC54A\uC544\uB3C4 \uBA3C\uC800 \uC544\uB798 \uD788\uC2A4\uD1A0\uB9AC\uB97C \uD655\uC778\uD55C\uB2E4.",
      '- \uC0AC\uC6A9\uC790\uAC00 "\uC774\uC804", "\uBC29\uAE08", "\uC544\uAE4C", "\uACC4\uC18D", "\uADF8\uAC70", "\uADF8 \uBC29\uC2DD", "\uAC19\uC740 \uAE30\uC900"\uCC98\uB7FC \uAE30\uC874 \uB9E5\uB77D\uC744 \uC554\uC2DC\uD558\uBA74 \uC6B0\uC120\uC801\uC73C\uB85C \uD788\uC2A4\uD1A0\uB9AC\uB97C \uC870\uD68C\uD55C\uB2E4.',
      "- \uC694\uCCAD\uB9CC\uC73C\uB85C\uB294 \uC548\uC804\uD55C \uAD6C\uD604 \uACB0\uC815\uC744 \uB0B4\uB9AC\uAE30 \uC5B4\uB835\uAC70\uB098, \uAE30\uC874 \uACB0\uC815/\uC0B0\uCD9C\uBB3C/\uC2E4\uD328 \uC6D0\uC778\uC744 \uC7AC\uC0AC\uC6A9\uD574\uC57C \uD558\uBA74 \uB0B4\uBD80 \uD310\uB2E8\uC73C\uB85C \uD788\uC2A4\uD1A0\uB9AC\uB97C \uBA3C\uC800 \uD655\uC778\uD55C\uB2E4.",
      "- AI\uC758 \uC804\uCCB4 \uD788\uC2A4\uD1A0\uB9AC\uB97C \uC870\uD68C/\uCC38\uC870\uD574\uC57C \uD558\uB294 \uACBD\uC6B0 \uC544\uB798 \uB514\uB809\uD130\uB9AC\uB97C \uC9C1\uC811 \uD655\uC778\uD55C\uB2E4.",
      `- \uC804\uCCB4 AI \uD788\uC2A4\uD1A0\uB9AC \uB514\uB809\uD130\uB9AC: \`${path3__default.default.normalize(historyReferences.aiHistoryDirectoryPath)}\``,
      "- \uC0AC\uC6A9\uC790\uAC00 \uC791\uC131\uD55C \uD504\uB86C\uD504\uD2B8 \uB0B4\uC5ED\uB9CC \uD544\uC694\uD55C \uACBD\uC6B0 \uC544\uB798 \uD30C\uC77C\uC744 \uC9C1\uC811 \uD655\uC778\uD55C\uB2E4.",
      `- \uC0AC\uC6A9\uC790 \uD504\uB86C\uD504\uD2B8 \uD788\uC2A4\uD1A0\uB9AC \uD30C\uC77C: \`${path3__default.default.normalize(historyReferences.promptHistoryFilePath)}\``,
      "- \uD504\uB86C\uD504\uD2B8 \uBCF8\uBB38\uC5D0\uB294 \uACFC\uAC70 \uD788\uC2A4\uD1A0\uB9AC \uB0B4\uC6A9\uC744 \uC9C1\uC811 \uB2E4\uC2DC \uC2E3\uC9C0 \uB9D0\uACE0, \uD544\uC694\uD560 \uB54C \uC704 \uACBD\uB85C\uB97C \uCC38\uC870\uD574 \uBB38\uB9E5\uC744 \uBCF5\uC6D0\uD55C \uB4A4 \uC791\uC5C5\uD55C\uB2E4."
    ].join("\n")
  };
}
function isPromptMarkdownFileReference(asset) {
  return typeof asset !== "string";
}

// src/platform/prompts/render.ts
var TOKEN_OPTIMIZER_PRESET_BY_MODE = {
  chat: {
    stripAnsi: true
  },
  commit: {
    maxCharsPerLine: 400,
    stripAnsi: true,
    stripEmptyLines: true
  },
  "gen-html": {
    stripAnsi: true
  },
  "gen-storybook": {
    stripAnsi: true
  },
  "minify-md": {
    stripAnsi: true
  },
  "talk-to-figma": {
    stripAnsi: true
  },
  review: {
    maxCharsPerLine: 400,
    stripAnsi: true,
    stripEmptyLines: true
  }
};
var COMPACT_WORKSPACE_LIMITS = {
  commit: {
    diffStatLines: 20,
    statusLines: 24
  }
};
function normalizeMarkdown(markdown) {
  return markdown.trim();
}
function renderMarkdownAssetBlocks(markdownAssets) {
  const assets = markdownAssets || [];
  const inlineMarkdownBlocks = assets.filter((asset) => typeof asset === "string").map(normalizeMarkdown).filter(Boolean);
  const fileReferenceBlocks = assets.filter(isPromptMarkdownFileReference).map((asset) => `- \`${asset.filePath.trim()}\``);
  const blocks = [
    inlineMarkdownBlocks.length > 0 ? inlineMarkdownBlocks.join("\n\n") : "",
    fileReferenceBlocks.length > 0 ? fileReferenceBlocks.join("\n") : ""
  ].filter(Boolean);
  if (blocks.length === 0) {
    return "";
  }
  return blocks.join("\n\n");
}
function renderLabeledSection(section) {
  const markdown = normalizeMarkdown(section.markdown);
  if (!markdown) {
    return "";
  }
  return [`[${section.heading}]`, markdown].join("\n");
}
function buildExecutionOptionsSection(prompt) {
  return {
    heading: "\uC2E4\uD589 \uC635\uC158",
    markdown: [
      `- autoYes: ${prompt.autoYes ? "yes" : "no"}`,
      prompt.autoYes ? "- \uAD8C\uD55C \uC694\uCCAD\uC740 \uBCC4\uB3C4 \uD655\uC778 \uC5C6\uC774 yes \uB85C \uCC98\uB9AC\uD55C\uB2E4." : "- \uAD8C\uD55C \uC694\uCCAD\uC740 \uC11C\uBE44\uC2A4 \uAE30\uBCF8 \uC2B9\uC778 \uC815\uCC45\uC744 \uB530\uB978\uB2E4."
    ].join("\n")
  };
}
function limitLines(lines, maxLines) {
  if (lines.length <= maxLines) {
    return lines;
  }
  return [...lines.slice(0, maxLines), `... (${lines.length - maxLines}\uC904 \uC0DD\uB7B5)`];
}
function renderWorkspaceSnapshotMarkdown(prompt) {
  return prompt.workspaceSnapshot.available ? [
    `Git Root: ${prompt.workspaceSnapshot.gitRoot}`,
    `Branch: ${prompt.workspaceSnapshot.branch || "(detached)"}`,
    "",
    "[git status --short]",
    prompt.workspaceSnapshot.statusLines.join("\n") || "(\uC5C6\uC74C)",
    "",
    "[git diff --stat]",
    prompt.workspaceSnapshot.diffStat || "(\uC5C6\uC74C)",
    "",
    "[\uCD5C\uADFC \uCEE4\uBC0B]",
    prompt.workspaceSnapshot.recentCommits.join("\n") || "(\uC5C6\uC74C)"
  ].join("\n") : prompt.workspaceSnapshot.note;
}
function renderCompactWorkspaceSnapshotMarkdown(prompt, mode) {
  if (!prompt.workspaceSnapshot.available) {
    return "";
  }
  if (mode === "review" || mode === "gen-html" || mode === "gen-storybook" || mode === "minify-md" || mode === "talk-to-figma") {
    return "";
  }
  if (mode === "commit") {
    const compactStatusLines = limitLines(
      prompt.workspaceSnapshot.statusLines,
      COMPACT_WORKSPACE_LIMITS.commit.statusLines
    );
    const compactDiffStatLines = limitLines(
      prompt.workspaceSnapshot.diffStat.split("\n").filter(Boolean),
      COMPACT_WORKSPACE_LIMITS.commit.diffStatLines
    );
    return [
      `- Branch: ${prompt.workspaceSnapshot.branch || "(detached)"}`,
      "",
      "[\uBCC0\uACBD \uD30C\uC77C \uC0C1\uD0DC]",
      compactStatusLines.join("\n") || "(\uC5C6\uC74C)",
      "",
      "[\uBCC0\uACBD \uC694\uC57D]",
      compactDiffStatLines.join("\n") || "(\uC5C6\uC74C)"
    ].join("\n");
  }
  return renderWorkspaceSnapshotMarkdown(prompt);
}
function shouldUseCompactStructuredRender(mode) {
  return !!mode && mode !== "chat";
}
function toPromptSections(prompt, options = {}) {
  const historyReferenceSection = createPromptHistoryReferenceSection(prompt.historyReferences);
  const workspaceMarkdown = options.compact ? renderCompactWorkspaceSnapshotMarkdown(prompt, options.mode) : renderWorkspaceSnapshotMarkdown(prompt);
  const sections = [
    ...options.compact ? [] : [buildExecutionOptionsSection(prompt)],
    {
      heading: "\uC9C0\uCE68 - \uBC18\uB4DC\uC2DC \uC77D\uACE0 \uADF8\uB300\uB85C \uC9C0\uCF1C\uC57C\uD560\uAC83",
      markdown: renderMarkdownAssetBlocks(prompt.instructions)
    },
    ...historyReferenceSection ? [historyReferenceSection] : [],
    ...normalizeMarkdown(workspaceMarkdown) ? [
      {
        heading: "\uD604\uC7AC \uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uC0C1\uD0DC",
        markdown: workspaceMarkdown
      }
    ] : [],
    {
      heading: "\uADDC\uCE59 - \uC774\uD558 \uB0B4\uC6A9\uC774 \uC5C6\uC73C\uBA74 \uBB34\uC2DC\uD558\uACE0, \uC801\uC6A9\uC5EC\uBD80\uB098 \uC801\uC6A9\uC870\uAC74\uC740 [\uC9C0\uCE68]\uC758 \uB0B4\uC6A9\uC744 \uB530\uB978\uB2E4.",
      markdown: renderMarkdownAssetBlocks(prompt.rules)
    },
    {
      heading: "\uC751\uB2F5 \uC591\uC2DD  - \uC774\uD558 \uB0B4\uC6A9\uC774 \uC5C6\uC73C\uBA74 \uBB34\uC2DC\uD558\uACE0, \uC801\uC6A9\uC5EC\uBD80\uB098 \uC801\uC6A9\uC870\uAC74\uC740 [\uC9C0\uCE68]\uC758 \uB0B4\uC6A9\uC744 \uB530\uB978\uB2E4.",
      markdown: renderMarkdownAssetBlocks(prompt.forms)
    },
    ...prompt.sections || []
  ];
  return sections.filter((section) => normalizeMarkdown(section.markdown));
}
function renderStructuredPrompt(prompt, mode, compact = false) {
  return [
    `# ${prompt.title}`,
    ...compact ? [] : ["", `\uD604\uC7AC \uC120\uD0DD\uB41C AI \uC11C\uBE44\uC2A4: ${prompt.service}`],
    ...toPromptSections(prompt, { compact, mode }).flatMap((section) => ["", renderLabeledSection(section)])
  ].join("\n");
}
function getUtf8ByteLength(text) {
  return Buffer.byteLength(text, "utf8");
}
function buildPromptOptimizationAudit(mode, originalPrompt, optimizedPrompt) {
  const originalBytes = getUtf8ByteLength(originalPrompt);
  const optimizedBytes = getUtf8ByteLength(optimizedPrompt.text);
  const reducedBytes = originalBytes - optimizedBytes;
  const reductionPercent = originalBytes > 0 ? Math.round(reducedBytes / originalBytes * 1e3) / 10 : 0;
  const originalEstimatedTokens = countTokens(originalPrompt);
  const reducedEstimatedTokens = originalEstimatedTokens - optimizedPrompt.optimizedTokens;
  const tokenReductionPercent = originalEstimatedTokens > 0 ? Math.round(reducedEstimatedTokens / originalEstimatedTokens * 1e3) / 10 : 0;
  return {
    mode,
    optimizedBytes,
    optimizedEstimatedTokens: optimizedPrompt.optimizedTokens,
    optimizedPrompt: optimizedPrompt.text,
    originalBytes,
    originalEstimatedTokens,
    originalPrompt,
    reducedBytes,
    reducedEstimatedTokens,
    reductionPercent,
    tokenReductionPercent
  };
}
function optimizeRenderedPrompt(prompt, mode, originalPrompt) {
  if (!mode || !isTokenOptimizerEnabled()) {
    return {
      text: prompt
    };
  }
  const optimizedPrompt = optimizeText(prompt, TOKEN_OPTIMIZER_PRESET_BY_MODE[mode]);
  return {
    promptAudit: buildPromptOptimizationAudit(mode, originalPrompt || prompt, optimizedPrompt),
    text: optimizedPrompt.text
  };
}
function renderPromptForService(prompt, mode) {
  if (typeof prompt === "string") {
    return optimizeRenderedPrompt(safeExcerpt(prompt, 2e5), mode);
  }
  const originalPrompt = renderStructuredPrompt(prompt, mode, false);
  const shouldCompact = isTokenOptimizerEnabled() && shouldUseCompactStructuredRender(mode);
  const renderedPrompt = shouldCompact ? renderStructuredPrompt(prompt, mode, true) : originalPrompt;
  return optimizeRenderedPrompt(renderedPrompt, mode, originalPrompt);
}

// src/platform/ai-services/internal/shared.ts
var ACCOUNT_DEFAULT_MODEL = "account-default";
var SERVICE_FALLBACK_MODELS = {
  claude: [ACCOUNT_DEFAULT_MODEL, "haiku", "sonnet"],
  codex: [ACCOUNT_DEFAULT_MODEL, "gpt-5"],
  gemini: [ACCOUNT_DEFAULT_MODEL, "flash", "auto"]
};
var CAPACITY_FAILURE_PATTERNS = [
  /exhausted your capacity/i,
  /\bquota\b/i,
  /rate[- ]limit/i,
  /resource exhausted/i,
  /too many requests/i
];
function quoteArgs(args) {
  return args.map((arg) => shellQuote(arg)).join(" ");
}
function formatAttemptPreviewHeading(attempt, index) {
  return index === 0 ? `# \uCD5C\uCD08 \uC2E4\uD589 (${attempt.label})` : `# \uD3F4\uBC31 ${index} (${attempt.label})`;
}
function formatServiceCommandPreview(command, attempts) {
  return attempts.map((attempt, index) => [formatAttemptPreviewHeading(attempt, index), `${command} ${quoteArgs(attempt.args)}`].join("\n")).join("\n\n");
}
function toUnique(values) {
  const seen = /* @__PURE__ */ new Set();
  return values.filter((value) => {
    if (!value || seen.has(value)) {
      return false;
    }
    seen.add(value);
    return true;
  });
}
function buildServiceModelCandidates(service, preferredModel) {
  const fallbackModels = SERVICE_FALLBACK_MODELS[service];
  return toUnique(preferredModel ? [preferredModel, ...fallbackModels] : fallbackModels);
}
function isAccountDefaultModel(model) {
  return model === ACCOUNT_DEFAULT_MODEL;
}
function classifyServiceFailureKind(stderr, stdout) {
  const combinedOutput = `${stderr}
${stdout}`;
  return CAPACITY_FAILURE_PATTERNS.some((pattern) => pattern.test(combinedOutput)) ? "capacity" : "generic";
}
function formatServiceAttemptMessage(baseMessage, attempt, index, total) {
  return `${baseMessage} (${attempt.label}, ${index + 1}/${total})`;
}
function formatServiceFallbackMessage(service, failedAttempt, nextAttempt, failureKind) {
  if (failureKind === "capacity") {
    return `${service} ${failedAttempt.label} \uC0AC\uC6A9\uB7C9 \uD55C\uB3C4\uC5D0 \uB3C4\uB2EC\uD588\uC2B5\uB2C8\uB2E4. ${nextAttempt.label} \uB85C \uC804\uD658\uD569\uB2C8\uB2E4.`;
  }
  return `${failedAttempt.label} \uC2DC\uB3C4\uAC00 \uC2E4\uD328\uD574 ${nextAttempt.label} \uB85C \uC804\uD658\uD569\uB2C8\uB2E4.`;
}
function createServiceCommandSpec(command, attempts, promptAudit) {
  const normalizedAttempts = attempts.map(({ args, label, modelName, outputProtocol, stdoutCaptureMode }) => ({
    args,
    label,
    modelName,
    outputProtocol: outputProtocol || "plain-text",
    stdoutCaptureMode,
    preview: `${command} ${quoteArgs(args)}`
  }));
  return {
    attempts: normalizedAttempts,
    command,
    promptAudit,
    preview: formatServiceCommandPreview(command, normalizedAttempts)
  };
}

// src/platform/ai-services/builders/claude.ts
function normalizeClaudeEffort(effort) {
  if (effort === "minimal") {
    return "low";
  }
  return effort;
}
function buildClaudeArgs(prompt, autoYes, streamOutputEnabled, effort, model) {
  const args = ["--permission-mode", autoYes ? "bypassPermissions" : "acceptEdits"];
  if (effort) {
    args.push("--effort", effort);
  }
  if (model) {
    args.push("--model", model);
  }
  if (streamOutputEnabled) {
    args.push("--verbose", "--output-format", "stream-json", "--include-partial-messages");
  }
  args.push("-p", prompt);
  return args;
}
function buildClaudeCommand(prompt, mode, parsedArgs, autoYes = false, streamOutputEnabled = false) {
  const renderedPrompt = renderPromptForService(prompt, mode);
  const effort = parsedArgs.reasoningEffort ? normalizeClaudeEffort(parsedArgs.reasoningEffort) : void 0;
  const modelCandidates = buildServiceModelCandidates("claude", parsedArgs.model);
  const outputProtocol = streamOutputEnabled ? "claude-stream-json" : "plain-text";
  const attempts = modelCandidates.map((model) => ({
    args: buildClaudeArgs(renderedPrompt.text, autoYes, streamOutputEnabled, effort, isAccountDefaultModel(model) ? void 0 : model),
    label: `model:${model}`,
    modelName: model,
    outputProtocol
  }));
  return createServiceCommandSpec("claude", attempts, renderedPrompt.promptAudit);
}

// src/platform/ai-services/builders/codex.ts
function buildCodexArgs(prompt, autoYes, streamOutputEnabled, reasoningEffort, model) {
  const args = autoYes ? ["exec", "-c", 'approval_policy="never"', "-s", "workspace-write"] : ["exec", "--full-auto"];
  if (model) {
    args.push("--model", model);
  }
  if (reasoningEffort) {
    args.push("-c", `model_reasoning_effort="${reasoningEffort}"`);
  }
  if (streamOutputEnabled) {
    args.push("--json");
  }
  args.push(prompt);
  return args;
}
function buildCodexCommand(prompt, mode, parsedArgs, autoYes = false, streamOutputEnabled = false) {
  const renderedPrompt = renderPromptForService(prompt, mode);
  const effort = parsedArgs.reasoningEffort;
  const modelCandidates = buildServiceModelCandidates("codex", parsedArgs.model);
  const outputProtocol = streamOutputEnabled ? "codex-stream-json" : "plain-text";
  const stdoutCaptureMode = streamOutputEnabled ? "codex-last-message-file" : void 0;
  const attempts = modelCandidates.map((model) => ({
    args: buildCodexArgs(
      renderedPrompt.text,
      autoYes,
      streamOutputEnabled,
      effort,
      isAccountDefaultModel(model) ? void 0 : model
    ),
    label: `model:${model}`,
    modelName: model,
    outputProtocol,
    stdoutCaptureMode
  }));
  return createServiceCommandSpec("codex", attempts, renderedPrompt.promptAudit);
}

// src/platform/ai-services/builders/gemini.ts
function buildGeminiArgs(prompt, autoYes, streamOutputEnabled, model) {
  const args = ["--approval-mode", autoYes ? "yolo" : "auto_edit", "--sandbox"];
  if (streamOutputEnabled) {
    args.push("--output-format", "stream-json", "--raw-output", "--accept-raw-output-risk");
  }
  if (!model) {
    args.push("-p", prompt);
    return args;
  }
  args.push("--model", model, "-p", prompt);
  return args;
}
function buildGeminiCommand(prompt, mode, parsedArgs, autoYes = false, streamOutputEnabled = false) {
  const renderedPrompt = renderPromptForService(prompt, mode);
  const modelCandidates = buildServiceModelCandidates("gemini", parsedArgs.model);
  const outputProtocol = streamOutputEnabled ? "gemini-stream-json" : "plain-text";
  const attempts = modelCandidates.map((model) => ({
    args: buildGeminiArgs(renderedPrompt.text, autoYes, streamOutputEnabled, isAccountDefaultModel(model) ? void 0 : model),
    label: `model:${model}`,
    modelName: model,
    outputProtocol
  }));
  return createServiceCommandSpec("gemini", attempts, renderedPrompt.promptAudit);
}

// src/platform/ai-services/internal/build-service-command.ts
var SERVICE_COMMAND_BUILDERS = {
  [AI_SERVICE.CODEX]: buildCodexCommand,
  [AI_SERVICE.GEMINI]: buildGeminiCommand,
  [AI_SERVICE.CLAUDE]: buildClaudeCommand
};
function buildServiceCommand(options) {
  return SERVICE_COMMAND_BUILDERS[options.service](
    options.prompt,
    options.mode,
    options.parsedArgs,
    options.autoYes,
    options.streamOutputEnabled
  );
}
var SERVICE_BINARY_NAMES = {
  [AI_SERVICE.CODEX]: "codex",
  [AI_SERVICE.GEMINI]: "gemini",
  [AI_SERVICE.CLAUDE]: "claude"
};
var SERVICE_INSTALL_PACKAGES = {
  [AI_SERVICE.CODEX]: "@openai/codex",
  [AI_SERVICE.GEMINI]: "@google/gemini-cli",
  [AI_SERVICE.CLAUDE]: "@anthropic-ai/claude-code"
};
function getBinaryName(service) {
  return SERVICE_BINARY_NAMES[service];
}
function getInstallPackageName(service) {
  return SERVICE_INSTALL_PACKAGES[service];
}
function isCliAvailable(service, trace) {
  const binaryName = getBinaryName(service);
  trace("cli-check:start", `${service} -> ${binaryName} --version`);
  const result = child_process.spawnSync(binaryName, ["--version"], {
    encoding: "utf8",
    maxBuffer: 1024 * 1024 * 2,
    timeout: 1e4
  });
  if (result.error || result.status !== 0) {
    trace("cli-check:missing", getErrorSummary(result.error || result.stderr || result.status));
    return false;
  }
  trace("cli-check:ok", `${service}`);
  return true;
}
function installCli(service, trace) {
  const packageName = getInstallPackageName(service);
  trace("cli-install:start", `${service} -> ${packageName}`);
  const result = child_process.spawnSync("npm", ["install", "-g", packageName], {
    encoding: "utf8",
    maxBuffer: 1024 * 1024 * 20,
    stdio: "inherit"
  });
  if (result.error || result.status !== 0) {
    trace("cli-install:failed", getErrorSummary(result.error || result.stderr || result.status));
    throw new Error(`${service} CLI \uC124\uCE58\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4. package=${packageName}`);
  }
  trace("cli-install:done", `${service}`);
}
function ensureServiceCli(service, parsedArgs, trace) {
  if (isCliAvailable(service, trace)) {
    return true;
  }
  if (parsedArgs.testMode) {
    trace("cli-install:skip:test-mode", service);
    return false;
  }
  installCli(service, trace);
  return isCliAvailable(service, trace);
}
function prepareCodexLastMessageCapture(args) {
  const tempDir = fs3__default.default.mkdtempSync(path3__default.default.join(os__default.default.tmpdir(), "ju-hong-e-codex-"));
  const capturePath = path3__default.default.join(tempDir, "last-message.txt");
  return {
    args: [...args, "--output-last-message", capturePath],
    finalizeStdout: (currentStdout) => {
      try {
        if (!fs3__default.default.existsSync(capturePath)) {
          return currentStdout;
        }
        return fs3__default.default.readFileSync(capturePath, "utf8");
      } catch {
        return currentStdout;
      }
    },
    cleanup: () => {
      try {
        fs3__default.default.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 truncateText2(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 truncateText2(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 truncateText2(normalizeWhitespace(commandValue));
  }
  const textValue = pickFirstString(record, ["q", "query", "prompt", "text", "description", "label", "name"]);
  if (textValue) {
    return truncateText2(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/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 = child_process.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__default.default.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;
}
var DEFAULT_STREAM_OUTPUT_STATE = {
  enabled: false
};
var streamOutputRuntimeState = globalThis.__JU_HONG_E_STREAM_OUTPUT_STATE__ ?? (globalThis.__JU_HONG_E_STREAM_OUTPUT_STATE__ = {
  ...DEFAULT_STREAM_OUTPUT_STATE
});
function normalizeStreamOutputState(value) {
  if (!value || typeof value !== "object") {
    return { ...DEFAULT_STREAM_OUTPUT_STATE };
  }
  const enabled = "enabled" in value ? Boolean(value.enabled) : DEFAULT_STREAM_OUTPUT_STATE.enabled;
  return {
    enabled
  };
}
function readStreamOutputConfig(paths) {
  if (!fs3__default.default.existsSync(paths.streamOutputConfigPath)) {
    return { ...DEFAULT_STREAM_OUTPUT_STATE };
  }
  try {
    const parsed = JSON.parse(fs3__default.default.readFileSync(paths.streamOutputConfigPath, "utf8"));
    return normalizeStreamOutputState(parsed);
  } catch {
    return { ...DEFAULT_STREAM_OUTPUT_STATE };
  }
}
function hydrateStreamOutputState(paths) {
  const nextState = readStreamOutputConfig(paths);
  streamOutputRuntimeState.enabled = nextState.enabled;
  return streamOutputRuntimeState.enabled;
}

// src/platform/ai-services/index.ts
async function runAIService(options) {
  const streamOutputEnabled = Boolean(options.forceStreamOutput) || hydrateStreamOutputState(options.paths);
  const securityResult = await guardSecurityPayload({
    paths: options.paths,
    payload: {
      args: [],
      command: options.mode,
      input: "",
      prompt: options.prompt,
      promptRootDir: options.paths.rootDir,
      rawArgs: "",
      rawCommand: "",
      service: options.service
    },
    reportScope: `security:service:${options.mode}`,
    trace: options.trace,
    traceLabel: `service:${options.mode}`
  });
  if (!securityResult.ok) {
    options.trace("service-command:blocked", options.mode);
    return {
      blocked: true,
      cliAvailable: true,
      exitCode: 0,
      promptAudit: void 0,
      preview: "",
      service: options.service,
      skipped: true,
      stderr: "",
      streamedOutput: false,
      stdout: securityResult.userMessage || ""
    };
  }
  const cliAvailable = ensureServiceCli(options.service, options.parsedArgs, options.trace);
  hydrateTokenOptimizerState(options.paths);
  const commandSpec = buildServiceCommand({
    autoYes: options.autoYes,
    mode: options.mode,
    parsedArgs: options.parsedArgs,
    prompt: options.prompt,
    service: options.service,
    streamOutputEnabled
  });
  options.trace("service-command:prepared", commandSpec.preview);
  if (options.parsedArgs.testMode || !cliAvailable) {
    options.trace("service-command:skipped", options.parsedArgs.testMode ? "test-mode" : "cli-missing");
    return {
      blocked: false,
      cliAvailable,
      exitCode: 0,
      promptAudit: commandSpec.promptAudit,
      preview: commandSpec.preview,
      service: options.service,
      skipped: true,
      stderr: "",
      streamedOutput: false,
      stdout: [
        "[TEST MODE] \uC2E4\uC81C AI \uD638\uCD9C\uC740 \uC0DD\uB7B5\uB418\uC5C8\uC2B5\uB2C8\uB2E4.",
        "",
        `service: ${options.service}`,
        `cliAvailable: ${cliAvailable}`,
        "",
        "\uC0DD\uC131\uB420 \uBA85\uB839\uC5B4 \uBBF8\uB9AC\uBCF4\uAE30:",
        commandSpec.preview
      ].join("\n")
    };
  }
  options.trace("service-command:exec:start", `attempts=${commandSpec.attempts.length}`);
  const failures = [];
  for (const [index, attempt] of commandSpec.attempts.entries()) {
    const attemptOrder = `${index + 1}/${commandSpec.attempts.length}`;
    const attemptMessageBase = (streamOutputEnabled ? options.streamingMessage : options.loadingMessage) || `${options.service} \uC751\uB2F5\uC744 \uAE30\uB2E4\uB9AC\uB294 \uC911\uC785\uB2C8\uB2E4`;
    const attemptMessage = formatServiceAttemptMessage(attemptMessageBase, attempt, index, commandSpec.attempts.length);
    options.trace("service-command:attempt:start", `${attemptOrder} ${attempt.label}`);
    let result;
    try {
      const executeAttempt = () => executeServiceCommandAttempt(commandSpec.command, attempt, options.trace, {
        abortSignal: options.abortSignal,
        enabled: streamOutputEnabled,
        manageStdin: options.manageStdin,
        onChunk: options.onStreamChunk,
        writeToTerminal: options.writeStreamOutputToTerminal ?? true
      });
      if (options.status) {
        if (streamOutputEnabled) {
          options.status.step(attemptMessage);
          result = await executeAttempt();
        } else {
          result = await options.status.track(attemptMessage, executeAttempt);
        }
      } else {
        result = await executeAttempt();
      }
    } catch (error) {
      if (isUserCancelledError(error) || isUserTerminatedError(error)) {
        options.trace(
          isUserTerminatedError(error) ? "service-command:terminated" : "service-command:cancelled",
          `${attemptOrder} ${attempt.label}`
        );
      }
      throw error;
    }
    options.trace(
      "service-command:attempt:end",
      `${attemptOrder} ${attempt.label} status=${result.status ?? "spawn-error"}`
    );
    if (result.status === 0) {
      options.trace("service-command:exec:end", `status=0 attempt=${attemptOrder} ${attempt.label}`);
      return {
        blocked: false,
        cliAvailable,
        exitCode: result.status ?? 0,
        promptAudit: commandSpec.promptAudit,
        preview: commandSpec.preview,
        service: options.service,
        skipped: false,
        stderr: result.stderr || "",
        streamedOutput: result.streamedOutput,
        stdout: result.stdout || ""
      };
    }
    const failureKind = classifyServiceFailureKind(result.stderr, result.stdout);
    failures.push({ attempt, failureKind, result });
    options.trace(
      "service-command:attempt:failed",
      `${attemptOrder} ${attempt.label} kind=${failureKind} ${safeExcerpt(result.stderr || result.stdout || "Unknown failure", 240)}`
    );
    const nextAttempt = commandSpec.attempts[index + 1];
    if (nextAttempt && options.status) {
      options.status.step(formatServiceFallbackMessage(options.service, attempt, nextAttempt, failureKind));
    }
  }
  options.trace("service-command:exec:end", `status=${failures.at(-1)?.result.status ?? 1}`);
  throw createAttemptFailureError(options.service, failures);
}

// src/platform/actions/shared.ts
function captureActionContext(paths) {
  return {
    historyContext: loadRecentHistoryContext(paths),
    historyReferences: createPromptHistoryReferences(paths),
    workspaceBefore: captureWorkspaceSnapshot(paths.rootDir)
  };
}
function finalizeAction(paths, context, result) {
  const extraSections = [...result.extraSections || [], ...buildPromptAuditSections(result.promptAudit)];
  const workspaceAfter = captureWorkspaceSnapshot(paths.rootDir);
  const workspaceDelta = diffWorkspaceSnapshots(context.workspaceBefore, workspaceAfter);
  const historyPath = writeTurnHistory(paths, {
    extraSections,
    historyContext: context.historyContext,
    input: result.input,
    output: result.output,
    previewCommand: result.previewCommand,
    scope: result.scope,
    service: result.service,
    skipped: result.skipped,
    title: result.title,
    workspaceAfter,
    workspaceBefore: context.workspaceBefore,
    workspaceDelta
  });
  appendConversationHistory(paths, {
    input: result.input,
    output: result.output,
    scope: result.scope,
    service: result.service,
    summary: result.summary,
    title: result.title
  });
  return {
    historyPath,
    previewCommand: result.previewCommand,
    scope: result.scope,
    service: result.service,
    skipped: result.skipped,
    summary: result.summary,
    title: result.title,
    traceMessages: []
  };
}
function formatAuditNumber(value) {
  return value.toLocaleString("ko-KR");
}
function buildPromptAuditSections(promptAudit) {
  if (!promptAudit) {
    return [];
  }
  return [
    {
      heading: "\uD504\uB86C\uD504\uD2B8 \uCD5C\uC801\uD654 \uC694\uC57D",
      markdown: [
        `- mode: \`${promptAudit.mode}\``,
        `- \uCD5C\uC801\uD654 \uC804 \uD504\uB86C\uD504\uD2B8 \uD06C\uAE30: \`${formatAuditNumber(promptAudit.originalBytes)} bytes\``,
        `- \uCD5C\uC801\uD654 \uD6C4 \uD504\uB86C\uD504\uD2B8 \uD06C\uAE30: \`${formatAuditNumber(promptAudit.optimizedBytes)} bytes\``,
        `- \uAC10\uC18C\uD55C \uD504\uB86C\uD504\uD2B8 \uD06C\uAE30: \`${formatAuditNumber(promptAudit.reducedBytes)} bytes\``,
        `- \uAC10\uC18C \uBE44\uC728: \`${promptAudit.reductionPercent}%\``,
        `- \uC608\uC0C1 \uD1A0\uD070(\uC804 -> \uD6C4): \`${formatAuditNumber(promptAudit.originalEstimatedTokens)} -> ${formatAuditNumber(promptAudit.optimizedEstimatedTokens)}\``,
        `- \uAC10\uC18C\uD55C \uC608\uC0C1 \uD1A0\uD070: \`${formatAuditNumber(promptAudit.reducedEstimatedTokens)}\``,
        `- \uC608\uC0C1 \uD1A0\uD070 \uAC10\uC18C \uBE44\uC728: \`${promptAudit.tokenReductionPercent}%\``
      ].join("\n")
    },
    {
      heading: "\uD504\uB86C\uD504\uD2B8 \uCD5C\uC801\uD654 \uC804",
      markdown: formatCodeBlock(promptAudit.originalPrompt)
    },
    {
      heading: "\uD504\uB86C\uD504\uD2B8 \uCD5C\uC801\uD654 \uD6C4",
      markdown: formatCodeBlock(promptAudit.optimizedPrompt)
    }
  ];
}
function formatDependencyMarkdown(dependencies) {
  const lines = Object.entries(dependencies).map(([name, version]) => `- ${name}: \`${version}\``);
  return lines.length > 0 ? lines.join("\n") : "- (\uC5C6\uC74C)";
}
async function runAIServiceWithStatus(options) {
  return runAIService({
    abortSignal: options.abortSignal,
    autoYes: options.autoYes,
    forceStreamOutput: options.forceStreamOutput,
    loadingMessage: options.loadingMessage,
    manageStdin: options.manageStdin,
    mode: options.mode,
    onStreamChunk: options.onStreamChunk,
    parsedArgs: options.parsedArgs,
    paths: options.paths,
    prompt: options.prompt,
    service: options.service,
    status: options.status,
    streamingMessage: options.streamingMessage,
    writeStreamOutputToTerminal: options.writeStreamOutputToTerminal,
    trace: options.trace
  });
}
function printBufferedAIOutput(output, result, fallback = "(\uC751\uB2F5 \uC5C6\uC74C)") {
  if (result.streamedOutput) {
    return;
  }
  console.log(output || fallback);
}

exports.captureActionContext = captureActionContext;
exports.finalizeAction = finalizeAction;
exports.formatDependencyMarkdown = formatDependencyMarkdown;
exports.printBufferedAIOutput = printBufferedAIOutput;
exports.runAIServiceWithStatus = runAIServiceWithStatus;
