import fs2 from 'node:fs';
import path2 from 'node:path';
import { execSync } from 'node:child_process';
import { inspect } from 'node:util';

// src/platform/core/helpers.ts
function runGitCommand(rootDir, command) {
  return 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 normalizePromptPathInput(value) {
  let normalized = value.trim();
  while (normalized.length >= 2 && (normalized.startsWith("`") && normalized.endsWith("`") || normalized.startsWith('"') && normalized.endsWith('"') || normalized.startsWith("'") && normalized.endsWith("'"))) {
    normalized = normalized.slice(1, -1).trim();
  }
  return normalized;
}
function stringifyUnknown(value) {
  if (value === void 0 || value === null) {
    return "";
  }
  if (typeof value === "string") {
    return value;
  }
  if (Buffer.isBuffer(value)) {
    return value.toString("utf8");
  }
  if (value instanceof Error) {
    return value.stack || value.message;
  }
  return inspect(value, { depth: 6, breakLength: 120 });
}
function isNodeError(error) {
  return error instanceof Error && typeof error.code === "string";
}
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 getDashedFileTimestamp(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 PROMPT_HISTORY_LIMIT = 100;
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()
  };
  fs2.appendFileSync(paths.conversationHistoryPath, `${JSON.stringify(normalizedEntry)}
`, "utf8");
  return normalizedEntry;
}
function loadConversationHistory(paths, limit = DEFAULT_HISTORY_LIMIT) {
  if (!fs2.existsSync(paths.conversationHistoryPath)) {
    return [];
  }
  const lines = fs2.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);
}
function readSavedService(paths) {
  if (!fs2.existsSync(paths.serviceFilePath)) {
    return "";
  }
  const service = fs2.readFileSync(paths.serviceFilePath, "utf8").trim();
  return aiServicesRef.includes(service) ? service : "";
}
function saveService(paths, service) {
  fs2.writeFileSync(paths.serviceFilePath, `${service}
`, "utf8");
}
function loadPromptHistory(paths, limit = PROMPT_HISTORY_LIMIT) {
  if (!fs2.existsSync(paths.promptHistoryPath)) {
    return [];
  }
  try {
    const parsed = JSON.parse(fs2.readFileSync(paths.promptHistoryPath, "utf8"));
    if (!Array.isArray(parsed)) {
      return [];
    }
    return parsed.filter((entry) => typeof entry === "string").map((entry) => entry.trim()).filter(Boolean).slice(-limit);
  } catch {
    return [];
  }
}
function savePromptHistory(paths, history) {
  const normalized = history.map((entry) => entry.trim()).filter(Boolean).slice(-100);
  fs2.writeFileSync(paths.promptHistoryPath, JSON.stringify(normalized, null, 2), "utf8");
}
function appendPromptHistory(paths, value) {
  const normalizedValue = value.trim();
  if (!normalizedValue) {
    return loadPromptHistory(paths);
  }
  const existing = loadPromptHistory(paths).filter((entry) => entry !== normalizedValue);
  const nextHistory = [...existing, normalizedValue].slice(-100);
  savePromptHistory(paths, nextHistory);
  return nextHistory;
}

// src/platform/types/app.ts
var AI_SERVICE = {
  CLAUDE: "claude",
  CODEX: "codex",
  GEMINI: "gemini"
};

// src/platform/core/figma-helpers.ts
var DIRECT_NODE_ID_PATTERN = /^\d+[:-]\d+$/;
var FIGMA_QUERY_NODE_ID_KEYS = ["node-id", "nodeId"];
var SUPPORTED_FIGMA_ROUTE_PREFIXES = /* @__PURE__ */ new Set(["design", "file", "proto"]);
function normalizeFigmaNodeId(nodeId) {
  return decodeURIComponent(nodeId).trim().replace(/-/g, ":");
}
function readFigmaNodeId(url) {
  for (const key of FIGMA_QUERY_NODE_ID_KEYS) {
    const queryValue = url.searchParams.get(key);
    if (queryValue) {
      return queryValue;
    }
  }
  const hashParams = new URLSearchParams(url.hash.startsWith("#") ? url.hash.slice(1) : url.hash);
  for (const key of FIGMA_QUERY_NODE_ID_KEYS) {
    const hashValue = hashParams.get(key);
    if (hashValue) {
      return hashValue;
    }
  }
  return "";
}
function readFigmaFileKeys(url) {
  const segments = url.pathname.split("/").filter(Boolean);
  const routePrefix = segments[0];
  if (!routePrefix || !SUPPORTED_FIGMA_ROUTE_PREFIXES.has(routePrefix) || !segments[1]) {
    return {
      branchKey: "",
      fileKey: "",
      resolvedFileKey: ""
    };
  }
  const fileKey = segments[1];
  const branchKey = segments[2] === "branch" && segments[3] ? segments[3] : "";
  return {
    branchKey,
    fileKey,
    resolvedFileKey: branchKey || fileKey
  };
}
function parseFigmaAddress(sourceAddress) {
  const originalAddress = sourceAddress.trim();
  const parsed = {
    originalAddress,
    parseNotes: []
  };
  if (!originalAddress) {
    parsed.parseNotes.push("\uC785\uB825\uAC12\uC774 \uBE44\uC5B4 \uC788\uC5B4 Figma \uC8FC\uC18C\uB97C \uD30C\uC2F1\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.");
    return parsed;
  }
  if (DIRECT_NODE_ID_PATTERN.test(originalAddress)) {
    parsed.nodeId = originalAddress;
    parsed.normalizedNodeId = normalizeFigmaNodeId(originalAddress);
    parsed.parseNotes.push("URL \uB300\uC2E0 node id \uC9C1\uC811 \uC785\uB825\uC73C\uB85C \uD574\uC11D\uD588\uC2B5\uB2C8\uB2E4.");
    return parsed;
  }
  let url;
  try {
    url = new URL(originalAddress);
  } catch {
    parsed.parseNotes.push("\uC720\uD6A8\uD55C URL\uB85C \uD574\uC11D\uB418\uC9C0 \uC54A\uC544 \uC6D0\uBCF8 \uBB38\uC790\uC5F4\uB9CC \uC0AC\uC6A9\uD569\uB2C8\uB2E4.");
    return parsed;
  }
  const { branchKey, fileKey, resolvedFileKey } = readFigmaFileKeys(url);
  const nodeId = readFigmaNodeId(url);
  parsed.branchKey = branchKey || void 0;
  parsed.fileKey = fileKey || void 0;
  parsed.resolvedFileKey = resolvedFileKey || void 0;
  parsed.nodeId = nodeId || void 0;
  parsed.normalizedNodeId = nodeId ? normalizeFigmaNodeId(nodeId) : void 0;
  if (!fileKey) {
    parsed.parseNotes.push("Figma URL path\uC5D0\uC11C file key\uB97C \uCD94\uCD9C\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.");
  }
  if (!nodeId) {
    parsed.parseNotes.push("Figma URL\uC5D0\uC11C node-id query\uB97C \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.");
  }
  if (branchKey) {
    parsed.parseNotes.push("branch URL\uC774\uBBC0\uB85C branch key\uB97C MCP file key\uCC98\uB7FC \uC0AC\uC6A9\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.");
  }
  return parsed;
}
function getAvailableFilePath(directory, baseName, extension) {
  const first = path2.join(directory, `${baseName}${extension}`);
  if (!fs2.existsSync(first)) {
    return first;
  }
  let next = first;
  let count = 1;
  while (fs2.existsSync(next)) {
    next = path2.join(directory, `${baseName}-${count}${extension}`);
    if (!fs2.existsSync(next)) {
      break;
    }
    count += 1;
  }
  return next;
}
function appendHistoryIndex(paths, summary, relativeFilePath) {
  const line = `- ${getHumanReadableNow()} | ${summary} | file: \`${relativeFilePath}\`
`;
  fs2.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 writeCodeReviewArtifact(paths, baseNameSuffix, content) {
  const filePath = getAvailableFilePath(paths.codeReviewDir, `${getDashedFileTimestamp()}-${baseNameSuffix}`, ".md");
  const normalizedContent = content?.trim() || "(\uC751\uB2F5 \uC5C6\uC74C)";
  fs2.writeFileSync(filePath, `${normalizedContent}
`, "utf8");
  return filePath;
}
function writeCodeReviewReport(paths, reviewOutput) {
  return writeCodeReviewArtifact(paths, "code-review", reviewOutput);
}
function writeCodeReviewDiffFile(paths, diffOutput) {
  return writeCodeReviewArtifact(paths, "diff", diffOutput);
}
function openReportInBrowser(reportPath) {
  const resolvedPath = path2.resolve(reportPath);
  const { platform } = process;
  const openWithChrome = () => {
    if (platform === "darwin") {
      execSync(`open -a "Google Chrome" "${resolvedPath}"`, { stdio: "ignore" });
      return true;
    }
    if (platform === "linux") {
      execSync(`google-chrome "${resolvedPath}"`, { stdio: "ignore" });
      return true;
    }
    return false;
  };
  const openWithDefaultBrowser = () => {
    if (platform === "darwin") {
      execSync(`open "${resolvedPath}"`, { stdio: "ignore" });
      return true;
    }
    if (platform === "linux") {
      execSync(`xdg-open "${resolvedPath}"`, { stdio: "ignore" });
      return true;
    }
    return false;
  };
  try {
    if (openWithChrome()) {
      console.log(`Google Chrome\uC5D0\uC11C \uB9AC\uBDF0 \uC774\uB825\uC744 \uC5F4\uC5C8\uC2B5\uB2C8\uB2E4: ${resolvedPath}`);
      return;
    }
  } catch {
  }
  try {
    if (openWithDefaultBrowser()) {
      console.log(`\uAE30\uBCF8 \uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uB9AC\uBDF0 \uC774\uB825\uC744 \uC5F4\uC5C8\uC2B5\uB2C8\uB2E4: ${resolvedPath}`);
      return;
    }
  } catch (error) {
    console.error(`\uAE30\uBCF8 \uBE0C\uB77C\uC6B0\uC800\uB85C \uB9AC\uBDF0 \uC774\uB825\uC744 \uC5F4\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4: ${getErrorSummary(error)}`);
    return;
  }
  console.error(`\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uD50C\uB7AB\uD3FC\uC774\uB77C \uB9AC\uBDF0 \uC774\uB825\uC744 \uC790\uB3D9\uC73C\uB85C \uC5F4\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4: ${platform}`);
}
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)}
`;
  fs2.writeFileSync(filePath, markdown, "utf8");
  appendHistoryIndex(paths, `${record.scope} | ${record.service} | ${record.title}`, path2.relative(paths.rootDir, filePath));
  return filePath;
}
function writeServiceChangeHistory(paths, previousService, nextService, historyContext) {
  const baseName = `${getFileTimestamp()}-service-change`;
  const filePath = getAvailableFilePath(paths.servicesDir, baseName, ".md");
  const markdown = `# Service Change

- \uC2DC\uAC01: ${getHumanReadableNow()}
- \uC774\uC804 \uC11C\uBE44\uC2A4: \`${previousService || "(\uC5C6\uC74C)"}\`
- \uB2E4\uC74C \uC11C\uBE44\uC2A4: \`${nextService}\`

## \uC8FC\uC785 \uC608\uC815 \uD788\uC2A4\uD1A0\uB9AC

${formatCodeBlock(historyContext)}
`;
  fs2.writeFileSync(filePath, markdown, "utf8");
  appendHistoryIndex(paths, `service-change | ${previousService || "(\uC5C6\uC74C)"} -> ${nextService}`, path2.relative(paths.rootDir, filePath));
  return filePath;
}
function writeTestReport(paths, title, markdown) {
  const filePath = getAvailableFilePath(paths.testDir, `${getFileTimestamp()}-test`, ".md");
  const content = `# ${title}

- \uC2DC\uAC01: ${getHumanReadableNow()}

${markdown}
`;
  fs2.writeFileSync(filePath, content, "utf8");
  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)}
`;
  fs2.writeFileSync(filePath, markdown, "utf8");
  return filePath;
}
function ensureOutputDirectory(rootDir, outputPath) {
  const resolvedPath = path2.resolve(rootDir, outputPath);
  fs2.mkdirSync(resolvedPath, { recursive: true });
  return resolvedPath;
}

// src/platform/core/helpers.ts
var AI_SERVICES = Object.values(AI_SERVICE);
var COMMIT_SELECTION_WINDOW = 10;
var COMMIT_FETCH_LIMIT = 200;
setAiServicesRef(AI_SERVICES);
var TRACE_MESSAGES = [];
function getStoragePaths(rootDir = process.cwd()) {
  const baseDir = path2.join(rootDir, ".ju-hong-e");
  const codeReviewDir = path2.join(baseDir, "code-review");
  const historyDir = path2.join(baseDir, "ai-history");
  const mcpDir = path2.join(baseDir, "mcp");
  return {
    baseDir,
    codeReviewDir,
    conversationHistoryPath: path2.join(baseDir, "conversation-history.jsonl"),
    errorDir: path2.join(baseDir, "error"),
    historyDir,
    historyIndexPath: path2.join(historyDir, "index.md"),
    mcpDir,
    mcpRegistryPath: path2.join(mcpDir, "servers.json"),
    promptHistoryPath: path2.join(baseDir, "prompt-history.json"),
    rootDir,
    securityPolicyPath: path2.join(baseDir, "security-policy.json"),
    serviceFilePath: path2.join(baseDir, "service"),
    servicesDir: path2.join(historyDir, "services"),
    streamOutputConfigPath: path2.join(baseDir, "show-stream.json"),
    testDir: path2.join(baseDir, "test"),
    tmpDir: path2.join(baseDir, "tmp"),
    tokenOptimizerConfigPath: path2.join(baseDir, "token-optimizer-config.json"),
    turnsDir: path2.join(historyDir, "turns")
  };
}
function ensureStorageDirectories(paths) {
  [paths.baseDir, paths.codeReviewDir, paths.historyDir, paths.turnsDir, paths.servicesDir, paths.testDir, paths.errorDir, paths.tmpDir, paths.mcpDir].forEach((directory) => {
    fs2.mkdirSync(directory, { recursive: true });
  });
}
function parseCliArgs(args = process.argv.slice(2)) {
  const parsed = {
    help: false,
    testMode: false,
    traceMode: false
  };
  const getNextValue = (index) => {
    const value = args[index + 1];
    if (!value || value.startsWith("--")) {
      return "";
    }
    return value;
  };
  args.forEach((arg, index) => {
    if (arg === "--help" || arg === "-h") {
      parsed.help = true;
    }
    if (arg === "--test") {
      parsed.testMode = true;
    }
    if (arg === "--trace") {
      parsed.traceMode = true;
    }
    if (arg === "--model") {
      parsed.model = getNextValue(index) || void 0;
    }
    if (arg === "--service") {
      const service = getNextValue(index);
      if (AI_SERVICES.includes(service)) {
        parsed.service = service;
      }
    }
    if (arg === "--reasoning-effort") {
      const effort = getNextValue(index);
      if (["minimal", "low", "medium", "high"].includes(effort)) {
        parsed.reasoningEffort = effort;
      }
    }
  });
  return parsed;
}
function clearTraceMessages() {
  TRACE_MESSAGES.length = 0;
}
function getTraceMessages() {
  return [...TRACE_MESSAGES];
}
function createTraceLogger(scope, args) {
  const enabled = args.testMode || args.traceMode;
  return (step, detail) => {
    const message = `[${(/* @__PURE__ */ new Date()).toISOString()}][TRACE][${scope}] ${step}${detail ? ` | ${detail}` : ""}`;
    TRACE_MESSAGES.push(message);
    if (enabled) {
      console.log(message);
    }
  };
}

export { AI_SERVICES, COMMIT_FETCH_LIMIT, COMMIT_SELECTION_WINDOW, appendConversationHistory, appendPromptHistory, captureWorkspaceSnapshot, clearTraceMessages, createTraceLogger, diffWorkspaceSnapshots, ensureOutputDirectory, ensureStorageDirectories, formatCodeBlock, formatWorkspaceDelta, formatWorkspaceSnapshot, getErrorSummary, getHumanReadableNow, getStoragePaths, getTraceMessages, isGitRepository, isNodeError, loadConversationHistory, loadPromptHistory, loadRecentHistoryContext, normalizeFigmaNodeId, normalizePromptPathInput, openReportInBrowser, parseCliArgs, parseFigmaAddress, readSavedService, runGitCommand, safeExcerpt, savePromptHistory, saveService, shellQuote, writeCodeReviewDiffFile, writeCodeReviewReport, writeErrorReport, writeServiceChangeHistory, writeTestReport, writeTurnHistory };
