import { l as listCodexProjects, g as getCodexConversation, h as listGeminiProjects, i as getGeminiConversation, j as listQwenProjects, k as getQwenConversation, m as listCursorProjects, n as getCursorConversation, o as listCopilotProjects, p as getCopilotConversation, q as listAmpProjects, s as getAmpConversation, r as resolveOpenCodeDbPath } from './qwen-reader-DGfUbKaJ.js';
import * as crypto from 'crypto';
import * as fs from 'fs';
import * as path from 'path';
import Database from 'better-sqlite3';

function extractToolResultText(content) {
  if (typeof content === "string") {
    return content;
  }
  if (Array.isArray(content)) {
    return content.filter((c) => isRecord(c) && c.type === "text").map((c) => {
      const text = c.text;
      return typeof text === "string" ? text : "";
    }).join("\n");
  }
  return "";
}
function isRecord(value) {
  return typeof value === "object" && value !== null && !Array.isArray(value);
}
function str(obj, key) {
  const v = obj[key];
  return typeof v === "string" ? v : "";
}
function toContentBlocks(raw) {
  if (Array.isArray(raw)) {
    return raw.filter((item) => isRecord(item));
  }
  if (isRecord(raw)) {
    return [raw];
  }
  return [];
}
const SKIP_EVENT_TYPES = /* @__PURE__ */ new Set([
  "config",
  "heartbeat",
  "metadata",
  "result",
  "summary",
  "system"
]);
function parseAssistantBlock(block) {
  if (!block || typeof block !== "object") {
    return null;
  }
  switch (block.type) {
    case "text":
      return { content: block.text || "", type: "text" };
    case "thinking":
      return { content: block.thinking || "", type: "thinking" };
    case "tool_use":
      return {
        id: block.id || "",
        input: block.input || {},
        toolName: block.name || "Unknown",
        type: "tool_use"
      };
    default:
      return null;
  }
}
function parseJsonlLine(line, assistantTurns, messageIndex) {
  const messages = [];
  const assistantCompleted = [];
  const entry = JSON.parse(line);
  if (!isRecord(entry)) {
    return { assistantCompleted, messages };
  }
  const entryType = str(entry, "type");
  if (SKIP_EVENT_TYPES.has(entryType)) {
    return { assistantCompleted, messages };
  }
  const entryTimestamp = str(entry, "timestamp");
  const entryUuid = str(entry, "uuid");
  if (entryType === "user") {
    const msg = isRecord(entry.message) ? entry.message : null;
    if (!msg?.content) {
      return { assistantCompleted, messages };
    }
    const parts = [];
    const blocks = toContentBlocks(msg.content);
    if (Array.isArray(msg.content)) {
      for (const item of msg.content) {
        if (typeof item === "string") {
          parts.push({ content: item, type: "text" });
        }
      }
    } else if (typeof msg.content === "string") {
      parts.push({ content: msg.content, type: "text" });
    }
    for (const block of blocks) {
      const blockType = str(block, "type");
      if (!blockType) {
        continue;
      }
      if (blockType === "text") {
        parts.push({ content: str(block, "text"), type: "text" });
      } else if (blockType === "tool_result") {
        let output = extractToolResultText(block.content);
        const toolUseResult = isRecord(entry.toolUseResult) ? entry.toolUseResult : null;
        if (toolUseResult?.content !== void 0) {
          output = extractToolResultText(toolUseResult.content);
        }
        parts.push({
          isError: typeof block.is_error === "boolean" ? block.is_error : false,
          output: output.slice(0, 2e3),
          toolUseId: str(block, "tool_use_id"),
          type: "tool_result"
        });
      }
    }
    if (parts.length > 0 && parts.some((p) => p.type === "text")) {
      messages.push({
        id: entryUuid || `user-${messageIndex}`,
        parts: parts.filter((p) => p.type === "text"),
        role: "user",
        timestamp: entryTimestamp
      });
    }
    const toolResults = parts.filter((p) => p.type === "tool_result");
    if (toolResults.length > 0) {
      messages.push({
        id: `tool-result-${entryUuid || messageIndex}`,
        parts: toolResults,
        role: "system",
        timestamp: entryTimestamp
      });
    }
  } else if (entryType === "assistant") {
    const msg = isRecord(entry.message) ? entry.message : null;
    if (!msg?.content) {
      return { assistantCompleted, messages };
    }
    const blocks = toContentBlocks(msg.content);
    const msgId = str(msg, "id") || entryUuid;
    for (const block of blocks) {
      const part = parseAssistantBlock(block);
      if (!part) {
        continue;
      }
      if (!assistantTurns.has(msgId)) {
        assistantTurns.set(msgId, { parts: [], timestamp: entryTimestamp });
      }
      const turn = assistantTurns.get(msgId);
      if (turn) {
        turn.parts.push(part);
      }
    }
    if (msg.stop_reason) {
      const turn = assistantTurns.get(msgId);
      if (turn && turn.parts.length > 0) {
        assistantCompleted.push({
          id: msgId,
          parts: turn.parts,
          role: "assistant",
          timestamp: turn.timestamp
        });
        assistantTurns.delete(msgId);
      }
    }
  }
  return { assistantCompleted, messages };
}
function parseJsonlText(text, assistantTurns, startIndex) {
  const lines = text.split("\n").filter((line) => line.trim());
  const allMessages = [];
  let idx = startIndex;
  for (const line of lines) {
    try {
      const { assistantCompleted, messages } = parseJsonlLine(line, assistantTurns, idx);
      allMessages.push(...messages, ...assistantCompleted);
      idx++;
    } catch {
    }
  }
  return allMessages;
}
const SYSTEM_TAG_PREFIXES = [
  "<local-command",
  "<command-name>",
  "<command-message>",
  "<command-args>",
  "<local-command-stdout>",
  "<local-command-caveat>",
  "<system-reminder>",
  "<task-notification>"
];
function extractContentText(content) {
  if (typeof content === "string") {
    return content.trim();
  }
  if (Array.isArray(content)) {
    for (const b of content) {
      if (typeof b === "string" && b.trim()) {
        return b.trim();
      }
      if (typeof b === "object" && b !== null) {
        const block = b;
        if (block.type === "text" && typeof block.text === "string" && block.text.trim()) {
          return block.text.trim();
        }
      }
    }
  }
  return "";
}
function findFirstUserPrompt(content) {
  for (const line of content.split("\n")) {
    if (!line.trim()) {
      continue;
    }
    try {
      const entry = JSON.parse(line);
      if (entry.type !== "user") {
        continue;
      }
      const msg = entry.message;
      if (!msg?.content) {
        continue;
      }
      const text = extractContentText(msg.content);
      if (!text || SYSTEM_TAG_PREFIXES.some((p) => text.startsWith(p))) {
        continue;
      }
      return text;
    } catch {
      continue;
    }
  }
  return "";
}
function shortHash$1(input) {
  return crypto.createHash("sha256").update(input).digest("hex").slice(0, 8);
}
const CLAUDE_PROJECTS_DIR = path.join(process.env.HOME || "", ".claude", "projects");
function getSessionConversation(sessionId, offset = 0, limit = 100, projectId) {
  const projectDir = projectId ? path.join(CLAUDE_PROJECTS_DIR, projectId) : getProjectDir();
  const jsonlPath = path.join(projectDir, `${sessionId}.jsonl`);
  if (!fs.existsSync(jsonlPath)) {
    return [];
  }
  try {
    const raw = fs.readFileSync(jsonlPath, "utf-8");
    const assistantTurns = /* @__PURE__ */ new Map();
    const messages = parseJsonlText(raw, assistantTurns, 0);
    for (const [msgId, turn] of assistantTurns) {
      if (turn.parts.length > 0) {
        messages.push({
          id: msgId,
          parts: turn.parts,
          role: "assistant",
          timestamp: turn.timestamp
        });
      }
    }
    const seenIds = /* @__PURE__ */ new Set();
    const deduped = [];
    for (let i = messages.length - 1; i >= 0; i--) {
      if (!seenIds.has(messages[i].id)) {
        seenIds.add(messages[i].id);
        deduped.push(messages[i]);
      }
    }
    deduped.reverse();
    if (offset === 0 && deduped.length > limit) {
      let startIdx = deduped.length - limit;
      while (startIdx > 0 && startIdx < deduped.length && deduped[startIdx].role !== "user") {
        startIdx--;
      }
      return deduped.slice(startIdx);
    }
    return deduped.slice(offset, offset + limit);
  } catch (error) {
    console.error("[sessions] Failed to parse session JSONL:", error);
    return [];
  }
}
function listProjectsWithSessions() {
  if (!fs.existsSync(CLAUDE_PROJECTS_DIR)) {
    return [];
  }
  let projectDirs;
  try {
    projectDirs = fs.readdirSync(CLAUDE_PROJECTS_DIR).filter((d) => {
      const fullPath = path.join(CLAUDE_PROJECTS_DIR, d);
      try {
        return fs.statSync(fullPath).isDirectory();
      } catch {
        return false;
      }
    });
  } catch {
    return [];
  }
  const projects = [];
  for (const dir of projectDirs) {
    const projectDir = path.join(CLAUDE_PROJECTS_DIR, dir);
    const sessions = listSessionsForProject(projectDir);
    if (sessions.length === 0) {
      continue;
    }
    sessions.sort((a, b) => new Date(b.modified).getTime() - new Date(a.modified).getTime());
    const realPath = sessions.find((s) => s.projectPath && !s.projectPath.includes(".claude/projects"))?.projectPath || readCwdFromProjectDir(projectDir, sessions) || decodeClaudeProjectDir(dir) || (dir.startsWith("-") ? dir.replace(/-/g, "/") : `/${dir.replace(/-/g, "/")}`);
    const pathSegments = realPath.split("/").filter(Boolean);
    const projectName = pathSegments.slice(-2).join("/");
    projects.push({
      fullPath: realPath,
      id: shortHash$1(realPath),
      lastModified: sessions[0]?.modified || "",
      name: projectName,
      sessionCount: sessions.length,
      sessions
    });
  }
  return projects.sort(
    (a, b) => new Date(b.lastModified).getTime() - new Date(a.lastModified).getTime()
  );
}
function bytesReadEnded(chunk) {
  return chunk.length > 0 && chunk.charCodeAt(chunk.length - 1) === 10;
}
function cleanTitle(prompt) {
  let cleaned = prompt.replace(/<command-message>.*?<\/command-message>/gs, "").replace(/<command-name>.*?<\/command-name>/gs, "").replace(/<command-args>.*?<\/command-args>/gs, "").replace(/<local-command-caveat>.*?<\/local-command-caveat>/gs, "").replace(/<local-command-stdout>.*?<\/local-command-stdout>/gs, "").replace(/<system-reminder>.*?<\/system-reminder>/gs, "").replace(/<task-notification>.*?<\/task-notification>/gs, "");
  let prev = "";
  while (prev !== cleaned) {
    prev = cleaned;
    cleaned = cleaned.replace(/<[^>]*>/g, "").replace(/</g, "");
  }
  cleaned = cleaned.trim();
  if (!cleaned) {
    return "Untitled Session";
  }
  const firstLine = cleaned.split("\n")[0].trim();
  if (!firstLine) {
    return "Untitled Session";
  }
  if (firstLine.length > 80) {
    return `${firstLine.slice(0, 77)}...`;
  }
  return firstLine;
}
function decodeClaudeProjectDir(encoded) {
  if (!encoded.startsWith("-")) {
    return null;
  }
  const parts = encoded.slice(1).split("-");
  if (parts.length === 0) {
    return null;
  }
  let currentPath = "/";
  let i = 0;
  while (i < parts.length) {
    let matchedTo = -1;
    for (let j = parts.length; j > i; j--) {
      const segment = parts.slice(i, j).join("-");
      const candidate = path.join(currentPath, segment);
      try {
        if (fs.statSync(candidate).isDirectory()) {
          matchedTo = j;
          break;
        }
      } catch {
      }
    }
    if (matchedTo === -1) {
      return null;
    }
    currentPath = path.join(currentPath, parts.slice(i, matchedTo).join("-"));
    i = matchedTo;
  }
  return currentPath;
}
function getProjectDir() {
  const projectPath = process.cwd();
  const encoded = projectPath.replace(/\//g, "-");
  return path.join(CLAUDE_PROJECTS_DIR, encoded);
}
function listSessionsForProject(projectDir) {
  const indexPath = path.join(projectDir, "sessions-index.json");
  const hasIndex = fs.existsSync(indexPath);
  const indexedIds = /* @__PURE__ */ new Set();
  const sessions = [];
  if (hasIndex) {
    try {
      const raw = fs.readFileSync(indexPath, "utf-8");
      const index = JSON.parse(raw);
      for (const entry of index.entries) {
        if (entry.isSidechain) {
          continue;
        }
        const jsonlFile = path.join(projectDir, `${entry.sessionId}.jsonl`);
        if (!fs.existsSync(jsonlFile)) {
          continue;
        }
        indexedIds.add(entry.sessionId);
        sessions.push({
          created: entry.created || "",
          gitBranch: entry.gitBranch || "",
          id: entry.sessionId,
          messageCount: entry.messageCount || 0,
          modified: entry.modified || "",
          projectPath: entry.projectPath || "",
          source: "claude-code",
          summary: entry.summary || "",
          title: cleanTitle(entry.firstPrompt || entry.summary || "Untitled Session")
        });
      }
    } catch (error) {
      console.error("[sessions] Failed to read sessions index:", error);
    }
  }
  try {
    const files = fs.readdirSync(projectDir);
    for (const file of files) {
      if (!file.endsWith(".jsonl")) {
        continue;
      }
      const sessionId = file.replace(".jsonl", "");
      if (indexedIds.has(sessionId)) {
        continue;
      }
      const filePath = path.join(projectDir, file);
      const stat = fs.statSync(filePath);
      let firstPrompt = "Active Session";
      let messageCount = 0;
      try {
        const content = fs.readFileSync(filePath, "utf-8");
        let countPos = 0;
        while (countPos < content.length) {
          const nl = content.indexOf("\n", countPos);
          const lineEnd = nl === -1 ? content.length : nl;
          const line = content.substring(countPos, lineEnd);
          if (line.includes('"type":"user"') || line.includes('"type":"assistant"')) {
            messageCount++;
          }
          if (nl === -1) {
            break;
          }
          countPos = nl + 1;
        }
        const prompt = findFirstUserPrompt(content);
        if (prompt) {
          firstPrompt = prompt;
        }
      } catch {
      }
      sessions.push({
        created: stat.birthtime.toISOString(),
        gitBranch: "",
        id: sessionId,
        messageCount,
        modified: stat.mtime.toISOString(),
        projectPath: "",
        source: "claude-code",
        summary: "",
        title: cleanTitle(firstPrompt)
      });
    }
  } catch {
  }
  return sessions.sort((a, b) => new Date(b.modified).getTime() - new Date(a.modified).getTime());
}
function readCwdFromProjectDir(projectDir, sessions) {
  const READ_BYTES = 65536;
  for (const session of sessions) {
    try {
      const filePath = path.join(projectDir, `${session.id}.jsonl`);
      if (!fs.existsSync(filePath)) {
        continue;
      }
      const fd = fs.openSync(filePath, "r");
      let chunk;
      try {
        const buf = Buffer.alloc(READ_BYTES);
        const bytesRead = fs.readSync(fd, buf, 0, READ_BYTES, 0);
        chunk = buf.toString("utf-8", 0, bytesRead);
      } finally {
        fs.closeSync(fd);
      }
      const lines = chunk.split("\n");
      const completeLines = bytesReadEnded(chunk) ? lines : lines.slice(0, -1);
      for (const line of completeLines) {
        if (!line.trim()) {
          continue;
        }
        try {
          const entry = JSON.parse(line);
          if (typeof entry.cwd === "string" && entry.cwd) {
            return entry.cwd;
          }
        } catch {
        }
      }
    } catch {
    }
  }
  return "";
}
function getOpenCodeConversation(sessionId, offset = 0, limit = 200) {
  const db = getDb();
  if (!db) {
    return [];
  }
  try {
    const messages = db.prepare(
      `
      SELECT id, session_id, time_created, data FROM (
        SELECT id, session_id, time_created, data
        FROM message
        WHERE session_id = ?
        ORDER BY time_created DESC
        LIMIT ? OFFSET ?
      ) ORDER BY time_created ASC
    `
    ).all(sessionId, limit, offset);
    const messageIds = messages.map((m) => m.id);
    if (messageIds.length === 0) {
      return [];
    }
    const placeholders = messageIds.map(() => "?").join(",");
    const parts = db.prepare(
      `
      SELECT id, message_id, time_created, data
      FROM part
      WHERE message_id IN (${placeholders})
      ORDER BY time_created ASC
    `
    ).all(...messageIds);
    const partsByMessage = /* @__PURE__ */ new Map();
    for (const part of parts) {
      if (!partsByMessage.has(part.message_id)) {
        partsByMessage.set(part.message_id, []);
      }
      const bucket = partsByMessage.get(part.message_id);
      if (bucket) {
        bucket.push(part);
      }
    }
    const result = [];
    for (const msg of messages) {
      let msgData = {};
      try {
        msgData = JSON.parse(msg.data);
      } catch {
      }
      const role = msgData.role === "user" ? "user" : "assistant";
      const msgParts = partsByMessage.get(msg.id) || [];
      const convertedParts = [];
      for (const part of msgParts) {
        let partData = {};
        try {
          partData = JSON.parse(part.data);
        } catch {
          continue;
        }
        const converted = convertOpenCodePart(partData);
        if (converted) {
          convertedParts.push(converted);
        }
      }
      if (convertedParts.length > 0) {
        result.push({
          id: msg.id,
          parts: convertedParts,
          role,
          timestamp: new Date(msg.time_created).toISOString()
        });
      }
    }
    return result;
  } catch (error) {
    console.error("[opencode] Failed to read conversation:", error);
    return [];
  } finally {
    db.close();
  }
}
function listOpenCodeProjects() {
  const db = getDb();
  if (!db) {
    return [];
  }
  try {
    const sessions = db.prepare(
      `
      SELECT id, directory, title, slug, time_created, time_updated, parent_id
      FROM session
      WHERE time_archived IS NULL OR time_archived = 0
      ORDER BY time_updated DESC
    `
    ).all();
    const msgCounts = db.prepare(`SELECT session_id, COUNT(*) as count FROM message GROUP BY session_id`).all();
    const msgCountMap = new Map(msgCounts.map((r) => [r.session_id, r.count]));
    const projectMap = /* @__PURE__ */ new Map();
    for (const row of sessions) {
      const dir = row.directory || "unknown";
      if (!projectMap.has(dir)) {
        projectMap.set(dir, []);
      }
      const sessionInfo = {
        created: new Date(row.time_created).toISOString(),
        gitBranch: "",
        id: row.id,
        messageCount: msgCountMap.get(row.id) || 0,
        modified: new Date(row.time_updated).toISOString(),
        projectPath: dir,
        source: "opencode",
        summary: "",
        title: row.title || row.slug || "Untitled Session"
      };
      const bucket = projectMap.get(dir);
      if (bucket) {
        bucket.push(sessionInfo);
      }
    }
    const projects = [];
    for (const [dir, dirSessions] of projectMap) {
      const pathSegments = dir.split("/").filter(Boolean);
      const projectName = pathSegments.slice(-2).join("/");
      dirSessions.sort((a, b) => new Date(b.modified).getTime() - new Date(a.modified).getTime());
      projects.push({
        fullPath: dir,
        id: shortHash(dir),
        lastModified: dirSessions[0]?.modified || "",
        name: `${projectName} (OpenCode)`,
        sessionCount: dirSessions.length,
        sessions: dirSessions
      });
    }
    return projects.sort(
      (a, b) => new Date(b.lastModified).getTime() - new Date(a.lastModified).getTime()
    );
  } catch (error) {
    console.error("[opencode] Failed to read sessions:", error);
    return [];
  } finally {
    db.close();
  }
}
function convertOpenCodePart(data) {
  const type = data.type;
  switch (type) {
    case "reasoning":
      return {
        content: data.text || "",
        type: "thinking"
      };
    case "text":
      return {
        content: data.text || "",
        type: "text"
      };
    case "tool": {
      const state = data.state;
      return {
        id: data.callID || data.id || "",
        input: state?.input || {},
        toolName: data.tool || "Unknown",
        type: "tool_use"
      };
    }
    default:
      return null;
  }
}
function getDb() {
  const dbPath = resolveOpenCodeDbPath();
  if (!fs.existsSync(dbPath)) {
    return null;
  }
  try {
    return new Database(dbPath, { readonly: true });
  } catch {
    return null;
  }
}
function shortHash(input) {
  return crypto.createHash("sha256").update(input).digest("hex").slice(0, 8);
}
const PROVIDERS = [
  {
    command: "claude",
    getConversation: (id, offset, limit) => getSessionConversation(id, offset, limit),
    isAI: true,
    label: "Claude Code",
    listProjects: listProjectsWithSessions,
    resumeArgs: (id) => ["--resume", id],
    source: "claude-code"
  },
  {
    command: "opencode",
    getConversation: getOpenCodeConversation,
    isAI: true,
    label: "OpenCode",
    listProjects: listOpenCodeProjects,
    nameSuffix: " (OpenCode)",
    resumeArgs: (id) => ["--session", id],
    source: "opencode"
  },
  {
    command: "codex",
    getConversation: getCodexConversation,
    isAI: true,
    label: "Codex",
    listProjects: listCodexProjects,
    resumeArgs: (id) => ["resume", id],
    source: "codex"
  },
  {
    command: "gemini",
    getConversation: getGeminiConversation,
    isAI: true,
    label: "Gemini",
    listProjects: listGeminiProjects,
    resumeArgs: () => [],
    // Gemini CLI has no session-resume flag
    source: "gemini"
  },
  {
    command: "qwen",
    getConversation: getQwenConversation,
    isAI: true,
    label: "Qwen",
    listProjects: listQwenProjects,
    resumeArgs: () => [],
    source: "qwen"
  },
  {
    command: "cursor-agent",
    getConversation: getCursorConversation,
    isAI: true,
    label: "Cursor",
    listProjects: listCursorProjects,
    resumeArgs: () => [],
    source: "cursor"
  },
  {
    command: "copilot",
    getConversation: getCopilotConversation,
    isAI: true,
    label: "Copilot",
    listProjects: listCopilotProjects,
    resumeArgs: () => [],
    source: "copilot"
  },
  {
    command: "amp",
    getConversation: getAmpConversation,
    isAI: true,
    label: "Amp",
    listProjects: listAmpProjects,
    resumeArgs: () => [],
    source: "amp"
  }
];
PROVIDERS.filter((p) => p.isAI).map((p) => p.command);
const PROVIDER_COMMANDS = PROVIDERS.map((p) => p.command);
function getProviderConversation(sessionId, offset, limit, claudeProjectDir) {
  const claude = getSessionConversation(sessionId, offset, limit, claudeProjectDir);
  if (claude.length > 0) {
    return claude;
  }
  for (const provider of PROVIDERS) {
    if (provider.source === "claude-code") {
      continue;
    }
    try {
      const messages = provider.getConversation(sessionId, offset, limit);
      if (messages.length > 0) {
        return messages;
      }
    } catch {
    }
  }
  return [];
}
function listAllProviderProjects() {
  const byPath = /* @__PURE__ */ new Map();
  for (const provider of PROVIDERS) {
    let groups;
    try {
      groups = provider.listProjects();
    } catch {
      continue;
    }
    for (const group of groups) {
      try {
        const name = provider.nameSuffix && typeof group.name === "string" ? group.name.replace(provider.nameSuffix, "") : group.name;
        const existing = byPath.get(group.fullPath);
        if (existing) {
          existing.sessions.push(...group.sessions);
          existing.sessions.sort(
            (a, b) => new Date(b.modified).getTime() - new Date(a.modified).getTime()
          );
          existing.sessionCount = existing.sessions.length;
          existing.lastModified = existing.sessions[0]?.modified || existing.lastModified;
        } else {
          byPath.set(group.fullPath, { ...group, name });
        }
      } catch {
      }
    }
  }
  return [...byPath.values()].sort(
    (a, b) => new Date(b.lastModified).getTime() - new Date(a.lastModified).getTime()
  );
}
function resumeArgsForCommand(command, sessionId) {
  return PROVIDERS.find((p) => p.command === command)?.resumeArgs(sessionId) ?? [];
}

export { PROVIDER_COMMANDS as P, PROVIDERS as a, getProviderConversation as g, listAllProviderProjects as l, resumeArgsForCommand as r };
//# sourceMappingURL=registry-D4J_CuzW.js.map
