import * as vscode from 'vscode';
import * as os from 'os';
import * as path from 'path';
import * as fs from 'fs';
import { randomUUID } from 'crypto';
import { spawn, execFile } from 'child_process';
import { promisify } from 'util';
import { type OpenCodeManager } from './opencode';
import { createAgent, createCommand, deleteAgent, deleteCommand, getAgentSources, getCommandSources, updateAgent, updateCommand, type AgentScope, type CommandScope, AGENT_SCOPE, COMMAND_SCOPE, discoverSkills, getSkillSources, createSkill, updateSkill, deleteSkill, readSkillSupportingFile, writeSkillSupportingFile, deleteSkillSupportingFile, type SkillScope, type SkillSource, type DiscoveredSkill, SKILL_SCOPE, getProviderSources, removeProviderConfig, listMcpConfigs, getMcpConfig, createMcpConfig, updateMcpConfig, deleteMcpConfig } from './opencodeConfig';
import { getProviderAuth, removeProviderAuth } from './opencodeAuth';
import { fetchQuotaForProvider, listConfiguredQuotaProviders } from './quotaProviders';
import * as gitService from './gitService';
import {
  getSkillsCatalog,
  scanSkillsRepository as scanSkillsRepositoryFromGit,
  installSkillsFromRepository as installSkillsFromGit,
  type SkillsCatalogSourceConfig,
} from './skillsCatalog';
import {
  DEFAULT_GITHUB_CLIENT_ID,
  DEFAULT_GITHUB_SCOPES,
  activateGitHubAuth,
  clearGitHubAuth,
  exchangeDeviceCode,
  fetchMe,
  readGitHubAuth,
  readGitHubAuthList,
  startDeviceFlow,
  writeGitHubAuth,
} from './githubAuth';
import {
  createPullRequest,
  getPullRequestStatus,
  markPullRequestReady,
  mergePullRequest,
  updatePullRequest,
} from './githubPr';

import {
  getIssue,
  listIssueComments,
  listIssues,
} from './githubIssues';

import {
  getPullRequestContext,
  listPullRequests,
} from './githubPulls';

export interface BridgeRequest {
  id: string;
  type: string;
  payload?: unknown;
}

export interface BridgeResponse {
  id: string;
  type: string;
  success: boolean;
  data?: unknown;
  error?: string;
}

type ApiProxyRequestPayload = {
  method?: string;
  path?: string;
  headers?: Record<string, string>;
  bodyBase64?: string;
};

type ApiSessionMessageRequestPayload = {
  path?: string;
  headers?: Record<string, string>;
  bodyText?: string;
};

type ApiProxyResponsePayload = {
  status: number;
  headers: Record<string, string>;
  bodyBase64: string;
};

type NotificationBridgePayload = {
  title?: string;
  body?: string;
  tag?: string;
};

type NotificationsNotifyRequestPayload = {
  payload?: NotificationBridgePayload;
};

interface FileEntry {
  name: string;
  path: string;
  isDirectory: boolean;
}

interface FileSearchResult {
  path: string;
  score?: number;
}

export interface BridgeContext {
  manager?: OpenCodeManager;
  context?: vscode.ExtensionContext;
}

const SETTINGS_KEY = 'openchamber.settings';
const CLIENT_RELOAD_DELAY_MS = 800;
const MAX_FILE_ATTACH_SIZE_BYTES = 10 * 1024 * 1024;
const execFileAsync = promisify(execFile);
const gpgconfCandidates = ['gpgconf', '/opt/homebrew/bin/gpgconf', '/usr/local/bin/gpgconf'];

const OPENCHAMBER_SHARED_SETTINGS_PATH = path.join(os.homedir(), '.config', 'openchamber', 'settings.json');
const UPDATE_CHECK_URL = process.env.OPENCHAMBER_UPDATE_API_URL || 'https://api.openchamber.dev/v1/update/check';

const getOpenChamberConfigDir = (): string => {
  if (process.platform === 'win32') {
    const appData = process.env.APPDATA;
    if (appData) return path.join(appData, 'openchamber');
  }
  return path.join(os.homedir(), '.config', 'openchamber');
};

const sanitizeInstallScope = (scope: string): 'desktop-tauri' | 'vscode' | 'web' => {
  if (scope === 'desktop-tauri' || scope === 'vscode' || scope === 'web') return scope;
  return 'web';
};

const getOrCreateInstallId = (scope: string): string => {
  const configDir = getOpenChamberConfigDir();
  const normalizedScope = sanitizeInstallScope(scope);
  const idPath = path.join(configDir, `install-id-${normalizedScope}`);

  try {
    const existing = fs.readFileSync(idPath, 'utf8').trim();
    if (existing) return existing;
  } catch {
    // Generate new id.
  }

  const installId = randomUUID();
  fs.mkdirSync(configDir, { recursive: true });
  fs.writeFileSync(idPath, `${installId}\n`, { encoding: 'utf8', mode: 0o600 });
  return installId;
};

const mapNodePlatformToApiPlatform = (value: string): 'macos' | 'windows' | 'linux' | 'web' => {
  if (value === 'darwin') return 'macos';
  if (value === 'win32') return 'windows';
  if (value === 'linux') return 'linux';
  return 'web';
};

const mapNodeArchToApiArch = (value: string): 'arm64' | 'x64' | 'unknown' => {
  if (value === 'arm64' || value === 'aarch64') return 'arm64';
  if (value === 'x64' || value === 'amd64') return 'x64';
  return 'unknown';
};

const guessMimeTypeFromExtension = (ext: string) => {
  switch (ext) {
    case '.png':
    case '.jpg':
    case '.jpeg':
    case '.gif':
    case '.bmp':
    case '.webp':
      return `image/${ext.replace('.', '')}`;
    case '.pdf':
      return 'application/pdf';
    case '.txt':
    case '.log':
      return 'text/plain';
    case '.json':
      return 'application/json';
    case '.md':
    case '.markdown':
      return 'text/markdown';
    default:
      return 'application/octet-stream';
  }
};

const hasUriScheme = (value: string): boolean => /^[A-Za-z][A-Za-z\d+.-]*:/.test(value);

const parseDroppedFileReference = (rawReference: string):
  | { uri: vscode.Uri }
  | { skipped: { name: string; reason: string } } => {
  const trimmed = rawReference.trim().replace(/^['"]+|['"]+$/g, '');
  if (!trimmed) {
    return { skipped: { name: rawReference, reason: 'Empty drop reference' } };
  }

  if (hasUriScheme(trimmed)) {
    try {
      const parsed = vscode.Uri.parse(trimmed, true);
      if (parsed.scheme !== 'file') {
        return {
          skipped: {
            name: trimmed,
            reason: `Unsupported URI scheme: ${parsed.scheme || 'unknown'}`,
          },
        };
      }
      return { uri: parsed };
    } catch (error) {
      return {
        skipped: {
          name: trimmed,
          reason: error instanceof Error ? error.message : 'Invalid URI',
        },
      };
    }
  }

  if (!path.isAbsolute(trimmed)) {
    return {
      skipped: {
        name: trimmed,
        reason: 'Drop reference is not an absolute file path',
      },
    };
  }

  return { uri: vscode.Uri.file(trimmed) };
};

const readUriAsAttachment = async (
  uri: vscode.Uri,
  fallbackName?: string,
): Promise<
  | { file: { name: string; mimeType: string; size: number; dataUrl: string } }
  | { skipped: { name: string; reason: string } }
> => {
  const name = path.basename(uri.fsPath || uri.path || fallbackName || 'file');

  try {
    const stat = await vscode.workspace.fs.stat(uri);
    if ((stat.type & vscode.FileType.Directory) !== 0) {
      return { skipped: { name, reason: 'Folders are not supported' } };
    }

    const size = stat.size ?? 0;
    if (size > MAX_FILE_ATTACH_SIZE_BYTES) {
      return { skipped: { name, reason: 'File exceeds 10MB limit' } };
    }

    const bytes = await vscode.workspace.fs.readFile(uri);
    const ext = path.extname(name).toLowerCase();
    const mimeType = guessMimeTypeFromExtension(ext);
    const base64 = Buffer.from(bytes).toString('base64');
    const dataUrl = `data:${mimeType};base64,${base64}`;

    return { file: { name, mimeType, size, dataUrl } };
  } catch (error) {
    return { skipped: { name, reason: error instanceof Error ? error.message : 'Failed to read file' } };
  }
};

type ParsedDiffHunk = {
  newStart: number;
  oldLines: string[];
  newLines: string[];
};

const VIRTUAL_DIFF_SCHEME = 'openchamber-diff';
const virtualDiffContents = new Map<string, string>();
let virtualDiffCounter = 0;
let virtualDiffProviderDisposable: vscode.Disposable | null = null;

const ensureVirtualDiffProviderRegistered = (ctx?: BridgeContext): void => {
  if (virtualDiffProviderDisposable) {
    return;
  }

  virtualDiffProviderDisposable = vscode.workspace.registerTextDocumentContentProvider(
    VIRTUAL_DIFF_SCHEME,
    {
      provideTextDocumentContent: (uri: vscode.Uri) => {
        const key = new URLSearchParams(uri.query).get('key') || '';
        return virtualDiffContents.get(key) ?? '';
      },
    },
  );

  if (ctx?.context) {
    ctx.context.subscriptions.push(virtualDiffProviderDisposable);
  }
};

const createVirtualOriginalDiffUri = (modifiedPath: string, content: string): vscode.Uri => {
  const key = `${Date.now()}-${++virtualDiffCounter}`;
  virtualDiffContents.set(key, content);

  if (virtualDiffContents.size > 100) {
    const firstKey = virtualDiffContents.keys().next().value;
    if (typeof firstKey === 'string') {
      virtualDiffContents.delete(firstKey);
    }
  }

  const fileName = path.basename(modifiedPath) || 'file';
  return vscode.Uri.from({
    scheme: VIRTUAL_DIFF_SCHEME,
    // Keep real filename (incl extension) so VS Code can infer language for syntax highlighting.
    path: `/${fileName}`,
    query: `key=${encodeURIComponent(key)}`,
  });
};

const parseUnifiedDiffHunks = (patch: string): ParsedDiffHunk[] => {
  if (typeof patch !== 'string' || patch.trim().length === 0) {
    return [];
  }

  const lines = patch.split('\n');
  const hunks: ParsedDiffHunk[] = [];
  let current: ParsedDiffHunk | null = null;

  for (const rawLine of lines) {
    const line = rawLine.replace(/\r$/, '');
    const headerMatch = line.match(/^@@\s+-\d+(?:,\d+)?\s+\+(\d+)(?:,\d+)?\s+@@/);
    if (headerMatch) {
      if (current) {
        hunks.push(current);
      }
      const newStart = Number.parseInt(headerMatch[1] ?? '', 10);
      current = {
        newStart: Number.isFinite(newStart) ? Math.max(1, newStart) : 1,
        oldLines: [],
        newLines: [],
      };
      continue;
    }

    if (!current) {
      continue;
    }

    if (line.startsWith(' ')) {
      const text = line.slice(1);
      current.oldLines.push(text);
      current.newLines.push(text);
      continue;
    }

    if (line.startsWith('+') && !line.startsWith('+++')) {
      current.newLines.push(line.slice(1));
      continue;
    }

    if (line.startsWith('-') && !line.startsWith('---')) {
      current.oldLines.push(line.slice(1));
      continue;
    }
  }

  if (current) {
    hunks.push(current);
  }

  return hunks;
};

const reconstructOriginalContentFromPatch = (modifiedContent: string, patch: string): string | null => {
  const hunks = parseUnifiedDiffHunks(patch);
  if (hunks.length === 0) {
    return null;
  }

  const lines = modifiedContent.split('\n');
  for (let index = hunks.length - 1; index >= 0; index -= 1) {
    const hunk = hunks[index];
    if (!hunk) {
      continue;
    }
    const startIndex = Math.max(0, hunk.newStart - 1);
    const replaceCount = hunk.newLines.length;
    lines.splice(startIndex, replaceCount, ...hunk.oldLines);
  }

  return lines.join('\n');
};

const isPathInside = (candidatePath: string, parentPath: string): boolean => {
  const normalizedCandidate = path.resolve(candidatePath);
  const normalizedParent = path.resolve(parentPath);
  return normalizedCandidate === normalizedParent || normalizedCandidate.startsWith(`${normalizedParent}${path.sep}`);
};

const findWorktreeRootForSkills = (workingDirectory?: string): string | null => {
  if (!workingDirectory) return null;
  let current = path.resolve(workingDirectory);
  while (true) {
    if (fs.existsSync(path.join(current, '.git'))) {
      return current;
    }
    const parent = path.dirname(current);
    if (parent === current) return null;
    current = parent;
  }
};

const getProjectAncestors = (workingDirectory?: string): string[] => {
  if (!workingDirectory) return [];
  const result: string[] = [];
  let current = path.resolve(workingDirectory);
  const stop = findWorktreeRootForSkills(workingDirectory) || current;
  while (true) {
    result.push(current);
    if (current === stop) break;
    const parent = path.dirname(current);
    if (parent === current) break;
    current = parent;
  }
  return result;
};

const inferSkillScopeAndSourceFromLocation = (location: string, workingDirectory?: string): { scope: SkillScope; source: SkillSource } => {
  const resolvedPath = path.resolve(location);
  const source: SkillSource = resolvedPath.includes(`${path.sep}.agents${path.sep}skills${path.sep}`)
    ? 'agents'
    : resolvedPath.includes(`${path.sep}.claude${path.sep}skills${path.sep}`)
      ? 'claude'
      : 'opencode';

  const projectAncestors = getProjectAncestors(workingDirectory);
  const isProjectScoped = projectAncestors.some((ancestor) => {
    const candidates = [
      path.join(ancestor, '.opencode'),
      path.join(ancestor, '.claude', 'skills'),
      path.join(ancestor, '.agents', 'skills'),
    ];
    return candidates.some((candidate) => isPathInside(resolvedPath, candidate));
  });

  if (isProjectScoped) {
    return { scope: 'project', source };
  }

  const home = os.homedir();
  const userRoots = [
    path.join(home, '.config', 'opencode'),
    path.join(home, '.opencode'),
    path.join(home, '.claude', 'skills'),
    path.join(home, '.agents', 'skills'),
    process.env.OPENCODE_CONFIG_DIR ? path.resolve(process.env.OPENCODE_CONFIG_DIR) : null,
  ].filter((value): value is string => Boolean(value));

  if (userRoots.some((root) => isPathInside(resolvedPath, root))) {
    return { scope: 'user', source };
  }

  return { scope: 'user', source };
};

const fetchOpenCodeSkillsFromApi = async (ctx: BridgeContext | undefined, workingDirectory?: string): Promise<DiscoveredSkill[] | null> => {
  const apiUrl = ctx?.manager?.getApiUrl();
  if (!apiUrl) {
    return null;
  }

  try {
    const base = apiUrl.endsWith('/') ? apiUrl : `${apiUrl}/`;
    const url = new URL('skill', base);
    if (workingDirectory) {
      url.searchParams.set('directory', workingDirectory);
    }

    const response = await fetch(url.toString(), {
      method: 'GET',
      headers: {
        Accept: 'application/json',
        ...(ctx?.manager?.getOpenCodeAuthHeaders() || {}),
      },
      signal: AbortSignal.timeout(8_000),
    });

    if (!response.ok) {
      return null;
    }

    const payload = await response.json();
    if (!Array.isArray(payload)) {
      return null;
    }

    return payload
      .map((item) => {
        const name = typeof item?.name === 'string' ? item.name.trim() : '';
        const location = typeof item?.location === 'string' ? item.location : '';
        const description = typeof item?.description === 'string' ? item.description : '';
        if (!name || !location) {
          return null;
        }
        const inferred = inferSkillScopeAndSourceFromLocation(location, workingDirectory);
        return {
          name,
          path: location,
          scope: inferred.scope,
          source: inferred.source,
          description,
        } as DiscoveredSkill;
      })
      .filter((item): item is DiscoveredSkill => item !== null);
  } catch {
    return null;
  }
};

const readSharedSettingsFromDisk = (): Record<string, unknown> => {
  try {
    const raw = fs.readFileSync(OPENCHAMBER_SHARED_SETTINGS_PATH, 'utf8');
    const parsed = JSON.parse(raw) as unknown;
    if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
      return parsed as Record<string, unknown>;
    }
    return {};
  } catch {
    return {};
  }
};

const writeSharedSettingsToDisk = async (changes: Record<string, unknown>): Promise<void> => {
  try {
    await fs.promises.mkdir(path.dirname(OPENCHAMBER_SHARED_SETTINGS_PATH), { recursive: true });
    const current = readSharedSettingsFromDisk();
    const next: Record<string, unknown> = { ...current, ...changes };
    // Keep empty-string sentinel (""), so other runtimes can detect explicit clears.
    await fs.promises.writeFile(OPENCHAMBER_SHARED_SETTINGS_PATH, JSON.stringify(next, null, 2), 'utf8');
  } catch {
    // ignore
  }
};

const readSettings = (ctx?: BridgeContext) => {
  const stored = ctx?.context?.globalState.get<Record<string, unknown>>(SETTINGS_KEY) || {};
  const restStored = { ...stored };
  delete (restStored as Record<string, unknown>).lastDirectory;
  const shared = readSharedSettingsFromDisk();
  const sharedOpencodeBinary = typeof shared.opencodeBinary === 'string' ? shared.opencodeBinary.trim() : '';
  const workspaceFolder = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath || '';
  const themeVariant =
    vscode.window.activeColorTheme.kind === vscode.ColorThemeKind.Light ||
    vscode.window.activeColorTheme.kind === vscode.ColorThemeKind.HighContrastLight
      ? 'light'
      : 'dark';

  return {
    themeVariant,
    lastDirectory: workspaceFolder,
    ...restStored,
    opencodeBinary:
      typeof restStored.opencodeBinary === 'string'
        ? String(restStored.opencodeBinary).trim()
        : (sharedOpencodeBinary || undefined),
  };
};

const readStringField = (value: unknown, key: string): string => {
  if (!value || typeof value !== 'object') return '';
  const record = value as Record<string, unknown>;
  const candidate = record[key];
  return typeof candidate === 'string' ? candidate.trim() : '';
};

const readBooleanField = (value: unknown, key: string): boolean | undefined => {
  if (!value || typeof value !== 'object') return undefined;
  const record = value as Record<string, unknown>;
  const candidate = record[key];
  return typeof candidate === 'boolean' ? candidate : undefined;
};

const readNumberField = (value: unknown, key: string): number | undefined => {
  if (!value || typeof value !== 'object') return undefined;
  const record = value as Record<string, unknown>;
  const candidate = record[key];
  return typeof candidate === 'number' && Number.isFinite(candidate) ? candidate : undefined;
};

const normalizeMergeMethod = (value: string): 'merge' | 'squash' | 'rebase' => {
  const trimmed = value.trim();
  if (trimmed === 'merge' || trimmed === 'squash' || trimmed === 'rebase') return trimmed;
  return 'merge';
};

const BRIDGE_ZEN_DEFAULT_MODEL = 'gpt-5-nano';
const BRIDGE_GIT_GENERATION_TIMEOUT_MS = 2 * 60 * 1000;
const BRIDGE_GIT_GENERATION_POLL_INTERVAL_MS = 500;
let bridgeGitModelCatalogCache: Set<string> | null = null;
let bridgeGitModelCatalogCacheAt = 0;
const BRIDGE_GIT_MODEL_CATALOG_CACHE_TTL_MS = 30 * 1000;

const sleep = (ms: number) => new Promise<void>((resolve) => {
  setTimeout(resolve, ms);
});

const fetchBridgeGitModelCatalog = async (
  apiUrl: string,
  authHeaders?: Record<string, string>
): Promise<Set<string>> => {
  const now = Date.now();
  if (bridgeGitModelCatalogCache && now - bridgeGitModelCatalogCacheAt < BRIDGE_GIT_MODEL_CATALOG_CACHE_TTL_MS) {
    return bridgeGitModelCatalogCache;
  }

  const headers = authHeaders || {};
  const modelsUrl = new URL(`${apiUrl.replace(/\/+$/, '')}/model`);
  const response = await fetch(modelsUrl.toString(), {
    method: 'GET',
    headers: {
      Accept: 'application/json',
      ...headers,
    },
    signal: AbortSignal.timeout(8_000),
  });

  if (!response.ok) {
    throw new Error('Failed to fetch model catalog');
  }

  const payload = await response.json().catch(() => null) as unknown;
  const refs = new Set<string>();
  if (Array.isArray(payload)) {
    for (const item of payload) {
      if (!item || typeof item !== 'object') {
        continue;
      }
      const record = item as Record<string, unknown>;
      const providerID = typeof record.providerID === 'string' ? record.providerID.trim() : '';
      const modelID = typeof record.modelID === 'string' ? record.modelID.trim() : '';
      if (providerID && modelID) {
        refs.add(`${providerID}/${modelID}`);
      }
    }
  }

  bridgeGitModelCatalogCache = refs;
  bridgeGitModelCatalogCacheAt = now;
  return refs;
};

const resolveBridgeGitGenerationModel = async (
  payloadModel: { providerId?: string; modelId?: string; zenModel?: string },
  settings: Record<string, unknown>,
  apiUrl: string,
  authHeaders?: Record<string, string>
): Promise<{ providerID: string; modelID: string }> => {
  let catalog: Set<string> | null = null;
  try {
    catalog = await fetchBridgeGitModelCatalog(apiUrl, authHeaders);
  } catch {
    catalog = null;
  }

  const hasModel = (providerID: string, modelID: string): boolean => {
    if (!catalog) {
      return false;
    }
    return catalog.has(`${providerID}/${modelID}`);
  };

  const requestProviderId = typeof payloadModel.providerId === 'string' ? payloadModel.providerId.trim() : '';
  const requestModelId = typeof payloadModel.modelId === 'string' ? payloadModel.modelId.trim() : '';
  if (requestProviderId && requestModelId && hasModel(requestProviderId, requestModelId)) {
    return { providerID: requestProviderId, modelID: requestModelId };
  }

  const settingsProviderId = readStringField(settings, 'gitProviderId');
  const settingsModelId = readStringField(settings, 'gitModelId');
  if (settingsProviderId && settingsModelId && hasModel(settingsProviderId, settingsModelId)) {
    return { providerID: settingsProviderId, modelID: settingsModelId };
  }

  const payloadZenModel = typeof payloadModel.zenModel === 'string' ? payloadModel.zenModel.trim() : '';
  const settingsZenModel = readStringField(settings, 'zenModel');
  return {
    providerID: 'zen',
    modelID: payloadZenModel || settingsZenModel || BRIDGE_ZEN_DEFAULT_MODEL,
  };
};

const extractTextFromMessageParts = (parts: unknown): string => {
  if (!Array.isArray(parts)) {
    return '';
  }

  const textParts = parts
    .filter((part) => {
      if (!part || typeof part !== 'object') return false;
      const record = part as Record<string, unknown>;
      return record.type === 'text' && typeof record.text === 'string';
    })
    .map((part) => (part as Record<string, unknown>).text as string)
    .map((text) => text.trim())
    .filter((text) => text.length > 0);

  return textParts.join('\n').trim();
};

const generateBridgeTextWithSessionFlow = async ({
  apiUrl,
  directory,
  prompt,
  providerID,
  modelID,
  authHeaders,
}: {
  apiUrl: string;
  directory: string;
  prompt: string;
  providerID: string;
  modelID: string;
  authHeaders?: Record<string, string>;
}): Promise<string> => {
  const headers = authHeaders || {};
  const apiBase = apiUrl.replace(/\/+$/, '');
  const deadlineAt = Date.now() + BRIDGE_GIT_GENERATION_TIMEOUT_MS;
  const remainingMs = () => Math.max(1_000, deadlineAt - Date.now());
  let sessionId: string | null = null;

  try {
    const sessionUrl = new URL(`${apiBase}/session`);
    if (directory) {
      sessionUrl.searchParams.set('directory', directory);
    }

    const createResponse = await fetch(sessionUrl.toString(), {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        ...headers,
      },
      body: JSON.stringify({ title: 'Git Generation' }),
      signal: AbortSignal.timeout(remainingMs()),
    });

    if (!createResponse.ok) {
      throw new Error('Failed to create OpenCode session');
    }

    const session = await createResponse.json().catch(() => null) as unknown;
    const sessionObj = session && typeof session === 'object' ? session as Record<string, unknown> : null;
    const createdSessionId = sessionObj && typeof sessionObj.id === 'string' ? sessionObj.id : '';
    if (!createdSessionId) {
      throw new Error('Invalid session response');
    }
    sessionId = createdSessionId;

    const promptUrl = new URL(`${apiBase}/session/${encodeURIComponent(sessionId)}/prompt_async`);
    if (directory) {
      promptUrl.searchParams.set('directory', directory);
    }

    const promptResponse = await fetch(promptUrl.toString(), {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        ...headers,
      },
      body: JSON.stringify({
        model: {
          providerID,
          modelID,
        },
        parts: [{ type: 'text', text: prompt }],
      }),
      signal: AbortSignal.timeout(remainingMs()),
    });

    if (!promptResponse.ok) {
      throw new Error('Failed to send prompt');
    }

    const messagesUrl = new URL(`${apiBase}/session/${encodeURIComponent(sessionId)}/message`);
    if (directory) {
      messagesUrl.searchParams.set('directory', directory);
    }
    messagesUrl.searchParams.set('limit', '10');

    while (Date.now() < deadlineAt) {
      await sleep(BRIDGE_GIT_GENERATION_POLL_INTERVAL_MS);

      const messagesResponse = await fetch(messagesUrl.toString(), {
        method: 'GET',
        headers: {
          Accept: 'application/json',
          ...headers,
        },
        signal: AbortSignal.timeout(remainingMs()),
      });

      if (!messagesResponse.ok) {
        continue;
      }

      const messages = await messagesResponse.json().catch(() => null) as unknown;
      if (!Array.isArray(messages)) {
        continue;
      }

      for (let i = messages.length - 1; i >= 0; i--) {
        const message = messages[i] as Record<string, unknown> | null;
        if (!message || typeof message !== 'object') {
          continue;
        }
        const info = message.info as Record<string, unknown> | undefined;
        if (info?.role !== 'assistant' || info?.finish !== 'stop') {
          continue;
        }

        const text = extractTextFromMessageParts(message.parts);
        if (text) {
          return text;
        }
      }
    }

    throw new Error('Timeout waiting for generation to complete');
  } finally {
    if (sessionId) {
      const deleteUrl = new URL(`${apiBase}/session/${encodeURIComponent(sessionId)}`);
      try {
        await fetch(deleteUrl.toString(), {
          method: 'DELETE',
          headers,
          signal: AbortSignal.timeout(5_000),
        });
      } catch {
        // ignore cleanup failures
      }
    }
  }
};

const parseJsonObjectSafe = (value: string): Record<string, unknown> | null => {
  try {
    const parsed = JSON.parse(value) as unknown;
    if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return null;
    return parsed as Record<string, unknown>;
  } catch {
    return null;
  }
};

const persistSettings = async (changes: Record<string, unknown>, ctx?: BridgeContext) => {
  const current = readSettings(ctx);
  const restChanges = { ...(changes || {}) };
  delete restChanges.lastDirectory;

  const keysToClear = new Set<string>();

  // Normalize empty-string clears to key removal (match web/desktop behavior)
  for (const key of ['defaultModel', 'defaultVariant', 'defaultAgent', 'defaultGitIdentityId', 'opencodeBinary']) {
    const value = restChanges[key];
    if (typeof value === 'string' && value.trim().length === 0) {
      keysToClear.add(key);
      delete restChanges[key];
    }
  }

  if (typeof restChanges.usageAutoRefresh !== 'boolean') {
    delete restChanges.usageAutoRefresh;
  }

  if (typeof restChanges.usageRefreshIntervalMs === 'number' && Number.isFinite(restChanges.usageRefreshIntervalMs)) {
    restChanges.usageRefreshIntervalMs = Math.max(30000, Math.min(300000, Math.round(restChanges.usageRefreshIntervalMs)));
  } else {
    delete restChanges.usageRefreshIntervalMs;
  }

  const merged = { ...current, ...restChanges, lastDirectory: current.lastDirectory } as Record<string, unknown>;
  for (const key of keysToClear) {
    delete merged[key];
  }
  await ctx?.context?.globalState.update(SETTINGS_KEY, merged);

  if (keysToClear.has('opencodeBinary')) {
    await writeSharedSettingsToDisk({ opencodeBinary: '' });
  } else if (typeof restChanges.opencodeBinary === 'string') {
    await writeSharedSettingsToDisk({ opencodeBinary: restChanges.opencodeBinary.trim() });
  }

  return merged;
};

const normalizeFsPath = (value: string) => value.replace(/\\/g, '/');

const isSocketPath = async (candidate: string): Promise<boolean> => {
  if (!candidate) {
    return false;
  }
  try {
    const stat = await fs.promises.stat(candidate);
    return typeof stat.isSocket === 'function' && stat.isSocket();
  } catch {
    return false;
  }
};

const resolveSshAuthSock = async (): Promise<string | undefined> => {
  const existing = (process.env.SSH_AUTH_SOCK || '').trim();
  if (existing) {
    return existing;
  }

  if (process.platform === 'win32') {
    return undefined;
  }

  const gpgSock = path.join(os.homedir(), '.gnupg', 'S.gpg-agent.ssh');
  if (await isSocketPath(gpgSock)) {
    return gpgSock;
  }

  const runGpgconf = async (args: string[]): Promise<string> => {
    for (const candidate of gpgconfCandidates) {
      try {
        const { stdout } = await execFileAsync(candidate, args);
        return String(stdout || '');
      } catch {
        continue;
      }
    }
    return '';
  };

  const candidate = (await runGpgconf(['--list-dirs', 'agent-ssh-socket'])).trim();
  if (candidate && await isSocketPath(candidate)) {
    return candidate;
  }

  if (candidate) {
    await runGpgconf(['--launch', 'gpg-agent']);
    const retried = (await runGpgconf(['--list-dirs', 'agent-ssh-socket'])).trim();
    if (retried && await isSocketPath(retried)) {
      return retried;
    }
  }

  return undefined;
};

const buildGitEnv = async (): Promise<NodeJS.ProcessEnv> => {
  const env: NodeJS.ProcessEnv = { ...process.env, GIT_TERMINAL_PROMPT: '0' };
  if (!env.SSH_AUTH_SOCK || !env.SSH_AUTH_SOCK.trim()) {
    const resolved = await resolveSshAuthSock();
    if (resolved) {
      env.SSH_AUTH_SOCK = resolved;
    }
  }
  return env;
};

const execGit = async (args: string[], cwd: string): Promise<{ stdout: string; stderr: string; exitCode: number }> => {
  const env = await buildGitEnv();
  return new Promise((resolve) => {
    const proc = spawn('git', args, {
      cwd,
      stdio: ['ignore', 'pipe', 'pipe'],
      env,
      windowsHide: true,
    });

    let stdout = '';
    let stderr = '';

    proc.stdout?.on('data', (data) => {
      stdout += data.toString();
    });

    proc.stderr?.on('data', (data) => {
      stderr += data.toString();
    });

    proc.on('close', (code) => {
      resolve({ stdout, stderr, exitCode: code ?? 0 });
    });

    proc.on('error', (error) => {
      resolve({ stdout: '', stderr: error instanceof Error ? error.message : String(error), exitCode: 1 });
    });
  });
};

const gitCheckIgnoreNames = async (cwd: string, names: string[]): Promise<Set<string>> => {
  if (names.length === 0) {
    return new Set();
  }

  const result = await execGit(['check-ignore', '--', ...names], cwd);
  if (result.exitCode !== 0 || !result.stdout) {
    return new Set();
  }

  return new Set(
    result.stdout
      .split('\n')
      .map((name: string) => name.trim())
      .filter(Boolean)
  );
};

const gitCheckIgnorePaths = async (cwd: string, paths: string[]): Promise<Set<string>> => {
  if (paths.length === 0) {
    return new Set();
  }

  const result = await execGit(['check-ignore', '--', ...paths], cwd);
  if (result.exitCode !== 0 || !result.stdout) {
    return new Set();
  }

  return new Set(
    result.stdout
      .split('\n')
      .map((name: string) => name.trim())
      .filter(Boolean)
  );
};

const expandTildePath = (value: string) => {
  const trimmed = (value || '').trim();
  if (!trimmed) {
    return trimmed;
  }

  if (trimmed === '~') {
    return os.homedir();
  }

  if (trimmed.startsWith('~/') || trimmed.startsWith('~\\')) {
    return path.join(os.homedir(), trimmed.slice(2));
  }

  return trimmed;
};

const resolveUserPath = (value: string, baseDirectory: string) => {
  const expanded = expandTildePath(value);
  if (!expanded) {
    return expanded;
  }
  if (path.isAbsolute(expanded)) {
    return expanded;
  }
  return path.resolve(baseDirectory, expanded);
};

const listDirectoryEntries = async (dirPath: string) => {
  const uri = vscode.Uri.file(dirPath);
  const entries = await vscode.workspace.fs.readDirectory(uri);
  return entries.map(([name, fileType]) => ({
    name,
    path: normalizeFsPath(vscode.Uri.joinPath(uri, name).fsPath),
    isDirectory: fileType === vscode.FileType.Directory,
  }));
};

const FILE_SEARCH_EXCLUDED_DIRS = new Set([
  'node_modules',
  '.git',
  'dist',
  'build',
  '.next',
  '.turbo',
  '.cache',
  'coverage',
  'tmp',
  'logs',
]);

const shouldSkipSearchDirectory = (name: string, includeHidden: boolean) => {
  if (!name) {
    return false;
  }
  if (!includeHidden && name.startsWith('.')) {
    return true;
  }
  return FILE_SEARCH_EXCLUDED_DIRS.has(name.toLowerCase());
};

/**
 * Fuzzy match scoring function.
 * Returns a score > 0 if the query fuzzy-matches the candidate, null otherwise.
 * Higher scores indicate better matches.
 */
const fuzzyMatchScore = (query: string, candidate: string): number | null => {
  if (!query) return 0;

  const q = query.toLowerCase();
  const c = candidate.toLowerCase();

  // Fast path: exact substring match gets high score
  if (c.includes(q)) {
    const idx = c.indexOf(q);
    let bonus = 0;
    if (idx === 0) {
      bonus = 20;
    } else {
      const prev = c[idx - 1];
      if (prev === '/' || prev === '_' || prev === '-' || prev === '.' || prev === ' ') {
        bonus = 15;
      }
    }
    return 100 + bonus - Math.min(idx, 20) - Math.floor(c.length / 5);
  }

  // Fuzzy match: all query chars must appear in order
  let score = 0;
  let lastIndex = -1;
  let consecutive = 0;

  for (let i = 0; i < q.length; i++) {
    const ch = q[i];
    if (!ch || ch === ' ') continue;

    const idx = c.indexOf(ch, lastIndex + 1);
    if (idx === -1) {
      return null; // No match
    }

    const gap = idx - lastIndex - 1;
    if (gap === 0) {
      consecutive++;
    } else {
      consecutive = 0;
    }

    score += 10;
    score += Math.max(0, 18 - idx); // Prefer matches near start
    score -= Math.min(gap, 10); // Penalize gaps

    // Bonus for word boundary matches
    if (idx === 0) {
      score += 12;
    } else {
      const prev = c[idx - 1];
      if (prev === '/' || prev === '_' || prev === '-' || prev === '.' || prev === ' ') {
        score += 10;
      }
    }

    score += consecutive > 0 ? 12 : 0; // Bonus for consecutive matches
    lastIndex = idx;
  }

  // Prefer shorter paths
  score += Math.max(0, 24 - Math.floor(c.length / 3));

  return score;
};

const searchFilesystemFiles = async (
  rootPath: string,
  query: string,
  limit: number,
  includeHidden: boolean,
  respectGitignore: boolean,
  timeBudgetMs?: number
) => {
  const normalizedQuery = (query || '').trim().toLowerCase();
  const matchAll = normalizedQuery.length === 0;
  const deadline = typeof timeBudgetMs === 'number' && timeBudgetMs > 0 ? Date.now() + timeBudgetMs : null;

  const rootUri = vscode.Uri.file(rootPath);
  const queue: vscode.Uri[] = [rootUri];
  const visited = new Set<string>([normalizeFsPath(rootUri.fsPath)]);
  // Collect more candidates for fuzzy matching, then sort and trim
  const collectLimit = matchAll ? limit : Math.max(limit * 3, 200);
  const candidates: Array<{ name: string; path: string; relativePath: string; extension?: string; score: number }> = [];
  const MAX_CONCURRENCY = 10;

  while (queue.length > 0 && candidates.length < collectLimit) {
    if (deadline && Date.now() > deadline) {
      break;
    }
    const batch = queue.splice(0, MAX_CONCURRENCY);
    const dirLists = await Promise.all(
      batch.map((dir) => Promise.resolve(vscode.workspace.fs.readDirectory(dir)).catch(() => [] as [string, vscode.FileType][]))
    );

    for (let index = 0; index < batch.length; index += 1) {
      if (deadline && Date.now() > deadline) {
        break;
      }
      const currentDir = batch[index];
      const dirents = dirLists[index];

      const ignoredNames = respectGitignore
        ? await gitCheckIgnoreNames(normalizeFsPath(currentDir.fsPath), dirents.map(([name]) => name))
        : new Set<string>();

      for (const [entryName, entryType] of dirents) {
        if (!entryName || (!includeHidden && entryName.startsWith('.'))) {
          continue;
        }

        if (respectGitignore && ignoredNames.has(entryName)) {
          continue;
        }

        const entryUri = vscode.Uri.joinPath(currentDir, entryName);
        const absolute = normalizeFsPath(entryUri.fsPath);

        if (entryType === vscode.FileType.Directory) {
          if (shouldSkipSearchDirectory(entryName, includeHidden)) {
            continue;
          }
          if (!visited.has(absolute)) {
            visited.add(absolute);
            queue.push(entryUri);
          }
          continue;
        }

        if (entryType !== vscode.FileType.File) {
          continue;
        }

        const relativePath = normalizeFsPath(path.relative(rootPath, absolute) || path.basename(absolute));
        const extension = entryName.includes('.') ? entryName.split('.').pop()?.toLowerCase() : undefined;

        if (matchAll) {
          candidates.push({
            name: entryName,
            path: absolute,
            relativePath,
            extension,
            score: 0,
          });
        } else {
          // Try fuzzy match against relative path (includes filename)
          const score = fuzzyMatchScore(normalizedQuery, relativePath);
          if (score !== null) {
            candidates.push({
              name: entryName,
              path: absolute,
              relativePath,
              extension,
              score,
            });
          }
        }

        if (candidates.length >= collectLimit) {
          queue.length = 0;
          break;
        }
      }

      if (candidates.length >= collectLimit) {
        break;
      }
    }
  }

  // Sort by score descending, then by path length, then alphabetically
  if (!matchAll) {
    candidates.sort((a, b) => {
      if (b.score !== a.score) return b.score - a.score;
      if (a.relativePath.length !== b.relativePath.length) {
        return a.relativePath.length - b.relativePath.length;
      }
      return a.relativePath.localeCompare(b.relativePath);
    });
  }

  // Return top results without the score field
  return candidates.slice(0, limit).map(({ name, path: filePath, relativePath, extension }) => ({
    name,
    path: filePath,
    relativePath,
    extension,
  }));
};

const searchDirectory = async (
  directory: string,
  query: string,
  limit = 60,
  includeHidden = false,
  respectGitignore = true
) => {
  const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath || os.homedir();
  const rootPath = directory
    ? resolveUserPath(directory, workspaceRoot)
    : vscode.workspace.workspaceFolders?.[0]?.uri.fsPath || '';
  if (!rootPath) return [];

  const sanitizedQuery = query?.trim() || '';
  if (!sanitizedQuery) {
    return searchFilesystemFiles(rootPath, '', limit, includeHidden, respectGitignore);
  }

  const escapeGlob = (value: string) => value
    .replace(/[\\{}()?*]/g, '\\$&')
    .replace(/\[/g, '\\[')
    .replace(/\]/g, '\\]');
  const exclude = '**/{node_modules,.git,dist,build,.next,.turbo,.cache,coverage,tmp,logs}/**';
  const mapResults = (results: vscode.Uri[]) => results.map((file) => {
    const absolute = normalizeFsPath(file.fsPath);
    const relative = normalizeFsPath(path.relative(rootPath, absolute));
    const name = path.basename(absolute);
    return {
      name,
      path: absolute,
      relativePath: relative || name,
      extension: name.includes('.') ? name.split('.').pop()?.toLowerCase() : undefined,
    };
  });
  const filterGitIgnored = async (results: vscode.Uri[]) => {
    if (!respectGitignore || results.length === 0) {
      return results;
    }

    const relativePaths = results.map((file) => {
      const relative = normalizeFsPath(path.relative(rootPath, file.fsPath));
      return relative || path.basename(file.fsPath);
    });

    const ignored = await gitCheckIgnorePaths(rootPath, relativePaths);
    if (ignored.size === 0) {
      return results;
    }

    return results.filter((_, index) => !ignored.has(relativePaths[index]));
  };

  // Fast-path via VS Code's file index (may be case-sensitive depending on platform/workspace).
  try {
    const escapedQuery = escapeGlob(sanitizedQuery);
    const pattern = `**/*${escapedQuery}*`;
    const results = await vscode.workspace.findFiles(
      new vscode.RelativePattern(vscode.Uri.file(rootPath), pattern),
      exclude,
      limit,
    );

    if (Array.isArray(results) && results.length > 0) {
      const visible = includeHidden ? results : results.filter((file) => !path.basename(file.fsPath).startsWith('.'));
      const filtered = await filterGitIgnored(visible);
      if (filtered.length > 0) {
        return mapResults(filtered);
      }
    }

    if (sanitizedQuery.length >= 2 && sanitizedQuery.length <= 32) {
      const fuzzyPattern = `**/*${escapedQuery.split('').join('*')}*`;
      const fuzzyResults = await vscode.workspace.findFiles(
        new vscode.RelativePattern(vscode.Uri.file(rootPath), fuzzyPattern),
        exclude,
        limit,
      );

      if (Array.isArray(fuzzyResults) && fuzzyResults.length > 0) {
        const visible = includeHidden ? fuzzyResults : fuzzyResults.filter((file) => !path.basename(file.fsPath).startsWith('.'));
        const filtered = await filterGitIgnored(visible);
        if (filtered.length > 0) {
          return mapResults(filtered);
        }
      }
    }
  } catch {
    // Fall through to filesystem traversal.
  }

  // Fallback: deterministic, case-insensitive traversal with early-exit at limit.
  return searchFilesystemFiles(rootPath, sanitizedQuery, limit, includeHidden, respectGitignore, 1500);
};

const fetchModelsMetadata = async () => {
  const controller = typeof AbortController !== 'undefined' ? new AbortController() : undefined;
  const timeout = controller ? setTimeout(() => controller.abort(), 8000) : undefined;
  try {
    const response = await fetch('https://models.dev/api.json', {
      signal: controller?.signal,
      headers: { Accept: 'application/json' },
    });
    if (!response.ok) {
      throw new Error(`models.dev responded with ${response.status}`);
    }
    return await response.json();
  } finally {
    if (timeout) {
      clearTimeout(timeout);
    }
  }
};

const base64EncodeUtf8 = (text: string) => Buffer.from(text, 'utf8').toString('base64');

const collectHeaders = (headers: Headers): Record<string, string> => {
  const result: Record<string, string> = {};
  headers.forEach((value, key) => {
    result[key] = value;
  });
  return result;
};

const buildUnavailableApiResponse = (): ApiProxyResponsePayload => {
  const body = JSON.stringify({ error: 'OpenCode API unavailable' });
  return {
    status: 503,
    headers: { 'content-type': 'application/json' },
    bodyBase64: base64EncodeUtf8(body),
  };
};

const sanitizeForwardHeaders = (input: Record<string, string> | undefined): Record<string, string> => {
  const headers: Record<string, string> = { ...(input || {}) };
  delete headers['content-length'];
  delete headers['host'];
  delete headers['connection'];
  return headers;
};

const getFsAccessRoot = (): string => vscode.workspace.workspaceFolders?.[0]?.uri.fsPath || os.homedir();

const getFsMimeType = (filePath: string): string => {
  const ext = path.extname(filePath).toLowerCase();
  const mimeMap: Record<string, string> = {
    '.png': 'image/png',
    '.jpg': 'image/jpeg',
    '.jpeg': 'image/jpeg',
    '.gif': 'image/gif',
    '.webp': 'image/webp',
    '.svg': 'image/svg+xml',
    '.txt': 'text/plain; charset=utf-8',
    '.md': 'text/markdown; charset=utf-8',
    '.markdown': 'text/markdown; charset=utf-8',
    '.mmd': 'text/plain; charset=utf-8',
    '.mermaid': 'text/plain; charset=utf-8',
    '.json': 'application/json; charset=utf-8',
    '.pdf': 'application/pdf',
  };
  return mimeMap[ext] || 'application/octet-stream';
};

type FsReadPathResolution =
  | { ok: true; resolvedPath: string }
  | { ok: false; status: number; error: string };

const resolveFileReadPath = async (targetPath: string): Promise<FsReadPathResolution> => {
  const trimmed = targetPath.trim();
  if (!trimmed) {
    return { ok: false, status: 400, error: 'Path is required' };
  }

  const baseRoot = getFsAccessRoot();
  const resolved = resolveUserPath(trimmed, baseRoot);
  if (!resolved) {
    return { ok: false, status: 400, error: 'Path is required' };
  }

  try {
    const [canonicalPath, canonicalBase] = await Promise.all([
      fs.promises.realpath(resolved),
      fs.promises.realpath(baseRoot).catch(() => path.resolve(baseRoot)),
    ]);

    if (!isPathInside(canonicalPath, canonicalBase)) {
      return { ok: false, status: 403, error: 'Access to file denied' };
    }

    return { ok: true, resolvedPath: canonicalPath };
  } catch (error) {
    const err = error as NodeJS.ErrnoException;
    if (err?.code === 'ENOENT') {
      return { ok: false, status: 404, error: 'File not found' };
    }
    return { ok: false, status: 500, error: 'Failed to resolve file path' };
  }
};

const buildProxyJsonError = (status: number, error: string): ApiProxyResponsePayload => ({
  status,
  headers: { 'content-type': 'application/json' },
  bodyBase64: base64EncodeUtf8(JSON.stringify({ error })),
});

const tryHandleLocalFsProxy = async (method: string, requestPath: string): Promise<ApiProxyResponsePayload | null> => {
  let parsed: URL;
  try {
    parsed = new URL(requestPath, 'https://openchamber.local');
  } catch {
    return buildProxyJsonError(400, 'Invalid request path');
  }

  if (parsed.pathname !== '/api/fs/read' && parsed.pathname !== '/api/fs/raw') {
    return null;
  }

  if (method !== 'GET' && method !== 'HEAD') {
    return buildProxyJsonError(405, 'Method not allowed');
  }

  const targetPath = parsed.searchParams.get('path') || '';
  const resolution = await resolveFileReadPath(targetPath);
  if (!resolution.ok) {
    return buildProxyJsonError(resolution.status, resolution.error);
  }

  try {
    const stats = await fs.promises.stat(resolution.resolvedPath);
    if (!stats.isFile()) {
      return buildProxyJsonError(400, 'Specified path is not a file');
    }

    if (parsed.pathname === '/api/fs/read') {
      const content = await fs.promises.readFile(resolution.resolvedPath, 'utf8');
      return {
        status: 200,
        headers: {
          'content-type': 'text/plain; charset=utf-8',
          'cache-control': 'no-store',
        },
        bodyBase64: base64EncodeUtf8(content),
      };
    }

    const raw = await fs.promises.readFile(resolution.resolvedPath);
    return {
      status: 200,
      headers: {
        'content-type': getFsMimeType(resolution.resolvedPath),
        'cache-control': 'no-store',
      },
      bodyBase64: Buffer.from(raw).toString('base64'),
    };
  } catch (error) {
    const err = error as NodeJS.ErrnoException;
    if (err?.code === 'ENOENT') {
      return buildProxyJsonError(404, 'File not found');
    }
    return buildProxyJsonError(500, 'Unable to read file');
  }
};

export async function handleBridgeMessage(message: BridgeRequest, ctx?: BridgeContext): Promise<BridgeResponse> {
  const { id, type, payload } = message;

  try {
    switch (type) {
      case 'api:proxy': {
        const { method, path: requestPath, headers, bodyBase64 } = (payload || {}) as ApiProxyRequestPayload;
        const normalizedMethod = typeof method === 'string' && method.trim() ? method.trim().toUpperCase() : 'GET';
        const normalizedPath =
          typeof requestPath === 'string' && requestPath.trim().length > 0
            ? requestPath.trim().startsWith('/')
              ? requestPath.trim()
              : `/${requestPath.trim()}`
            : '/';

        const localFsResponse = await tryHandleLocalFsProxy(normalizedMethod, normalizedPath);
        if (localFsResponse) {
          return { id, type, success: true, data: localFsResponse };
        }

        const apiUrl = ctx?.manager?.getApiUrl();
        if (!apiUrl) {
          const data = buildUnavailableApiResponse();
          return { id, type, success: true, data };
        }

        const base = `${apiUrl.replace(/\/+$/, '')}/`;
        const targetUrl = new URL(normalizedPath.replace(/^\/+/, ''), base).toString();
        const requestHeaders: Record<string, string> = {
          ...sanitizeForwardHeaders(headers),
          ...ctx?.manager?.getOpenCodeAuthHeaders(),
        };

        // Ensure SSE requests are negotiated correctly.
        if (normalizedPath === '/event' || normalizedPath === '/global/event') {
          if (!requestHeaders.Accept) {
            requestHeaders.Accept = 'text/event-stream';
          }
          requestHeaders['Cache-Control'] = requestHeaders['Cache-Control'] || 'no-cache';
          requestHeaders.Connection = requestHeaders.Connection || 'keep-alive';
        }

        try {
          const response = await fetch(targetUrl, {
            method: normalizedMethod,
            headers: requestHeaders,
            body:
              typeof bodyBase64 === 'string' && bodyBase64.length > 0 && normalizedMethod !== 'GET' && normalizedMethod !== 'HEAD'
                ? Buffer.from(bodyBase64, 'base64')
                : undefined,
          });

          const arrayBuffer = await response.arrayBuffer();
          const data: ApiProxyResponsePayload = {
            status: response.status,
            headers: collectHeaders(response.headers),
            bodyBase64: Buffer.from(arrayBuffer).toString('base64'),
          };

          return { id, type, success: true, data };
        } catch (error) {
          const body = JSON.stringify({
            error: error instanceof Error ? error.message : 'Failed to reach OpenCode API',
          });
          const data: ApiProxyResponsePayload = {
            status: 502,
            headers: { 'content-type': 'application/json' },
            bodyBase64: base64EncodeUtf8(body),
          };
          return { id, type, success: true, data };
        }
      }

      case 'api:session:message': {
        const apiUrl = ctx?.manager?.getApiUrl();
        if (!apiUrl) {
          const data = buildUnavailableApiResponse();
          return { id, type, success: true, data };
        }

        const { path: requestPath, headers, bodyText } = (payload || {}) as ApiSessionMessageRequestPayload;
        const normalizedPath =
          typeof requestPath === 'string' && requestPath.trim().length > 0
            ? requestPath.trim().startsWith('/')
              ? requestPath.trim()
              : `/${requestPath.trim()}`
            : '/';

        if (!/^\/session\/[^/]+\/message(?:\?.*)?$/.test(normalizedPath)) {
          const body = JSON.stringify({ error: 'Invalid session message proxy path' });
          const data: ApiProxyResponsePayload = {
            status: 400,
            headers: { 'content-type': 'application/json' },
            bodyBase64: base64EncodeUtf8(body),
          };
          return { id, type, success: true, data };
        }

        const base = `${apiUrl.replace(/\/+$/, '')}/`;
        const targetUrl = new URL(normalizedPath.replace(/^\/+/, ''), base).toString();
        const requestHeaders: Record<string, string> = {
          ...sanitizeForwardHeaders(headers),
          ...ctx?.manager?.getOpenCodeAuthHeaders(),
        };

        try {
          const response = await fetch(targetUrl, {
            method: 'POST',
            headers: requestHeaders,
            body: typeof bodyText === 'string' ? bodyText : '',
            signal: AbortSignal.timeout(45000),
          });

          const arrayBuffer = await response.arrayBuffer();
          const data: ApiProxyResponsePayload = {
            status: response.status,
            headers: collectHeaders(response.headers),
            bodyBase64: Buffer.from(arrayBuffer).toString('base64'),
          };

          return { id, type, success: true, data };
        } catch (error) {
          const isTimeout =
            error instanceof Error &&
            ((error as Error & { name?: string }).name === 'TimeoutError' ||
              (error as Error & { name?: string }).name === 'AbortError');
          const body = JSON.stringify({
            error: isTimeout ? 'OpenCode message forward timed out' : error instanceof Error ? error.message : 'OpenCode message forward failed',
          });
          const data: ApiProxyResponsePayload = {
            status: isTimeout ? 504 : 503,
            headers: { 'content-type': 'application/json' },
            bodyBase64: base64EncodeUtf8(body),
          };
          return { id, type, success: true, data };
        }
      }

      case 'files:list': {
        const { path: dirPath } = payload as { path: string };
        const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath || os.homedir();
        const resolvedPath = resolveUserPath(dirPath, workspaceRoot);
        const uri = vscode.Uri.file(resolvedPath);
        const entries = await vscode.workspace.fs.readDirectory(uri);
        const result: FileEntry[] = entries.map(([name, fileType]) => ({
          name,
          path: vscode.Uri.joinPath(uri, name).fsPath,
          isDirectory: fileType === vscode.FileType.Directory,
        }));
        return { id, type, success: true, data: { directory: normalizeFsPath(resolvedPath), entries: result } };
      }

      case 'files:search': {
        const { query, maxResults = 50 } = payload as { query: string; maxResults?: number };
        const pattern = `**/*${query}*`;
        const files = await vscode.workspace.findFiles(pattern, '**/node_modules/**', maxResults);
        const results: FileSearchResult[] = files.map((file) => ({
          path: file.fsPath,
        }));
        return { id, type, success: true, data: results };
      }

      case 'workspace:folder': {
        const folder = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath || '';
        return { id, type, success: true, data: { folder } };
      }

      case 'config:get': {
        const { key } = payload as { key: string };
        const config = vscode.workspace.getConfiguration('openchamber');
        const value = config.get(key);
        return { id, type, success: true, data: { value } };
      }

      case 'api:fs:list': {
        const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath || os.homedir();
        const { path: targetPath, respectGitignore } = (payload || {}) as { path?: string; respectGitignore?: boolean };
        const target = targetPath || workspaceRoot;
        const resolvedPath = resolveUserPath(target, workspaceRoot) || workspaceRoot;

        const entries = await listDirectoryEntries(resolvedPath);
        const normalized = normalizeFsPath(resolvedPath);

        if (!respectGitignore) {
          return { id, type, success: true, data: { entries, directory: normalized, path: normalized } };
        }

        const pathsToCheck = entries.map((entry) => entry.name).filter(Boolean);
        if (pathsToCheck.length === 0) {
          return { id, type, success: true, data: { entries, directory: normalized, path: normalized } };
        }

        try {
          const result = await execGit(['check-ignore', '--', ...pathsToCheck], normalized);
          const ignoredNames = new Set(
            result.stdout
              .split('\n')
              .map((name) => name.trim())
              .filter(Boolean)
          );

          const filteredEntries = entries.filter((entry) => !ignoredNames.has(entry.name));
          return { id, type, success: true, data: { entries: filteredEntries, directory: normalized, path: normalized } };
        } catch {
          return { id, type, success: true, data: { entries, directory: normalized, path: normalized } };
        }
      }

       case 'api:fs:search': {
         const { directory = '', query = '', limit, includeHidden, respectGitignore } = (payload || {}) as {
           directory?: string;
           query?: string;
           limit?: number;
           includeHidden?: boolean;
           respectGitignore?: boolean;
         };
         const files = await searchDirectory(directory, query, limit, Boolean(includeHidden), respectGitignore !== false);
         return { id, type, success: true, data: { files } };
       }

      case 'api:fs:mkdir': {
        const target = (payload as { path: string })?.path;
        if (!target) {
          return { id, type, success: false, error: 'Path is required' };
        }
        const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath || os.homedir();
        const resolvedPath = resolveUserPath(target, workspaceRoot);
        await vscode.workspace.fs.createDirectory(vscode.Uri.file(resolvedPath));
        return { id, type, success: true, data: { success: true, path: normalizeFsPath(resolvedPath) } };
      }

      case 'api:fs/home': {
        // Match web/desktop semantics: OS home directory.
        return { id, type, success: true, data: { home: normalizeFsPath(os.homedir()) } };
      }

      case 'api:fs:read': {
        const target = (payload as { path: string })?.path;
        if (!target) {
          return { id, type, success: false, error: 'Path is required' };
        }

        const resolution = await resolveFileReadPath(target);
        if (!resolution.ok) {
          return { id, type, success: false, error: resolution.error };
        }

        try {
          const content = await fs.promises.readFile(resolution.resolvedPath, 'utf8');
          return { id, type, success: true, data: { content, path: normalizeFsPath(resolution.resolvedPath) } };
        } catch (error) {
          const message = error instanceof Error ? error.message : 'Failed to read file';
          return { id, type, success: false, error: message };
        }
      }

      case 'api:fs:write': {
        const { path: targetPath, content } = (payload as { path: string; content: string }) || {};
        if (!targetPath) {
          return { id, type, success: false, error: 'Path is required' };
        }
        if (typeof content !== 'string') {
          return { id, type, success: false, error: 'Content is required' };
        }
        try {
          const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath || os.homedir();
          const resolvedPath = resolveUserPath(targetPath, workspaceRoot);
          const uri = vscode.Uri.file(resolvedPath);
          // Ensure parent directory exists
          const parentUri = vscode.Uri.file(path.dirname(resolvedPath));
          try {
            await vscode.workspace.fs.createDirectory(parentUri);
          } catch {
            // Directory may already exist
          }
          await vscode.workspace.fs.writeFile(uri, Buffer.from(content, 'utf8'));
          return { id, type, success: true, data: { success: true, path: normalizeFsPath(resolvedPath) } };
        } catch (error) {
          const message = error instanceof Error ? error.message : 'Failed to write file';
          return { id, type, success: false, error: message };
        }
      }

      case 'api:fs:delete': {
        const targetPath = (payload as { path: string })?.path;
        if (!targetPath) {
          return { id, type, success: false, error: 'Path is required' };
        }
        try {
          const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath || os.homedir();
          const resolvedPath = resolveUserPath(targetPath, workspaceRoot);
          const uri = vscode.Uri.file(resolvedPath);
          await vscode.workspace.fs.delete(uri, { recursive: true, useTrash: false });
          return { id, type, success: true, data: { success: true } };
        } catch (error) {
          const message = error instanceof Error ? error.message : 'Failed to delete file';
          return { id, type, success: false, error: message };
        }
      }

      case 'api:fs:rename': {
        const { oldPath, newPath } = (payload as { oldPath: string; newPath: string }) || {};
        if (!oldPath) {
          return { id, type, success: false, error: 'oldPath is required' };
        }
        if (!newPath) {
          return { id, type, success: false, error: 'newPath is required' };
        }
        try {
          const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath || os.homedir();
          const resolvedOld = resolveUserPath(oldPath, workspaceRoot);
          const resolvedNew = resolveUserPath(newPath, workspaceRoot);
          const oldUri = vscode.Uri.file(resolvedOld);
          const newUri = vscode.Uri.file(resolvedNew);
          await vscode.workspace.fs.rename(oldUri, newUri, { overwrite: false });
          return { id, type, success: true, data: { success: true, path: normalizeFsPath(resolvedNew) } };
        } catch (error) {
          const message = error instanceof Error ? error.message : 'Failed to rename file';
          return { id, type, success: false, error: message };
        }
      }

      case 'api:fs:exec': {
        const { commands, cwd } = (payload as { commands: string[]; cwd: string }) || {};
        if (!Array.isArray(commands) || commands.length === 0) {
          return { id, type, success: false, error: 'Commands array is required' };
        }
        if (!cwd) {
          return { id, type, success: false, error: 'Working directory (cwd) is required' };
        }
        try {
          const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath || os.homedir();
          const resolvedCwd = resolveUserPath(cwd, workspaceRoot);
          const { exec } = await import('child_process');
          const { promisify } = await import('util');
          const execAsync = promisify(exec);
          const shell = process.env.SHELL || (process.platform === 'win32' ? 'cmd.exe' : '/bin/sh');
          const shellFlag = process.platform === 'win32' ? '/c' : '-c';

          const augmentedEnv = {
            ...process.env,
            PATH: process.env.PATH,
          };

          const results: Array<{
            command: string;
            success: boolean;
            exitCode?: number;
            stdout?: string;
            stderr?: string;
            error?: string;
          }> = [];

          for (const cmd of commands) {
            if (typeof cmd !== 'string' || !cmd.trim()) {
              results.push({ command: cmd, success: false, error: 'Invalid command' });
              continue;
            }
            try {
              // Use async exec to not block the extension host event loop
              const { stdout, stderr } = await execAsync(`${shell} ${shellFlag} "${cmd.replace(/"/g, '\\"')}"`, {
                cwd: resolvedCwd,
                env: augmentedEnv,
                timeout: 300000, // 5 minutes per command
              });
              results.push({
                command: cmd,
                success: true,
                exitCode: 0,
                stdout: (stdout || '').trim(),
                stderr: (stderr || '').trim(),
              });
            } catch (execError) {
              const err = execError as { code?: number; stdout?: string; stderr?: string; message?: string };
              results.push({
                command: cmd,
                success: false,
                exitCode: typeof err.code === 'number' ? err.code : 1,
                stdout: (err.stdout || '').trim(),
                stderr: (err.stderr || '').trim(),
                error: err.message,
              });
            }
          }

          const allSucceeded = results.every((r) => r.success);
          return { id, type, success: true, data: { success: allSucceeded, results } };
        } catch (error) {
          const message = error instanceof Error ? error.message : 'Failed to execute commands';
          return { id, type, success: false, error: message };
        }
      }

      case 'api:files/pick': {
        const allowMany = (payload as { allowMany?: boolean })?.allowMany !== false;
        const defaultUri = vscode.workspace.workspaceFolders?.[0]?.uri;

        const picks = await vscode.window.showOpenDialog({
          canSelectFiles: true,
          canSelectFolders: false,
          canSelectMany: allowMany,
          defaultUri,
          openLabel: 'Attach',
        });

        if (!picks || picks.length === 0) {
          return { id, type, success: true, data: { files: [], skipped: [] } };
        }

        const files: Array<{ name: string; mimeType: string; size: number; dataUrl: string }> = [];
        const skipped: Array<{ name: string; reason: string }> = [];

        for (const uri of picks) {
          const result = await readUriAsAttachment(uri);
          if ('file' in result) {
            files.push(result.file);
          } else {
            skipped.push(result.skipped);
          }
        }

        return { id, type, success: true, data: { files, skipped } };
      }

      case 'api:files/drop': {
        const uris = Array.isArray((payload as { uris?: unknown[] })?.uris)
          ? (payload as { uris: unknown[] }).uris.filter((value): value is string => typeof value === 'string' && value.trim().length > 0)
          : [];

        if (uris.length === 0) {
          return { id, type, success: true, data: { files: [], skipped: [] } };
        }

        const files: Array<{ name: string; mimeType: string; size: number; dataUrl: string }> = [];
        const skipped: Array<{ name: string; reason: string }> = [];

        const dedupedUris = Array.from(new Set(uris.map((value) => value.trim())));

        for (const rawUri of dedupedUris) {
          const parsed = parseDroppedFileReference(rawUri);
          if ('skipped' in parsed) {
            skipped.push(parsed.skipped);
            continue;
          }

          const uri = parsed.uri;

          const name = path.basename(uri.fsPath || uri.path || rawUri);

          const result = await readUriAsAttachment(uri, name);
          if ('file' in result) {
            files.push(result.file);
          } else {
            skipped.push(result.skipped);
          }
        }

        return { id, type, success: true, data: { files, skipped } };
      }

      case 'api:files/save-image': {
        const rawFileName = (payload as { fileName?: unknown })?.fileName;
        const rawDataUrl = (payload as { dataUrl?: unknown })?.dataUrl;
        const dataUrl = typeof rawDataUrl === 'string' ? rawDataUrl.trim() : '';
        if (!dataUrl.startsWith('data:image/')) {
          return { id, type, success: false, error: 'Invalid image payload' };
        }

        const defaultFileName = typeof rawFileName === 'string' && rawFileName.trim().length > 0
          ? rawFileName.trim()
          : `message-${Date.now()}.png`;

        const saveUri = await vscode.window.showSaveDialog({
          saveLabel: 'Save image',
          defaultUri: vscode.workspace.workspaceFolders?.[0]
            ? vscode.Uri.joinPath(vscode.workspace.workspaceFolders[0].uri, defaultFileName)
            : undefined,
          filters: { Images: ['png'] },
        });

        if (!saveUri) {
          return { id, type, success: true, data: { saved: false, canceled: true } };
        }

        const commaIndex = dataUrl.indexOf(',');
        if (commaIndex === -1) {
          return { id, type, success: false, error: 'Invalid image data URL' };
        }

        const base64 = dataUrl.slice(commaIndex + 1);
        const bytes = Buffer.from(base64, 'base64');
        await vscode.workspace.fs.writeFile(saveUri, bytes);

        return { id, type, success: true, data: { saved: true, path: saveUri.fsPath || saveUri.toString() } };
      }

      case 'api:config/settings:get': {
        const settings = readSettings(ctx);
        return { id, type, success: true, data: settings };
      }

      case 'api:config/settings:save': {
        const changes = (payload as Record<string, unknown>) || {};
        const updated = await persistSettings(changes, ctx);
        return { id, type, success: true, data: updated };
      }

      case 'api:github/auth:status': {
        const context = ctx?.context;
        if (!context) return { id, type, success: false, error: 'Missing VS Code context' };
        const list = await readGitHubAuthList(context);
        const accounts = list
          .filter((entry) => entry.user && entry.accountId)
          .map((entry) => ({
            id: entry.accountId as string,
            user: entry.user,
            scope: entry.scope,
            current: Boolean(entry.current),
          }));

        const stored = list.find((entry) => entry.current) || list[0];
        if (!stored?.accessToken) {
          return { id, type, success: true, data: { connected: false, accounts } };
        }

        try {
          const user = await fetchMe(stored.accessToken);
          return { id, type, success: true, data: { connected: true, user, scope: stored.scope, accounts } };
        } catch (error: unknown) {
          const status = (error && typeof error === 'object' && 'status' in error) ? (error as { status?: number }).status : undefined;
          const message = error instanceof Error ? error.message : String(error);
          if (status === 401 || message === 'unauthorized') {
            await clearGitHubAuth(context);
            const updatedAccounts = (await readGitHubAuthList(context))
              .filter((entry) => entry.user && entry.accountId)
              .map((entry) => ({
                id: entry.accountId as string,
                user: entry.user,
                scope: entry.scope,
                current: Boolean(entry.current),
              }));
            return { id, type, success: true, data: { connected: false, accounts: updatedAccounts } };
          }
          return { id, type, success: false, error: message };
        }
      }

      case 'api:github/auth:start': {
        const context = ctx?.context;
        if (!context) return { id, type, success: false, error: 'Missing VS Code context' };
        const settings = readSettings(ctx);
        const clientId = readStringField(settings, 'githubClientId') || DEFAULT_GITHUB_CLIENT_ID;
        const scopes = readStringField(settings, 'githubScopes') || DEFAULT_GITHUB_SCOPES;
        const flow = await startDeviceFlow(clientId, scopes);
        return { id, type, success: true, data: flow };
      }

      case 'api:github/auth:complete': {
        const context = ctx?.context;
        if (!context) return { id, type, success: false, error: 'Missing VS Code context' };
        const deviceCode = readStringField(payload, 'deviceCode');
        if (!deviceCode) return { id, type, success: false, error: 'deviceCode is required' };

        const settings = readSettings(ctx);
        const clientId = readStringField(settings, 'githubClientId') || DEFAULT_GITHUB_CLIENT_ID;

        const token = await exchangeDeviceCode(clientId, deviceCode);
        const tokenRecord = token && typeof token === 'object' ? (token as Record<string, unknown>) : null;
        const tokenError = typeof tokenRecord?.error === 'string' ? tokenRecord.error : '';
        const tokenErrorDescription = typeof tokenRecord?.error_description === 'string' ? tokenRecord.error_description : '';
        if (tokenError) {
          return {
            id,
            type,
            success: true,
            data: {
              connected: false,
              status: tokenError,
              error: tokenErrorDescription || tokenError,
            },
          };
        }
        const accessToken = typeof tokenRecord?.access_token === 'string' ? tokenRecord.access_token : '';
        if (!accessToken) {
          return { id, type, success: false, error: 'Missing access_token from GitHub' };
        }

        const user = await fetchMe(accessToken);
        await writeGitHubAuth(context, {
          accessToken,
          scope: typeof tokenRecord?.scope === 'string' ? tokenRecord.scope : undefined,
          tokenType: typeof tokenRecord?.token_type === 'string' ? tokenRecord.token_type : undefined,
          createdAt: Date.now(),
          user,
        });

        return {
          id,
          type,
          success: true,
          data: {
            connected: true,
            user,
            scope: typeof tokenRecord?.scope === 'string' ? tokenRecord.scope : undefined,
          },
        };
      }

      case 'api:github/auth:disconnect': {
        const context = ctx?.context;
        if (!context) return { id, type, success: false, error: 'Missing VS Code context' };
        const removed = await clearGitHubAuth(context);
        return { id, type, success: true, data: { removed } };
      }

      case 'api:github/auth:activate': {
        const context = ctx?.context;
        if (!context) return { id, type, success: false, error: 'Missing VS Code context' };
        const accountId = readStringField(payload, 'accountId');
        if (!accountId) return { id, type, success: false, error: 'accountId is required' };
        const activated = await activateGitHubAuth(context, accountId);
        if (!activated) return { id, type, success: false, error: 'GitHub account not found' };
        const list = await readGitHubAuthList(context);
        const accounts = list
          .filter((entry) => entry.user && entry.accountId)
          .map((entry) => ({
            id: entry.accountId as string,
            user: entry.user,
            scope: entry.scope,
            current: Boolean(entry.current),
          }));
        const stored = list.find((entry) => entry.current) || list[0];
        if (!stored?.accessToken) {
          return { id, type, success: true, data: { connected: false, accounts } };
        }
        try {
          const user = await fetchMe(stored.accessToken);
          return { id, type, success: true, data: { connected: true, user, scope: stored.scope, accounts } };
        } catch (error: unknown) {
          const status = (error && typeof error === 'object' && 'status' in error) ? (error as { status?: number }).status : undefined;
          const message = error instanceof Error ? error.message : String(error);
          if (status === 401 || message === 'unauthorized') {
            await clearGitHubAuth(context);
            const updatedAccounts = (await readGitHubAuthList(context))
              .filter((entry) => entry.user && entry.accountId)
              .map((entry) => ({
                id: entry.accountId as string,
                user: entry.user,
                scope: entry.scope,
                current: Boolean(entry.current),
              }));
            return { id, type, success: true, data: { connected: false, accounts: updatedAccounts } };
          }
          return { id, type, success: false, error: message };
        }
      }

      case 'api:github/me': {
        const context = ctx?.context;
        if (!context) return { id, type, success: false, error: 'Missing VS Code context' };
        const stored = await readGitHubAuth(context);
        if (!stored?.accessToken) return { id, type, success: false, error: 'GitHub not connected' };
        try {
          const user = await fetchMe(stored.accessToken);
          return { id, type, success: true, data: user };
        } catch (error: unknown) {
          const status = (error && typeof error === 'object' && 'status' in error) ? (error as { status?: number }).status : undefined;
          const message = error instanceof Error ? error.message : String(error);
          if (status === 401 || message === 'unauthorized') {
            await clearGitHubAuth(context);
            return { id, type, success: false, error: 'GitHub token expired or revoked' };
          }
          return { id, type, success: false, error: message };
        }
      }

      case 'api:github/pr:status': {
        const context = ctx?.context;
        if (!context) return { id, type, success: false, error: 'Missing VS Code context' };
        const directory = readStringField(payload, 'directory');
        const branch = readStringField(payload, 'branch');
        if (!directory || !branch) {
          return { id, type, success: false, error: 'directory and branch are required' };
        }

        const stored = await readGitHubAuth(context);
        if (!stored?.accessToken) {
          return { id, type, success: true, data: { connected: false } };
        }

        try {
          const result = await getPullRequestStatus(
            stored.accessToken,
            stored.user?.login || null,
            directory,
            branch,
          );
          if (result.connected === false) {
            await clearGitHubAuth(context);
          }
          return { id, type, success: true, data: result };
        } catch (error: unknown) {
          const message = error instanceof Error ? error.message : String(error);
          return { id, type, success: false, error: message };
        }
      }

      case 'api:github/pr:create': {
        const context = ctx?.context;
        if (!context) return { id, type, success: false, error: 'Missing VS Code context' };
        const stored = await readGitHubAuth(context);
        if (!stored?.accessToken) return { id, type, success: false, error: 'GitHub not connected' };
        const directory = readStringField(payload, 'directory');
        const title = readStringField(payload, 'title');
        const head = readStringField(payload, 'head');
        const base = readStringField(payload, 'base');
        const body = readStringField(payload, 'body');
        const draft = readBooleanField(payload, 'draft');
        if (!directory || !title || !head || !base) {
          return { id, type, success: false, error: 'directory, title, head, base are required' };
        }
        try {
          const pr = await createPullRequest(stored.accessToken, directory, {
            directory,
            title,
            head,
            base,
            ...(body ? { body } : {}),
            ...(typeof draft === 'boolean' ? { draft } : {}),
          });
          return { id, type, success: true, data: pr };
        } catch (error: unknown) {
          const message = error instanceof Error ? error.message : String(error);
          return { id, type, success: false, error: message };
        }
      }

      case 'api:github/pr:update': {
        const context = ctx?.context;
        if (!context) return { id, type, success: false, error: 'Missing VS Code context' };
        const stored = await readGitHubAuth(context);
        if (!stored?.accessToken) return { id, type, success: false, error: 'GitHub not connected' };
        const directory = readStringField(payload, 'directory');
        const number = readNumberField(payload, 'number') ?? 0;
        const title = readStringField(payload, 'title');
        const body = readStringField(payload, 'body');
        if (!directory || !number || !title) {
          return { id, type, success: false, error: 'directory, number, title are required' };
        }
        try {
          const pr = await updatePullRequest(stored.accessToken, directory, {
            directory,
            number,
            title,
            ...(typeof body === 'string' ? { body } : {}),
          });
          return { id, type, success: true, data: pr };
        } catch (error: unknown) {
          const status = (error && typeof error === 'object' && 'status' in error) ? (error as { status?: number }).status : undefined;
          const message = error instanceof Error ? error.message : String(error);
          if (status === 401 || message === 'unauthorized') {
            await clearGitHubAuth(context);
          }
          return { id, type, success: false, error: message };
        }
      }

      case 'api:github/pr:merge': {
        const context = ctx?.context;
        if (!context) return { id, type, success: false, error: 'Missing VS Code context' };
        const stored = await readGitHubAuth(context);
        if (!stored?.accessToken) return { id, type, success: false, error: 'GitHub not connected' };
        const directory = readStringField(payload, 'directory');
        const method = normalizeMergeMethod(readStringField(payload, 'method') || 'merge');
        const number = readNumberField(payload, 'number') ?? 0;
        if (!directory || !number) {
          return { id, type, success: false, error: 'directory and number are required' };
        }
        try {
          const result = await mergePullRequest(stored.accessToken, directory, {
            directory,
            number,
            method,
          });
          return { id, type, success: true, data: result };
        } catch (error: unknown) {
          const message = error instanceof Error ? error.message : String(error);
          return { id, type, success: false, error: message };
        }
      }

      case 'api:github/pr:ready': {
        const context = ctx?.context;
        if (!context) return { id, type, success: false, error: 'Missing VS Code context' };
        const stored = await readGitHubAuth(context);
        if (!stored?.accessToken) return { id, type, success: false, error: 'GitHub not connected' };
        const directory = readStringField(payload, 'directory');
        const number = readNumberField(payload, 'number') ?? 0;
        if (!directory || !number) {
          return { id, type, success: false, error: 'directory and number are required' };
        }
        try {
          const result = await markPullRequestReady(stored.accessToken, directory, number);
          return { id, type, success: true, data: result };
        } catch (error: unknown) {
          const status = (error && typeof error === 'object' && 'status' in error) ? (error as { status?: number }).status : undefined;
          const message = error instanceof Error ? error.message : String(error);
          if (status === 401 || message === 'unauthorized') {
            await clearGitHubAuth(context);
          }
          return { id, type, success: false, error: message };
        }
      }

      case 'api:github/issues:list': {
        const context = ctx?.context;
        if (!context) return { id, type, success: false, error: 'Missing VS Code context' };
        const stored = await readGitHubAuth(context);
        if (!stored?.accessToken) {
          return { id, type, success: true, data: { connected: false } };
        }
        const directory = readStringField(payload, 'directory');
        const page = readNumberField(payload, 'page') ?? 1;
        if (!directory) {
          return { id, type, success: false, error: 'directory is required' };
        }
        try {
          const result = await listIssues(stored.accessToken, directory, page);
          if (result.connected === false) {
            await clearGitHubAuth(context);
          }
          return { id, type, success: true, data: result };
        } catch (error: unknown) {
          const message = error instanceof Error ? error.message : String(error);
          return { id, type, success: false, error: message };
        }
      }

      case 'api:github/issues:get': {
        const context = ctx?.context;
        if (!context) return { id, type, success: false, error: 'Missing VS Code context' };
        const stored = await readGitHubAuth(context);
        if (!stored?.accessToken) {
          return { id, type, success: true, data: { connected: false } };
        }
        const directory = readStringField(payload, 'directory');
        const number = readNumberField(payload, 'number') ?? 0;
        if (!directory || !number) {
          return { id, type, success: false, error: 'directory and number are required' };
        }
        try {
          const result = await getIssue(stored.accessToken, directory, number);
          if (result.connected === false) {
            await clearGitHubAuth(context);
          }
          return { id, type, success: true, data: result };
        } catch (error: unknown) {
          const message = error instanceof Error ? error.message : String(error);
          return { id, type, success: false, error: message };
        }
      }

      case 'api:github/issues:comments': {
        const context = ctx?.context;
        if (!context) return { id, type, success: false, error: 'Missing VS Code context' };
        const stored = await readGitHubAuth(context);
        if (!stored?.accessToken) {
          return { id, type, success: true, data: { connected: false } };
        }
        const directory = readStringField(payload, 'directory');
        const number = readNumberField(payload, 'number') ?? 0;
        if (!directory || !number) {
          return { id, type, success: false, error: 'directory and number are required' };
        }
        try {
          const result = await listIssueComments(stored.accessToken, directory, number);
          if (result.connected === false) {
            await clearGitHubAuth(context);
          }
          return { id, type, success: true, data: result };
        } catch (error: unknown) {
          const message = error instanceof Error ? error.message : String(error);
          return { id, type, success: false, error: message };
        }
      }

      case 'api:github/pulls:list': {
        const context = ctx?.context;
        if (!context) return { id, type, success: false, error: 'Missing VS Code context' };
        const stored = await readGitHubAuth(context);
        if (!stored?.accessToken) {
          return { id, type, success: true, data: { connected: false } };
        }
        const directory = readStringField(payload, 'directory');
        const page = readNumberField(payload, 'page') ?? 1;
        if (!directory) {
          return { id, type, success: false, error: 'directory is required' };
        }
        try {
          const result = await listPullRequests(stored.accessToken, directory, page);
          if (result.connected === false) {
            await clearGitHubAuth(context);
          }
          return { id, type, success: true, data: result };
        } catch (error: unknown) {
          const message = error instanceof Error ? error.message : String(error);
          return { id, type, success: false, error: message };
        }
      }

      case 'api:github/pulls:context': {
        const context = ctx?.context;
        if (!context) return { id, type, success: false, error: 'Missing VS Code context' };
        const stored = await readGitHubAuth(context);
        if (!stored?.accessToken) {
          return { id, type, success: true, data: { connected: false } };
        }
        const directory = readStringField(payload, 'directory');
        const number = readNumberField(payload, 'number') ?? 0;
        const includeDiff = readBooleanField(payload, 'includeDiff') ?? false;
        const includeCheckDetails = readBooleanField(payload, 'includeCheckDetails') ?? false;
        if (!directory || !number) {
          return { id, type, success: false, error: 'directory and number are required' };
        }
        try {
          const result = await getPullRequestContext(stored.accessToken, directory, number, includeDiff, includeCheckDetails);
          if (result.connected === false) {
            await clearGitHubAuth(context);
          }
          return { id, type, success: true, data: result };
        } catch (error: unknown) {
          const message = error instanceof Error ? error.message : String(error);
          return { id, type, success: false, error: message };
        }
      }

      case 'api:config/reload': {
        await ctx?.manager?.restart();
        return { id, type, success: true, data: { restarted: true } };
      }

      case 'api:config/agents': {
        const { method, name, body, directory } = (payload || {}) as { method?: string; name?: string; body?: Record<string, unknown>; directory?: string };
        const agentName = typeof name === 'string' ? name.trim() : '';
        if (!agentName) {
          return { id, type, success: false, error: 'Agent name is required' };
        }

        // Use directory from request if provided, otherwise fall back to workspace
        const workingDirectory = (typeof directory === 'string' && directory.trim())
          ? directory.trim()
          : (ctx?.manager?.getWorkingDirectory() || vscode.workspace.workspaceFolders?.[0]?.uri.fsPath);

        const normalizedMethod = typeof method === 'string' && method.trim() ? method.trim().toUpperCase() : 'GET';
        if (normalizedMethod === 'GET') {
          const sources = getAgentSources(agentName, workingDirectory);
          const scope = sources.md.exists
            ? sources.md.scope
            : (sources.json.exists ? sources.json.scope : null);
          return {
            id,
            type,
            success: true,
            data: { name: agentName, sources, scope, isBuiltIn: !sources.md.exists && !sources.json.exists },
          };
        }

        if (normalizedMethod === 'POST') {
          // Extract scope from body if present
          const scopeValue = body?.scope as string | undefined;
          const scope: AgentScope | undefined = scopeValue === 'project' ? AGENT_SCOPE.PROJECT : scopeValue === 'user' ? AGENT_SCOPE.USER : undefined;
          createAgent(agentName, (body || {}) as Record<string, unknown>, workingDirectory, scope);
          await ctx?.manager?.restart();
          return {
            id,
            type,
            success: true,
            data: {
              success: true,
              requiresReload: true,
              message: `Agent ${agentName} created successfully. Reloading interface…`,
              reloadDelayMs: CLIENT_RELOAD_DELAY_MS,
            },
          };
        }

        if (normalizedMethod === 'PATCH') {
          updateAgent(agentName, (body || {}) as Record<string, unknown>, workingDirectory);
          await ctx?.manager?.restart();
          return {
            id,
            type,
            success: true,
            data: {
              success: true,
              requiresReload: true,
              message: `Agent ${agentName} updated successfully. Reloading interface…`,
              reloadDelayMs: CLIENT_RELOAD_DELAY_MS,
            },
          };
        }

        if (normalizedMethod === 'DELETE') {
          deleteAgent(agentName, workingDirectory);
          await ctx?.manager?.restart();
          return {
            id,
            type,
            success: true,
            data: {
              success: true,
              requiresReload: true,
              message: `Agent ${agentName} deleted successfully. Reloading interface…`,
              reloadDelayMs: CLIENT_RELOAD_DELAY_MS,
            },
          };
        }

        return { id, type, success: false, error: `Unsupported method: ${normalizedMethod}` };
      }

      case 'api:config/commands': {
        const { method, name, body, directory } = (payload || {}) as { method?: string; name?: string; body?: Record<string, unknown>; directory?: string };
        const commandName = typeof name === 'string' ? name.trim() : '';
        if (!commandName) {
          return { id, type, success: false, error: 'Command name is required' };
        }

        // Use directory from request if provided, otherwise fall back to workspace
        const workingDirectory = (typeof directory === 'string' && directory.trim())
          ? directory.trim()
          : (ctx?.manager?.getWorkingDirectory() || vscode.workspace.workspaceFolders?.[0]?.uri.fsPath);

        const normalizedMethod = typeof method === 'string' && method.trim() ? method.trim().toUpperCase() : 'GET';
        if (normalizedMethod === 'GET') {
          const sources = getCommandSources(commandName, workingDirectory);
          const scope = sources.md.exists
            ? sources.md.scope
            : (sources.json.exists ? sources.json.scope : null);
          return {
            id,
            type,
            success: true,
            data: { name: commandName, sources, scope, isBuiltIn: !sources.md.exists && !sources.json.exists },
          };
        }

        if (normalizedMethod === 'POST') {
          // Extract scope from body if present
          const scopeValue = body?.scope as string | undefined;
          const scope: CommandScope | undefined = scopeValue === 'project' ? COMMAND_SCOPE.PROJECT : scopeValue === 'user' ? COMMAND_SCOPE.USER : undefined;
          createCommand(commandName, (body || {}) as Record<string, unknown>, workingDirectory, scope);
          await ctx?.manager?.restart();
          return {
            id,
            type,
            success: true,
            data: {
              success: true,
              requiresReload: true,
              message: `Command ${commandName} created successfully. Reloading interface…`,
              reloadDelayMs: CLIENT_RELOAD_DELAY_MS,
            },
          };
        }

        if (normalizedMethod === 'PATCH') {
          updateCommand(commandName, (body || {}) as Record<string, unknown>, workingDirectory);
          await ctx?.manager?.restart();
          return {
            id,
            type,
            success: true,
            data: {
              success: true,
              requiresReload: true,
              message: `Command ${commandName} updated successfully. Reloading interface…`,
              reloadDelayMs: CLIENT_RELOAD_DELAY_MS,
            },
          };
        }

        if (normalizedMethod === 'DELETE') {
          deleteCommand(commandName, workingDirectory);
          await ctx?.manager?.restart();
          return {
            id,
            type,
            success: true,
            data: {
              success: true,
              requiresReload: true,
              message: `Command ${commandName} deleted successfully. Reloading interface…`,
              reloadDelayMs: CLIENT_RELOAD_DELAY_MS,
            },
          };
        }

        return { id, type, success: false, error: `Unsupported method: ${normalizedMethod}` };
      }

      case 'api:config/mcp': {
        const { method, name, body, directory } = (payload || {}) as { method?: string; name?: string; body?: Record<string, unknown>; directory?: string };
        const normalizedMethod = typeof method === 'string' && method.trim() ? method.trim().toUpperCase() : 'GET';
        const mcpName = typeof name === 'string' ? name.trim() : '';

        const workingDirectory = (typeof directory === 'string' && directory.trim())
          ? directory.trim()
          : (ctx?.manager?.getWorkingDirectory() || vscode.workspace.workspaceFolders?.[0]?.uri.fsPath);

        if (normalizedMethod === 'GET' && !mcpName) {
          const configs = listMcpConfigs(workingDirectory);
          return { id, type, success: true, data: configs };
        }

        if (!mcpName) {
          return { id, type, success: false, error: 'MCP server name is required' };
        }

        if (normalizedMethod === 'GET') {
          const config = getMcpConfig(mcpName, workingDirectory);
          if (!config) {
            return { id, type, success: false, error: `MCP server "${mcpName}" not found` };
          }
          return { id, type, success: true, data: config };
        }

        if (normalizedMethod === 'POST') {
          const scope = body?.scope as 'user' | 'project' | undefined;
          createMcpConfig(mcpName, (body || {}) as Record<string, unknown>, workingDirectory, scope);
          await ctx?.manager?.restart();
          return {
            id,
            type,
            success: true,
            data: {
              success: true,
              requiresReload: true,
              message: `MCP server "${mcpName}" created. Reloading interface…`,
              reloadDelayMs: CLIENT_RELOAD_DELAY_MS,
            },
          };
        }

        if (normalizedMethod === 'PATCH') {
          updateMcpConfig(mcpName, (body || {}) as Record<string, unknown>, workingDirectory);
          await ctx?.manager?.restart();
          return {
            id,
            type,
            success: true,
            data: {
              success: true,
              requiresReload: true,
              message: `MCP server "${mcpName}" updated. Reloading interface…`,
              reloadDelayMs: CLIENT_RELOAD_DELAY_MS,
            },
          };
        }

        if (normalizedMethod === 'DELETE') {
          deleteMcpConfig(mcpName, workingDirectory);
          await ctx?.manager?.restart();
          return {
            id,
            type,
            success: true,
            data: {
              success: true,
              requiresReload: true,
              message: `MCP server "${mcpName}" deleted. Reloading interface…`,
              reloadDelayMs: CLIENT_RELOAD_DELAY_MS,
            },
          };
        }

        return { id, type, success: false, error: `Unsupported method: ${normalizedMethod}` };
      }

      case 'api:config/skills': {
        const { method, name, body } = (payload || {}) as { method?: string; name?: string; body?: Record<string, unknown> };
        const workingDirectory = ctx?.manager?.getWorkingDirectory() || vscode.workspace.workspaceFolders?.[0]?.uri.fsPath;
        const normalizedMethod = typeof method === 'string' && method.trim() ? method.trim().toUpperCase() : 'GET';

        // LIST all skills (no name provided)
        if (!name && normalizedMethod === 'GET') {
          const skills = (await fetchOpenCodeSkillsFromApi(ctx, workingDirectory)) || discoverSkills(workingDirectory);
          return { id, type, success: true, data: { skills } };
        }

        const skillName = typeof name === 'string' ? name.trim() : '';
        if (!skillName) {
          return { id, type, success: false, error: 'Skill name is required' };
        }

        if (normalizedMethod === 'GET') {
          const discoveredSkill = ((await fetchOpenCodeSkillsFromApi(ctx, workingDirectory)) || [])
            .find((skill) => skill.name === skillName);
          const sources = getSkillSources(skillName, workingDirectory, discoveredSkill || null);
          return {
            id,
            type,
            success: true,
            data: { name: skillName, sources, scope: sources.md.scope, source: sources.md.source },
          };
        }

        if (normalizedMethod === 'POST') {
          const scopeValue = body?.scope as string | undefined;
          const sourceValue = body?.source as string | undefined;
          const scope: SkillScope | undefined = scopeValue === 'project' ? SKILL_SCOPE.PROJECT : scopeValue === 'user' ? SKILL_SCOPE.USER : undefined;
          const normalizedSource = sourceValue === 'agents' ? 'agents' : 'opencode';
          createSkill(skillName, { ...(body || {}), source: normalizedSource } as Record<string, unknown>, workingDirectory, scope);
          await ctx?.manager?.restart();
          return {
            id,
            type,
            success: true,
            data: {
              success: true,
              requiresReload: true,
              message: `Skill ${skillName} created successfully. Reloading interface…`,
              reloadDelayMs: CLIENT_RELOAD_DELAY_MS,
            },
          };
        }

        if (normalizedMethod === 'PATCH') {
          updateSkill(skillName, (body || {}) as Record<string, unknown>, workingDirectory);
          await ctx?.manager?.restart();
          return {
            id,
            type,
            success: true,
            data: {
              success: true,
              requiresReload: true,
              message: `Skill ${skillName} updated successfully. Reloading interface…`,
              reloadDelayMs: CLIENT_RELOAD_DELAY_MS,
            },
          };
        }

        if (normalizedMethod === 'DELETE') {
          deleteSkill(skillName, workingDirectory);
          await ctx?.manager?.restart();
          return {
            id,
            type,
            success: true,
            data: {
              success: true,
              requiresReload: true,
              message: `Skill ${skillName} deleted successfully. Reloading interface…`,
              reloadDelayMs: CLIENT_RELOAD_DELAY_MS,
            },
          };
        }

        return { id, type, success: false, error: `Unsupported method: ${normalizedMethod}` };
      }

      case 'api:config/skills:catalog': {
        const refresh = Boolean((payload as { refresh?: boolean } | undefined)?.refresh);
        const workingDirectory = ctx?.manager?.getWorkingDirectory() || vscode.workspace.workspaceFolders?.[0]?.uri.fsPath;

        const settings = readSettings(ctx);
        const rawCatalogs = (settings as { skillCatalogs?: unknown }).skillCatalogs;

        const additionalSources: SkillsCatalogSourceConfig[] = Array.isArray(rawCatalogs)
          ? (rawCatalogs
              .map((entry) => {
                if (!entry || typeof entry !== 'object') return null;
                const candidate = entry as Record<string, unknown>;
                const id = typeof candidate.id === 'string' ? candidate.id.trim() : '';
                const label = typeof candidate.label === 'string' ? candidate.label.trim() : '';
                const source = typeof candidate.source === 'string' ? candidate.source.trim() : '';
                const subpath = typeof candidate.subpath === 'string' ? candidate.subpath.trim() : '';
                if (!id || !label || !source) return null;
                const normalized: SkillsCatalogSourceConfig = {
                  id,
                  label,
                  description: source,
                  source,
                  ...(subpath ? { defaultSubpath: subpath } : {}),
                };
                return normalized;
              })
              .filter((v) => v !== null) as SkillsCatalogSourceConfig[])
          : [];

        const installedSkills = (await fetchOpenCodeSkillsFromApi(ctx, workingDirectory)) || undefined;
        const data = await getSkillsCatalog(workingDirectory, refresh, additionalSources, installedSkills);
        return { id, type, success: true, data };
      }

      case 'api:config/skills:scan': {
        const body = (payload || {}) as { source?: string; subpath?: string; gitIdentityId?: string };
        const data = await scanSkillsRepositoryFromGit({
          source: String(body.source || ''),
          subpath: body.subpath,
        });
        return { id, type, success: true, data };
      }

      case 'api:config/skills:install': {
        const body = (payload || {}) as {
          source?: string;
          subpath?: string;
          scope?: 'user' | 'project';
          targetSource?: 'opencode' | 'agents';
          selections?: Array<{ skillDir: string }>;
          conflictPolicy?: 'prompt' | 'skipAll' | 'overwriteAll';
          conflictDecisions?: Record<string, 'skip' | 'overwrite'>;
        };

        const workingDirectory = ctx?.manager?.getWorkingDirectory() || vscode.workspace.workspaceFolders?.[0]?.uri.fsPath;

        const data = await installSkillsFromGit({
          source: String(body.source || ''),
          subpath: body.subpath,
          scope: body.scope === 'project' ? 'project' : 'user',
          targetSource: body.targetSource === 'agents' ? 'agents' : 'opencode',
          workingDirectory: body.scope === 'project' ? workingDirectory : undefined,
          selections: Array.isArray(body.selections) ? body.selections : [],
          conflictPolicy: body.conflictPolicy,
          conflictDecisions: body.conflictDecisions,
        });

        if (data.ok) {
          const installed = data.installed || [];
          const skipped = data.skipped || [];
          const requiresReload = installed.length > 0;

          if (requiresReload) {
            await ctx?.manager?.restart();
          }

          return {
            id,
            type,
            success: true,
            data: {
              ok: true,
              installed,
              skipped,
              requiresReload,
              message: requiresReload ? 'Skills installed successfully. Reloading interface…' : 'No skills were installed',
              reloadDelayMs: requiresReload ? CLIENT_RELOAD_DELAY_MS : undefined,
            },
          };
        }

        return { id, type, success: true, data };
      }

      case 'api:config/skills/files': {
        const { method, name, filePath, content } = (payload || {}) as { 
          method?: string; 
          name?: string; 
          filePath?: string; 
          content?: string;
        };
        const workingDirectory = ctx?.manager?.getWorkingDirectory() || vscode.workspace.workspaceFolders?.[0]?.uri.fsPath;

        const skillName = typeof name === 'string' ? name.trim() : '';
        if (!skillName) {
          return { id, type, success: false, error: 'Skill name is required' };
        }

        const relativePath = typeof filePath === 'string' ? filePath.trim() : '';
        if (!relativePath) {
          return { id, type, success: false, error: 'File path is required' };
        }

        const discoveredSkill = ((await fetchOpenCodeSkillsFromApi(ctx, workingDirectory)) || [])
          .find((skill) => skill.name === skillName);
        const sources = getSkillSources(skillName, workingDirectory, discoveredSkill || null);
        if (!sources.md.dir) {
          return { id, type, success: false, error: `Skill "${skillName}" not found` };
        }

        const skillDir = sources.md.dir;
        const normalizedMethod = typeof method === 'string' && method.trim() ? method.trim().toUpperCase() : 'GET';

        if (normalizedMethod === 'GET') {
          const fileContent = readSkillSupportingFile(skillDir, relativePath);
          if (fileContent === null) {
            return { id, type, success: false, error: `File "${relativePath}" not found in skill "${skillName}"` };
          }
          return { id, type, success: true, data: { content: fileContent } };
        }

        if (normalizedMethod === 'PUT') {
          writeSkillSupportingFile(skillDir, relativePath, content || '');
          return { id, type, success: true, data: { success: true } };
        }

        if (normalizedMethod === 'DELETE') {
          deleteSkillSupportingFile(skillDir, relativePath);
          return { id, type, success: true, data: { success: true } };
        }

        return { id, type, success: false, error: `Unsupported method: ${normalizedMethod}` };
      }

      case 'api:opencode/directory': {
        const target = (payload as { path?: string })?.path;
        if (!target) {
          return { id, type, success: false, error: 'Path is required' };
        }
        const baseDirectory =
          ctx?.manager?.getWorkingDirectory() || vscode.workspace.workspaceFolders?.[0]?.uri.fsPath || os.homedir();
        const resolvedPath = resolveUserPath(target, baseDirectory);
        const result = await ctx?.manager?.setWorkingDirectory(resolvedPath);
        if (!result) {
          return { id, type, success: false, error: 'OpenCode manager unavailable' };
        }
        return { id, type, success: true, data: result };
      }

      case 'api:models/metadata': {
        try {
          const data = await fetchModelsMetadata();
          return { id, type, success: true, data };
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : String(error);
          return { id, type, success: false, error: errorMessage };
        }
      }

      case 'api:openchamber:update-check': {
        try {
          const body = (payload && typeof payload === 'object' ? payload : {}) as Record<string, unknown>;
          const currentVersion = typeof body.currentVersion === 'string' && body.currentVersion.trim().length > 0
            ? body.currentVersion.trim()
            : 'unknown';
          const instanceMode = typeof body.instanceMode === 'string' && body.instanceMode.trim().length > 0
            ? body.instanceMode.trim()
            : 'local';
          const deviceClass = typeof body.deviceClass === 'string' && body.deviceClass.trim().length > 0
            ? body.deviceClass.trim()
            : 'desktop';
          const platformRaw = typeof body.platform === 'string' && body.platform.trim().length > 0
            ? body.platform.trim()
            : os.platform();
          const archRaw = typeof body.arch === 'string' && body.arch.trim().length > 0
            ? body.arch.trim()
            : os.arch();
          const reportUsage = body.reportUsage !== false;

          const installId = getOrCreateInstallId('vscode');
          const requestBody = {
            appType: 'vscode',
            deviceClass,
            platform: mapNodePlatformToApiPlatform(platformRaw),
            arch: mapNodeArchToApiArch(archRaw),
            channel: 'stable',
            currentVersion,
            installId,
            instanceMode,
            reportUsage,
          };

          const response = await fetch(UPDATE_CHECK_URL, {
            method: 'POST',
            headers: {
              Accept: 'application/json',
              'Content-Type': 'application/json',
            },
            body: JSON.stringify(requestBody),
            signal: AbortSignal.timeout(10_000),
          });

          if (!response.ok) {
            const text = await response.text().catch(() => 'update check failed');
            return { id, type, success: false, error: text || `Update check failed with ${response.status}` };
          }

          const data = await response.json();
          return { id, type, success: true, data };
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : String(error);
          return { id, type, success: false, error: errorMessage };
        }
      }

      case 'editor:openFile': {
        const { path: filePath, line, column } = payload as { path: string; line?: number; column?: number };
        try {
          const doc = await vscode.workspace.openTextDocument(filePath);
          const options: vscode.TextDocumentShowOptions = {};
          if (typeof line === 'number') {
            const pos = new vscode.Position(Math.max(0, line - 1), column || 0);
            options.selection = new vscode.Range(pos, pos);
          }
          await vscode.window.showTextDocument(doc, options);
          return { id, type, success: true };
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : String(error);
          return { id, type, success: false, error: errorMessage };
        }
      }

      case 'editor:openDiff': {
        const { original, modified, label, line, patch } = payload as {
          original: string;
          modified: string;
          label?: string;
          line?: number;
          patch?: string;
        };
        try {
          const modifiedUri = vscode.Uri.file(modified);
          const modifiedDoc = await vscode.workspace.openTextDocument(modifiedUri);
          let originalUri = original ? vscode.Uri.file(original) : modifiedUri;

          if (typeof patch === 'string' && patch.trim().length > 0) {
            const originalContent = reconstructOriginalContentFromPatch(modifiedDoc.getText(), patch);
            if (typeof originalContent === 'string') {
              ensureVirtualDiffProviderRegistered(ctx);
              originalUri = createVirtualOriginalDiffUri(modified, originalContent);
            }
          }

          const leftLabel = original ? path.basename(original) : `${path.basename(modified)} (before)`;
          const title = label || `${leftLabel} ↔ ${path.basename(modified)}`;

          await vscode.commands.executeCommand('vscode.diff', originalUri, modifiedUri, title);

          if (typeof line === 'number' && Number.isFinite(line)) {
            const targetLine = Math.max(0, Math.trunc(line) - 1);
            await new Promise((resolve) => setTimeout(resolve, 0));
            const targetEditor = vscode.window.visibleTextEditors.find(
              (editor) => editor.document.uri.toString() === modifiedUri.toString(),
            );
            if (targetEditor) {
              const target = new vscode.Position(targetLine, 0);
              targetEditor.selection = new vscode.Selection(target, target);
              targetEditor.revealRange(new vscode.Range(target, target), vscode.TextEditorRevealType.InCenter);
            }
          }

          return { id, type, success: true };
        } catch (error) {
           const errorMessage = error instanceof Error ? error.message : String(error);
           return { id, type, success: false, error: errorMessage };
        }
      }

       case 'api:provider/auth:delete': {
        const { providerId, scope } = (payload || {}) as { providerId?: string; scope?: string };
        if (!providerId) {
          return { id, type, success: false, error: 'Provider ID is required' };
        }
        const normalizedScope = typeof scope === 'string' ? scope : 'auth';
        try {
          let removed = false;
        if (normalizedScope === 'auth') {
          removed = removeProviderAuth(providerId);
        } else if (normalizedScope === 'user' || normalizedScope === 'project' || normalizedScope === 'custom') {
          removed = removeProviderConfig(providerId, ctx?.manager?.getWorkingDirectory(), normalizedScope);
        } else if (normalizedScope === 'all') {
          const workingDirectory = ctx?.manager?.getWorkingDirectory();
          const authRemoved = removeProviderAuth(providerId);
          const userRemoved = removeProviderConfig(providerId, workingDirectory, 'user');
          const projectRemoved = workingDirectory
            ? removeProviderConfig(providerId, workingDirectory, 'project')
            : false;
          const customRemoved = removeProviderConfig(providerId, workingDirectory, 'custom');
          removed = authRemoved || userRemoved || projectRemoved || customRemoved;
        } else {
          return { id, type, success: false, error: 'Invalid scope' };
        }

          if (removed) {
            await ctx?.manager?.restart();
          }
          return {
            id,
            type,
            success: true,
            data: {
              success: true,
              removed,
              requiresReload: removed,
              message: removed
                ? `Provider ${providerId} disconnected successfully. Reloading interface…`
                : `Provider ${providerId} was not configured.`,
              reloadDelayMs: removed ? CLIENT_RELOAD_DELAY_MS : undefined,
            },
          };
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : String(error);
          return { id, type, success: false, error: errorMessage };
        }
      }

       case 'api:provider/source:get': {
        const { providerId } = (payload || {}) as { providerId?: string };
        if (!providerId) {
          return { id, type, success: false, error: 'Provider ID is required' };
        }
        try {
          const sources = getProviderSources(providerId, ctx?.manager?.getWorkingDirectory());
          const auth = getProviderAuth(providerId);
          sources.auth.exists = Boolean(auth);
          return { id, type, success: true, data: { providerId, sources } };
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : String(error);
          return { id, type, success: false, error: errorMessage };
        }
      }

      case 'api:quota:providers': {
        try {
          const providers = listConfiguredQuotaProviders();
          return { id, type, success: true, data: { providers } };
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : String(error);
          return { id, type, success: false, error: errorMessage };
        }
      }

      case 'api:quota:get': {
        const { providerId } = (payload || {}) as { providerId?: string };
        if (!providerId) {
          return { id, type, success: false, error: 'Provider ID is required' };
        }
        try {
          const result = await fetchQuotaForProvider(providerId);
          return { id, type, success: true, data: result };
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : String(error);
          return { id, type, success: false, error: errorMessage };
        }
      }


      case 'vscode:command': {
        const { command, args } = (payload || {}) as { command?: string; args?: unknown[] };
        if (!command) {
          return { id, type, success: false, error: 'Command is required' };
        }
        try {
          const result = await vscode.commands.executeCommand(command, ...(args || []));
          return { id, type, success: true, data: { result } };
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : String(error);
          return { id, type, success: false, error: errorMessage };
        }
      }

      case 'vscode:openExternalUrl': {
        const { url } = (payload || {}) as { url?: string };
        const target = typeof url === 'string' ? url.trim() : '';
        if (!target) {
          return { id, type, success: false, error: 'URL is required' };
        }
        try {
          await vscode.env.openExternal(vscode.Uri.parse(target));
          return { id, type, success: true, data: { opened: true } };
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : String(error);
          return { id, type, success: false, error: errorMessage };
        }
      }

      case 'notifications:can-notify': {
        return { id, type, success: true, data: true };
      }

      case 'notifications:notify': {
        const request = (payload || {}) as NotificationsNotifyRequestPayload;
        const notification = request.payload || {};
        const title = typeof notification.title === 'string' ? notification.title.trim() : '';
        const body = typeof notification.body === 'string' ? notification.body.trim() : '';

        const message = title && body
          ? `${title}: ${body}`
          : title || body;

        if (!message) {
          return { id, type, success: true, data: { shown: false } };
        }

        void vscode.window.showInformationMessage(message);
        return { id, type, success: true, data: { shown: true } };
      }

      // ============== Git Operations ==============

      case 'api:git/check': {
        const { directory } = (payload || {}) as { directory?: string };
        if (!directory) {
          return { id, type, success: false, error: 'Directory is required' };
        }
        const isRepo = await gitService.checkIsGitRepository(directory);
        return { id, type, success: true, data: isRepo };
      }

      case 'api:git/worktree-type': {
        const { directory } = (payload || {}) as { directory?: string };
        if (!directory) {
          return { id, type, success: false, error: 'Directory is required' };
        }
        const isLinked = await gitService.isLinkedWorktree(directory);
        return { id, type, success: true, data: isLinked };
      }

      case 'api:git/status': {
        const { directory } = (payload || {}) as { directory?: string };
        if (!directory) {
          return { id, type, success: false, error: 'Directory is required' };
        }
        const status = await gitService.getGitStatus(directory);
        return { id, type, success: true, data: status };
      }

      case 'api:git/branches': {
        const { directory, method, name, startPoint, force } = (payload || {}) as { 
          directory?: string; 
          method?: string;
          name?: string;
          startPoint?: string;
          force?: boolean;
        };
        if (!directory) {
          return { id, type, success: false, error: 'Directory is required' };
        }

        const normalizedMethod = typeof method === 'string' ? method.toUpperCase() : 'GET';

        if (normalizedMethod === 'GET') {
          const branches = await gitService.getGitBranches(directory);
          return { id, type, success: true, data: branches };
        }

        if (normalizedMethod === 'POST') {
          if (!name) {
            return { id, type, success: false, error: 'Branch name is required' };
          }
          const result = await gitService.createBranch(directory, name, startPoint);
          return { id, type, success: true, data: result };
        }

        if (normalizedMethod === 'DELETE') {
          if (!name) {
            return { id, type, success: false, error: 'Branch name is required' };
          }
          const result = await gitService.deleteGitBranch(directory, name, force);
          return { id, type, success: true, data: result };
        }

        return { id, type, success: false, error: `Unsupported method: ${normalizedMethod}` };
      }

      case 'api:git/remote-branches': {
        const { directory, branch, remote } = (payload || {}) as { 
          directory?: string; 
          branch?: string;
          remote?: string;
        };
        if (!directory || !branch) {
          return { id, type, success: false, error: 'Directory and branch are required' };
        }
        const result = await gitService.deleteRemoteBranch(directory, branch, remote);
        return { id, type, success: true, data: result };
      }

      case 'api:git/checkout': {
        const { directory, branch } = (payload || {}) as { directory?: string; branch?: string };
        if (!directory || !branch) {
          return { id, type, success: false, error: 'Directory and branch are required' };
        }
        const result = await gitService.checkoutBranch(directory, branch);
        return { id, type, success: true, data: result };
      }

      case 'api:git/worktrees': {
        const { directory, method } = (payload || {}) as {
          directory?: string;
          method?: string;
          body?: unknown;
          directoryPath?: string;
          deleteLocalBranch?: boolean;
        };
        if (!directory) {
          return { id, type, success: false, error: 'Directory is required' };
        }

        const normalizedMethod = typeof method === 'string' ? method.toUpperCase() : 'GET';

        if (normalizedMethod === 'GET') {
          const worktrees = await gitService.listGitWorktrees(directory);
          return { id, type, success: true, data: worktrees };
        }

        if (normalizedMethod === 'POST') {
          const created = await gitService.createWorktree(directory, (payload || {}) as gitService.CreateGitWorktreePayload);
          return { id, type, success: true, data: created };
        }

        if (normalizedMethod === 'DELETE') {
          const removePayload = payload as {
            body?: { directory?: string; deleteLocalBranch?: boolean };
            directory?: string;
            deleteLocalBranch?: boolean;
          };
          const bodyDirectory = typeof removePayload?.body?.directory === 'string'
            ? removePayload.body.directory
            : '';
          const legacyDirectory = typeof removePayload?.directory === 'string' ? removePayload.directory : '';
          const worktreeDirectory = bodyDirectory || legacyDirectory || '';

          if (!worktreeDirectory) {
            return { id, type, success: false, error: 'Worktree directory is required' };
          }
          const removed = await gitService.removeWorktree(directory, {
            directory: worktreeDirectory,
            deleteLocalBranch: removePayload?.body?.deleteLocalBranch === true || removePayload?.deleteLocalBranch === true,
          });
          return { id, type, success: true, data: { success: Boolean(removed) } };
        }

        return { id, type, success: false, error: `Unsupported method: ${normalizedMethod}` };
      }

      case 'api:git/worktrees/validate': {
        const { directory } = (payload || {}) as { directory?: string };
        if (!directory) {
          return { id, type, success: false, error: 'Directory is required' };
        }
        const result = await gitService.validateWorktreeCreate(directory, (payload || {}) as gitService.CreateGitWorktreePayload);
        return { id, type, success: true, data: result };
      }

      case 'api:git/worktrees/bootstrap-status': {
        const { directory } = (payload || {}) as { directory?: string };
        if (!directory) {
          return { id, type, success: false, error: 'Directory is required' };
        }
        const result = await gitService.getWorktreeBootstrapStatus(directory);
        return { id, type, success: true, data: result };
      }

      case 'api:git/worktrees/preview': {
        const { directory } = (payload || {}) as { directory?: string };
        if (!directory) {
          return { id, type, success: false, error: 'Directory is required' };
        }
        const result = await gitService.previewWorktreeCreate(directory, (payload || {}) as gitService.CreateGitWorktreePayload);
        return { id, type, success: true, data: result };
      }

      case 'api:git/diff': {
        const { directory, path: filePath, staged, contextLines } = (payload || {}) as { 
          directory?: string; 
          path?: string;
          staged?: boolean;
          contextLines?: number;
        };
        if (!directory || !filePath) {
          return { id, type, success: false, error: 'Directory and path are required' };
        }
        const result = await gitService.getGitDiff(directory, filePath, staged, contextLines);
        return { id, type, success: true, data: result };
      }

      case 'api:git/file-diff': {
        const { directory, path: filePath, staged } = (payload || {}) as { 
          directory?: string; 
          path?: string;
          staged?: boolean;
        };
        if (!directory || !filePath) {
          return { id, type, success: false, error: 'Directory and path are required' };
        }
        const result = await gitService.getGitFileDiff(directory, filePath, staged);
        return { id, type, success: true, data: result };
      }

      case 'api:git/revert': {
        const { directory, path: filePath } = (payload || {}) as { directory?: string; path?: string };
        if (!directory || !filePath) {
          return { id, type, success: false, error: 'Directory and path are required' };
        }
        await gitService.revertGitFile(directory, filePath);
        return { id, type, success: true, data: { success: true } };
      }

      case 'api:git/commit': {
        const { directory, message, addAll, files } = (payload || {}) as { 
          directory?: string; 
          message?: string;
          addAll?: boolean;
          files?: string[];
        };
        if (!directory || !message) {
          return { id, type, success: false, error: 'Directory and message are required' };
        }
        const result = await gitService.createGitCommit(directory, message, { addAll, files });
        return { id, type, success: true, data: result };
      }

      case 'api:git/push': {
        const { directory, remote, branch, options } = (payload || {}) as { 
          directory?: string; 
          remote?: string;
          branch?: string;
          options?: string[] | Record<string, unknown>;
        };
        if (!directory) {
          return { id, type, success: false, error: 'Directory is required' };
        }
        const result = await gitService.gitPush(directory, { remote, branch, options });
        return { id, type, success: true, data: result };
      }

      case 'api:git/pull': {
        const { directory, remote, branch } = (payload || {}) as { 
          directory?: string; 
          remote?: string;
          branch?: string;
        };
        if (!directory) {
          return { id, type, success: false, error: 'Directory is required' };
        }
        const result = await gitService.gitPull(directory, { remote, branch });
        return { id, type, success: true, data: result };
      }

      case 'api:git/fetch': {
        const { directory, remote, branch } = (payload || {}) as { 
          directory?: string; 
          remote?: string;
          branch?: string;
        };
        if (!directory) {
          return { id, type, success: false, error: 'Directory is required' };
        }
        const result = await gitService.gitFetch(directory, { remote, branch });
        return { id, type, success: true, data: result };
      }

      case 'api:git/remotes': {
        const { directory, method, remote } = (payload || {}) as {
          directory?: string;
          method?: string;
          remote?: string;
        };
        if (!directory) {
          return { id, type, success: false, error: 'Directory is required' };
        }

        const normalizedMethod = typeof method === 'string' ? method.toUpperCase() : 'GET';
        if (normalizedMethod === 'GET') {
          const result = await gitService.getRemotes(directory);
          return { id, type, success: true, data: result };
        }

        if (normalizedMethod === 'DELETE') {
          if (!remote) {
            return { id, type, success: false, error: 'Remote name is required' };
          }
          const result = await gitService.removeRemote(directory, remote);
          return { id, type, success: true, data: result };
        }

        return { id, type, success: false, error: `Unsupported method: ${normalizedMethod}` };
      }

      case 'api:git/rebase': {
        const { directory, onto } = (payload || {}) as { directory?: string; onto?: string };
        if (!directory) {
          return { id, type, success: false, error: 'Directory is required' };
        }
        if (!onto) {
          return { id, type, success: false, error: 'onto is required' };
        }
        const result = await gitService.rebase(directory, { onto });
        return { id, type, success: true, data: result };
      }

      case 'api:git/rebase/abort': {
        const { directory } = (payload || {}) as { directory?: string };
        if (!directory) {
          return { id, type, success: false, error: 'Directory is required' };
        }
        const result = await gitService.abortRebase(directory);
        return { id, type, success: true, data: result };
      }

      case 'api:git/merge': {
        const { directory, branch } = (payload || {}) as { directory?: string; branch?: string };
        if (!directory) {
          return { id, type, success: false, error: 'Directory is required' };
        }
        if (!branch) {
          return { id, type, success: false, error: 'branch is required' };
        }
        const result = await gitService.merge(directory, { branch });
        return { id, type, success: true, data: result };
      }

      case 'api:git/merge/abort': {
        const { directory } = (payload || {}) as { directory?: string };
        if (!directory) {
          return { id, type, success: false, error: 'Directory is required' };
        }
        const result = await gitService.abortMerge(directory);
        return { id, type, success: true, data: result };
      }

      case 'api:git/rebase/continue': {
        const { directory } = (payload || {}) as { directory?: string };
        if (!directory) {
          return { id, type, success: false, error: 'Directory is required' };
        }
        const result = await gitService.continueRebase(directory);
        return { id, type, success: true, data: result };
      }

      case 'api:git/merge/continue': {
        const { directory } = (payload || {}) as { directory?: string };
        if (!directory) {
          return { id, type, success: false, error: 'Directory is required' };
        }
        const result = await gitService.continueMerge(directory);
        return { id, type, success: true, data: result };
      }

      case 'api:git/stash': {
        const { directory, message, includeUntracked } = (payload || {}) as {
          directory?: string;
          message?: string;
          includeUntracked?: boolean;
        };
        if (!directory) {
          return { id, type, success: false, error: 'Directory is required' };
        }
        const result = await gitService.stash(directory, { message, includeUntracked });
        return { id, type, success: true, data: result };
      }

      case 'api:git/stash/pop': {
        const { directory } = (payload || {}) as { directory?: string };
        if (!directory) {
          return { id, type, success: false, error: 'Directory is required' };
        }
        const result = await gitService.stashPop(directory);
        return { id, type, success: true, data: result };
      }

      case 'api:git/log': {
        const { directory, maxCount, from, to, file } = (payload || {}) as { 
          directory?: string; 
          maxCount?: number;
          from?: string;
          to?: string;
          file?: string;
        };
        if (!directory) {
          return { id, type, success: false, error: 'Directory is required' };
        }
        const result = await gitService.getGitLog(directory, { maxCount, from, to, file });
        return { id, type, success: true, data: result };
      }

      case 'api:git/commit-files': {
        const { directory, hash } = (payload || {}) as { directory?: string; hash?: string };
        if (!directory || !hash) {
          return { id, type, success: false, error: 'Directory and hash are required' };
        }
        const result = await gitService.getCommitFiles(directory, hash);
        return { id, type, success: true, data: result };
      }

      case 'api:git/pr-description': {
        const { directory, base, head, context, providerId, modelId, zenModel: payloadZenModel } = (payload || {}) as {
          directory?: string;
          base?: string;
          head?: string;
          context?: string;
          providerId?: string;
          modelId?: string;
          zenModel?: string;
        };
        if (!directory) {
          return { id, type, success: false, error: 'Directory is required' };
        }
        if (!base || !head) {
          return { id, type, success: false, error: 'base and head are required' };
        }

        // Collect diffs (best-effort)
        let files: string[] = [];
        try {
          const listed = await gitService.getGitRangeFiles(directory, base, head);
          files = Array.isArray(listed) ? listed : [];
        } catch {
          files = [];
        }

        if (files.length === 0) {
          return { id, type, success: false, error: 'No diffs available for base...head' };
        }

        let diffSummaries = '';
        for (const file of files) {
          try {
            const diff = await gitService.getGitRangeDiff(directory, base, head, file, 3);
            const raw = typeof diff?.diff === 'string' ? diff.diff : '';
            if (!raw.trim()) continue;
            diffSummaries += `FILE: ${file}\n${raw}\n\n`;
          } catch {
            // ignore
          }
        }

        if (!diffSummaries.trim()) {
          return { id, type, success: false, error: 'No diffs available for selected files' };
        }

        const prompt = `You are drafting a GitHub Pull Request title + description. Respond in JSON of the shape {"title": string, "body": string} (ONLY JSON in response, no markdown fences) with these rules:\n- title: concise, sentence case, <= 80 chars, no trailing punctuation, no commit-style prefixes (no "feat:", "fix:")\n- body: GitHub-flavored markdown with these sections in this order: Summary, Testing, Notes\n- Summary: 3-6 bullet points describing user-visible changes; avoid internal helper function names\n- Testing: bullet list ("- Not tested" allowed)\n- Notes: bullet list; include breaking/rollout notes only when relevant\n\nContext:\n- base branch: ${base}\n- head branch: ${head}${context?.trim() ? `\n- Additional context: ${context.trim()}` : ''}\n\nDiff summary:\n${diffSummaries}`;

        try {
          const apiUrl = ctx?.manager?.getApiUrl();
          if (!apiUrl) {
            return { id, type, success: false, error: 'OpenCode API unavailable' };
          }

          const settings = readSettings(ctx) as Record<string, unknown>;
          const { providerID, modelID } = await resolveBridgeGitGenerationModel(
            { providerId, modelId, zenModel: payloadZenModel },
            settings,
            apiUrl,
            ctx?.manager?.getOpenCodeAuthHeaders()
          );
          const raw = await generateBridgeTextWithSessionFlow({
            apiUrl,
            directory,
            prompt,
            providerID,
            modelID,
            authHeaders: ctx?.manager?.getOpenCodeAuthHeaders(),
          });
          if (!raw) {
            return { id, type, success: false, error: 'No PR description returned by generator' };
          }

          const cleaned = String(raw)
            .trim()
            .replace(/^```json\s*/i, '')
            .replace(/^```\s*/i, '')
            .replace(/```\s*$/i, '')
            .trim();

          const parsed = parseJsonObjectSafe(cleaned) || parseJsonObjectSafe(raw);
          if (parsed) {
            const title = typeof parsed.title === 'string' ? parsed.title : '';
            const body = typeof parsed.body === 'string' ? parsed.body : '';
            return { id, type, success: true, data: { title, body } };
          }

          return { id, type, success: true, data: { title: '', body: String(raw) } };
        } catch (error) {
          const message = error instanceof Error ? error.message : String(error);
          return { id, type, success: false, error: message };
        }
      }

      case 'api:git/identity': {
        const { directory, method, userName, userEmail, sshKey } = (payload || {}) as { 
          directory?: string; 
          method?: string;
          userName?: string;
          userEmail?: string;
          sshKey?: string | null;
        };
        if (!directory) {
          return { id, type, success: false, error: 'Directory is required' };
        }

        const normalizedMethod = typeof method === 'string' ? method.toUpperCase() : 'GET';

        if (normalizedMethod === 'GET') {
          const identity = await gitService.getCurrentGitIdentity(directory);
          return { id, type, success: true, data: identity };
        }

        if (normalizedMethod === 'POST') {
          if (!userName || !userEmail) {
            return { id, type, success: false, error: 'userName and userEmail are required' };
          }
          const result = await gitService.setGitIdentity(directory, userName, userEmail, sshKey);
          return { id, type, success: true, data: result };
        }

        return { id, type, success: false, error: `Unsupported method: ${normalizedMethod}` };
      }

      case 'api:git/ignore-openchamber': {
        // LEGACY_WORKTREES: only needed for <project>/.openchamber era. Safe to remove after legacy support dropped.
        // This is now a no-op since the function was removed with legacy worktree support.
        return { id, type, success: true, data: { success: true } };
      }

      case 'api:git/conflict-details': {
        const { directory } = (payload || {}) as { directory?: string };
        if (!directory) {
          return { id, type, success: false, error: 'Directory is required' };
        }

        try {
          // Get git status --porcelain
          const statusResult = await execGit(['status', '--porcelain'], directory);
          const statusPorcelain = statusResult.stdout;

          // Get unmerged files (files with conflicts)
          const unmergedResult = await execGit(['diff', '--name-only', '--diff-filter=U'], directory);
          const unmergedFiles = unmergedResult.stdout
            .split('\n')
            .map((line) => line.trim())
            .filter(Boolean);

          // Get current diff
          const diffResult = await execGit(['diff'], directory);
          const diff = diffResult.stdout;

          // Detect operation type and get head info
          let operation: 'merge' | 'rebase' = 'merge';
          let headInfo = '';

          // Check for MERGE_HEAD (merge in progress)
          const mergeHeadResult = await execGit(['rev-parse', '--verify', '--quiet', 'MERGE_HEAD'], directory);
          const mergeHeadExists = mergeHeadResult.exitCode === 0;

          if (mergeHeadExists) {
            operation = 'merge';
            const mergeHead = mergeHeadResult.stdout.trim();
            // Try to read MERGE_MSG file
            let mergeMsg = '';
            try {
              const mergeMsgPath = path.join(directory, '.git', 'MERGE_MSG');
              mergeMsg = await fs.promises.readFile(mergeMsgPath, 'utf8');
            } catch {
              // MERGE_MSG may not exist
            }
            headInfo = `MERGE_HEAD: ${mergeHead}${mergeMsg ? '\n' + mergeMsg : ''}`;
          } else {
            // Check for REBASE_HEAD (rebase in progress)
            const rebaseHeadResult = await execGit(['rev-parse', '--verify', '--quiet', 'REBASE_HEAD'], directory);
            const rebaseHeadExists = rebaseHeadResult.exitCode === 0;

            if (rebaseHeadExists) {
              operation = 'rebase';
              const rebaseHead = rebaseHeadResult.stdout.trim();
              headInfo = `REBASE_HEAD: ${rebaseHead}`;
            }
          }

          return {
            id,
            type,
            success: true,
            data: {
              statusPorcelain: statusPorcelain.trim(),
              unmergedFiles,
              diff: diff.trim(),
              headInfo: headInfo.trim(),
              operation,
            },
          };
        } catch (error) {
          const message = error instanceof Error ? error.message : String(error);
          return { id, type, success: false, error: message };
        }
      }

      default:
        return { id, type, success: false, error: `Unknown message type: ${type}` };
    }
  } catch (err) {
    const errorMessage = err instanceof Error ? err.message : String(err);
    return { id, type, success: false, error: errorMessage };
  }
}
