// 重构前 index.ts 只读参考：commit 6a04144d3f5103014f75b637d7e6bc2f45bf007f，blob 56e590c1a6b5ca7ad128bf2c992f60e46c355a58；可用 `git show 6a04144d3f5103014f75b637d7e6bc2f45bf007f:src/components/microservices/code-queue/src/index.ts` 查看。

import type { CodeExecutionMode, JsonValue } from "../types";

export type CodeAgentPortKind = "codex" | "opencode";

export interface CodeAgentClient {
  stop(): void;
  steer?(threadId: string, turnId: string, prompt: string): Promise<void>;
  interrupt?(threadId: string, turnId: string): Promise<void>;
}

export interface ActiveRun {
  taskId: string;
  queueId: string;
  app: CodeAgentClient;
  port: CodeAgentPortKind;
  threadId: string | null;
  turnId: string | null;
  startedAt: string;
  lastLocalHeartbeatAt: string;
  lastObservedAgentEventAt: string | null;
  lastPersistedTraceAt: string | null;
}

export interface ActiveRunSlotWaiter {
  id: number;
  taskId: string;
  queueId: string;
  enqueuedAt: string;
}

const gitProxyEnvKeys = ["CODE_QUEUE_EGRESS_PROXY_URL", "HTTPS_PROXY", "https_proxy", "HTTP_PROXY", "http_proxy", "ALL_PROXY", "all_proxy"];

export const minimaxM27Model = "minimax-m2.7";
export const minimaxM3Model = "minimax-m3";
export const deepseekChatModel = "deepseek-chat";
export const defaultCodeModels = ["gpt-5.5", "gpt-5.4-mini", "gpt-5.4", deepseekChatModel, minimaxM3Model, minimaxM27Model];
export const opencodeNpmPackage = "opencode-ai@1.14.48";
export const defaultCodeExecutionMode: CodeExecutionMode = "default";
export const codeExecutionModes: CodeExecutionMode[] = ["default", "windows-native"];
const codeExecutionModeAliases = new Set(["default", "windows-native", "windows", "win32", "native-windows"]);

export interface CodeModelProviderSourceConfig {
  codeModels: string[];
  codexModels?: string[];
  deepseekApiBase: string;
  deepseekApiKey: string;
  deepseekModel: string;
  minimaxApiBase: string;
  minimaxApiKey: string;
  minimaxModel: string;
  minimaxM3Model: string;
}

function proxyUrlFromEnv(env: NodeJS.ProcessEnv): string {
  for (const key of gitProxyEnvKeys) {
    const value = env[key];
    if (typeof value === "string" && value.trim().length > 0) return value.trim().replace(/\/+$/u, "");
  }
  return "";
}

function gitConfigCount(env: NodeJS.ProcessEnv): number {
  const raw = Number(env.GIT_CONFIG_COUNT);
  return Number.isInteger(raw) && raw >= 0 ? raw : 0;
}

export function codeAgentGitConfigEntries(proxyUrl = proxyUrlFromEnv(process.env)): Array<[string, string]> {
  return [
    ["safe.directory", "*"],
    ["http.proxy", proxyUrl],
    ["https.proxy", proxyUrl],
  ];
}

export function withCodeAgentGitConfigEnv(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv {
  const next: NodeJS.ProcessEnv = { ...env };
  let index = gitConfigCount(next);
  for (const [key, value] of codeAgentGitConfigEntries(proxyUrlFromEnv(next))) {
    next[`GIT_CONFIG_KEY_${index}`] = key;
    next[`GIT_CONFIG_VALUE_${index}`] = value;
    index += 1;
  }
  next.GIT_CONFIG_COUNT = String(index);
  return next;
}

export function normalizeCodeModel(value: string): string {
  const raw = String(value || "").trim();
  if (raw.length === 0) return raw;
  const lower = raw.toLowerCase();
  const leaf = lower.includes("/") ? lower.split("/").at(-1) ?? lower : lower;
  if (leaf === "minimax-m2.7" || leaf === "m2.7") return minimaxM27Model;
  if (leaf === "minimax-m3" || leaf === "m3") return minimaxM3Model;
  if (leaf === "deepseek" || leaf === "deepseek-chat") return deepseekChatModel;
  return raw;
}

export function codeAgentPortForModel(model: string): CodeAgentPortKind {
  const normalized = normalizeCodeModel(model);
  return normalized === minimaxM27Model || normalized === minimaxM3Model || normalized === deepseekChatModel ? "opencode" : "codex";
}

export function normalizeCodeExecutionMode(value: unknown): CodeExecutionMode {
  const raw = typeof value === "string" ? value.trim().toLowerCase() : "";
  if (raw === "windows-native" || raw === "windows" || raw === "win32" || raw === "native-windows") return "windows-native";
  return defaultCodeExecutionMode;
}

export function normalizeRequestedCodeExecutionMode(value: unknown): string | null {
  const raw = typeof value === "string" ? value.trim().toLowerCase() : "";
  if (raw.length === 0) return null;
  if (!/^[a-z0-9][a-z0-9-]{0,63}$/u.test(raw)) return null;
  return raw;
}

export function requestedCodeExecutionModeIsRecognized(value: unknown): boolean {
  const requested = normalizeRequestedCodeExecutionMode(value);
  return requested === null || codeExecutionModeAliases.has(requested);
}

export function codeExecutionModeInfo(mode: CodeExecutionMode): Record<string, JsonValue> {
  if (mode === "windows-native") {
    return {
      kind: mode,
      label: "Windows native Codex",
      description: "Run Codex on the provider Windows host while the execution container relays stdio.",
      codexRunsInContainer: false,
      requiresProvider: true,
      requiresWindowsCwd: true,
    };
  }
  return {
    kind: mode,
    label: "Default Codex runtime",
    description: "Use the Code Queue node Codex runtime or the provider execution container.",
    codexRunsInContainer: true,
    requiresProvider: false,
    requiresWindowsCwd: false,
  };
}

export function opencodeModels(models: string[]): string[] {
  return Array.from(new Set(models.filter((model) => codeAgentPortForModel(model) === "opencode")));
}

export function codeModelPorts(models: string[]): Record<string, CodeAgentPortKind> {
  return Object.fromEntries(models.map((model) => [model, codeAgentPortForModel(model)]));
}

function envRef(name: string, env: NodeJS.ProcessEnv): Record<string, JsonValue> {
  const value = env[name];
  return {
    ref: `env:${name}`,
    present: typeof value === "string" && value.trim().length > 0,
    valuesPrinted: false,
  };
}

function configRef(name: string, configuredValue: string, env: NodeJS.ProcessEnv): Record<string, JsonValue> {
  return {
    ...envRef(name, env),
    present: configuredValue.trim().length > 0,
    envPresent: envRef(name, env).present,
  };
}

export function codeModelProviderSourceContract(config: CodeModelProviderSourceConfig, env: NodeJS.ProcessEnv = process.env): Record<string, JsonValue> {
  const codeModels = Array.from(new Set(config.codeModels.map(normalizeCodeModel).filter(Boolean)));
  return {
    check: "code-model-provider-source-contract",
    valuesPrinted: false,
    codeModels,
    codexModels: config.codexModels ?? codeModels.filter((model) => codeAgentPortForModel(model) === "codex"),
    opencodeModels: opencodeModels(codeModels),
    modelPorts: codeModelPorts(codeModels) as unknown as JsonValue,
    providers: {
      deepseek: {
        runner: "opencode",
        publicModel: deepseekChatModel,
        providerModel: config.deepseekModel.trim() || deepseekChatModel,
        credentialSource: {
          apiKey: {
            ...configRef("DEEPSEEK_API_KEY", config.deepseekApiKey, env),
            present: config.deepseekApiKey.trim().length > 0,
          },
          baseURL: configRef("DEEPSEEK_API_BASE", config.deepseekApiBase, env),
          model: configRef("DEEPSEEK_MODEL", config.deepseekModel, env),
        },
      },
      minimax: {
        runner: "opencode",
        publicModel: minimaxM27Model,
        providerModel: config.minimaxModel.trim() || "MiniMax-M2.7",
        credentialSource: {
          apiKey: {
            ...configRef("MINIMAX_API_KEY", config.minimaxApiKey, env),
            present: config.minimaxApiKey.trim().length > 0,
          },
          baseURL: configRef("MINIMAX_API_BASE", config.minimaxApiBase, env),
          model: configRef("MINIMAX_MODEL", config.minimaxModel, env),
        },
      },
      minimaxM3: {
        runner: "opencode",
        publicModel: minimaxM3Model,
        providerModel: config.minimaxM3Model.trim() || "MiniMax-M3",
        credentialSource: {
          apiKey: {
            ...configRef("MINIMAX_API_KEY", config.minimaxApiKey, env),
            present: config.minimaxApiKey.trim().length > 0,
          },
          baseURL: configRef("MINIMAX_API_BASE", config.minimaxApiBase, env),
          model: configRef("MINIMAX_M3_MODEL", config.minimaxM3Model, env),
        },
      },
    },
  };
}

export function codeAgentPortInfo(kind: CodeAgentPortKind): Record<string, JsonValue> {
  return {
    kind,
    protocol: kind === "codex" ? "codex-app-server-jsonrpc-stdio" : "opencode-run-json-events",
    sessionResume: kind === "codex" ? "thread/resume" : "opencode --session with persisted XDG storage and stale-session recovery",
    tracePort: kind === "codex" ? "codex-transcript" : "opencode-json-event",
  };
}

export function textInput(text: string): JsonValue[] {
  return [{ type: "text", text, text_elements: [] }];
}

export function extractRecord(value: unknown): Record<string, unknown> | null {
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value as Record<string, unknown> : null;
}

export function extractString(value: unknown, key: string): string | null {
  const record = extractRecord(value);
  const field = record?.[key];
  return typeof field === "string" ? field : null;
}

export function terminalStatus(value: string): import("../types").TerminalStatus {
  if (value === "completed" || value === "interrupted" || value === "failed") return value;
  return null;
}

export function stripAnsi(text: string): string {
  return text.replace(/\u001b\[[0-9;]*m/gu, "");
}
