<div align="center">

# 🐋 dsh-think-translate

**Idiomas:** [English](README.md) · [中文](README.zh-CN.md) · [日本語](README.ja.md) · [한국어](README.ko.md) · [Español](README.es.md) · [Français](README.fr.md) · [Deutsch](README.de.md) · [Русский](README.ru.md)

[![npm version](https://img.shields.io/npm/v/dsh-think-translate?color=4D6BFE&label=npm)](https://www.npmjs.com/package/dsh-think-translate)
[![license](https://img.shields.io/npm/l/dsh-think-translate?color=4D6BFE)](LICENSE)
[![dsh](https://img.shields.io/badge/powered_by-dsh-4D6BFE?style=flat-square&logo=deepseek&logoColor=white)](https://github.com/deepseek-ai/deepseek-harness)

<img src="demo/demo.gif?v=2" width="46%" alt="dsh-think-translate demo" style="border:1px solid #4D6BFE;border-radius:8px;margin:4px" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="demo/demo2.gif?v=2" width="41%" alt="dsh-think-translate demo 2" style="border:1px solid #4D6BFE;border-radius:8px;margin:4px" />

</div>

---

Traducción en la capa de visualización para la interfaz web de [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness): la **cadena de pensamiento (fila Think), las tarjetas de tareas y el texto de respuesta** se muestran en el idioma de destino elegido, mientras los originales permanecen intactos en la transcripción y el texto traducido **nunca entra en el contexto del modelo**.

## ✨ Características

Los modelos de la familia DeepSeek suelen razonar en chino — o en el idioma en que les da por pensar. dsh-think-translate muestra la fila Think, las tarjetas de tareas y la respuesta en *tu* idioma mientras miras, como subtítulos del pensamiento del modelo.

- **🕵️ Lee cualquier cadena de pensamiento** — razonamiento, cadena de pensamiento, tarjetas de tareas y respuestas traducidos en tiempo real, por lotes
- **8 idiomas de destino** — 中文 / English / 日本語 / 한국어 / Español / Français / Deutsch / Русский
- **Interfaz en un solo idioma** — panel de ajustes, filas de pensamiento y tarjetas de tareas siguen el idioma de destino (sin mezclar zh/en); la elección persiste
- **Modelo local primero** — usa tu modelo local de Ollama (qwen, etc.): privado, sin conexión, gratis. La primera selección **activa la descarga automática** con barra de progreso; el modelo se configura y habilita al terminar
- **🧠 Coste de contexto cero** — capa de visualización pura: el modelo sigue viendo el texto original y el texto traducido nunca consume la ventana de contexto
- **Respaldo Google / Bing** — cambio automático si el modelo local no está disponible (google usa un túnel CONNECT de Node con el proxy del sistema)
- **Artefactos de código omitidos** — rutas, comandos, URL, regex y líneas de código puro nunca se traducen
- **Traducción por lotes de frases** — las cadenas largas se traducen en lotes pequeños para mantener la calidad en modelos locales pequeños
- **🧩 Fragmentación por párrafos y frases** — las cadenas largas se dividen por líneas en blanco (se conserva la estructura de párrafos) y luego por frases, para que un modelo local pequeño mantenga la calidad
- **Salida en streaming** — las traducciones aparecen lote a lote mientras piensa; expande la fila Think para comparar con el original
- **🎚️ Momento de traducción ajustable** — pre-traducir todo / carga diferida de cadenas antiguas (por defecto) / solo al expandir
- **🔗 Cadena de proveedores dinámica** — el orden de la lista es el orden de uso: arrastra para reordenar y activa o desactiva cada fila. Integrados google gtx / bing / Ollama local más cualquier endpoint personalizado
- **🔌 Proveedores personalizados (OpenAI y Anthropic)** — añade desde el panel cualquier endpoint compatible con OpenAI (`/v1/chat/completions`) o la **Anthropic Messages API** (Claude): tipo, preajuste, URL base, clave de API y modelo
- **🪄 Hereda los proveedores configurados en DSH** — detecta filas DSH de solo lectura desde `settings.yaml` (`llm-pi-ai.providers`) y un botón reescanea y las añade todas a la cadena; la clave se resuelve en cada petición desde `.credentials.yaml` y nunca se guarda en la config del plugin. La ruta por defecto del propio harness también cuenta: si `agent-default-model` apunta a `deepseek-official`, la API oficial de DeepSeek aparece como una fila DSH más
- **⏱️ Resistente** — 3 reintentos con backoff + respaldo directo del navegador, botón de prueba por fila, los fallos nunca se almacenan en caché

## 📦 Instalación

```bash
# Opción 1: npm (recomendado)
dsh plugin --profile web add dsh-think-translate
# luego reinicia web

# Opción 2: GitHub
dsh plugin --profile web add github:UncleK/dsh-think-translate

# Opción 3: manual (junction + patch)
#  1. enlaza el paquete en el node_modules del perfil
New-Item -ItemType Junction -Path "$HOME\.dsh\profiles\node_modules\dsh-think-translate" `
  -Target "<ruta del repositorio>"
#  2. añade a "$HOME\.dsh\profiles\web\cordis.patch.yml":
# - insert:
#     - id: dsh-think-translate
#       name: dsh-think-translate
#  3. reinicia web
```

## 🧯 Después de actualizar DSH

Los plugins de cliente de terceros se cargan a través del grafo de módulos de cliente de DSH, y ese grafo se compone **una sola vez por proceso**: una composición fallida permanece en memoria hasta reiniciar. Por eso, justo después de actualizar suelen aparecer estas tres cosas.

- **Arrancar desde un checkout del código falla** con `client bundles not found; run \`pnpm run build\` before launch` —— los paquetes de cliente nuevos vienen sin compilar: ejecuta `pnpm run build` en el checkout del harness y vuelve a iniciar `dsh web`.
- **La interfaz del plugin desaparece** (la fila Think sin traducción, sin la sección *Traducción de cadena de pensamiento* en Ajustes) —— **reinicia `dsh web`**; a veces no basta con recargar la página.
- **La lista de modelos locales está vacía** —— el servicio `ollama` no está sirviendo ese directorio de modelos: revisa `ollama list` (o `GET /api/tags`) y el `OLLAMA_MODELS` que usa realmente el servicio en ejecución. Si los modelos están en otra unidad, un enlace de directorio (junction) puede apuntar el directorio predeterminado del servicio hacia ellos.

No hay nada que configurar en el plugin: no declara dependencia de orden con los paquetes internos de DSH (solo se enlaza al servicio `slots` y, opcionalmente, a `@deepseek-ai/dsh-client-ui-primitives`), así que funciona tanto en DSH antiguo (≤ 0.1.1-rc) como en la línea actual (≥ 0.1.2-alpha.1, incluida 0.1.5-rc.1).

## 🚀 Uso

1. Abre **Ajustes → Traducción de cadena de pensamiento**
2. Elige el **idioma de destino** (p. ej. Español) — el panel, las filas y las tarjetas cambian a ese idioma
3. Gestiona la **cadena de proveedores** (arrastra para ordenar, marca para activar):
   - Integrados: **google gtx / bing** (gratis, listos para usar, proxy del sistema) y **modelo local (Ollama)** (al elegirlo por primera vez se descarga 7b/14b o uno personalizado)
   - **Proveedores DSH**: los endpoints ya configurados en `settings.yaml` aparecen solos (solo lectura; márcalos para añadirlos a la cadena). El botón **Importar desde la config de DSH**, justo debajo de la lista, vuelve a escanear y los añade todos de una vez: ni baseURL ni clave que reescribir, porque la clave se resuelve desde las credenciales de DSH
   - La clave se escribe a mano o llega como **`apiKeyEnv`** desde un preajuste o una fila DSH: esa fila muestra la insignia `env:NAME`, y la clave se resuelve en cada petición sin escribirse nunca en `config.json`. El formulario de edición no tiene campo de variable de entorno (el valor se conserva intacto), pero vaciar un campo lo elimina de verdad (se envía como borrado explícito)
   - Si desmarcas uno, se omite. Los detalles están en [README.md](README.md)
4. Envía un mensaje y expande la fila Think para ver la traducción

## ⚙️ Cómo funciona

```
navegador → POST /_xlate/translate (mismo origen, sin CORS)
  → cadena de proveedores en el host (fail-open, reordenable):
      chain: [provider1, provider2, ...]   ← orden arrastrando en Ajustes
        google / bing / compatible con OpenAI / Anthropic
      cadena fallback (opcional, desactivada por defecto, se activa en el config)
  → respaldo directo desde el navegador
```

- La **configuración de proveedores** vive en `config.json` (generado en tiempo de ejecución, ignorado por git): `chain` (ids ordenados), `fallback` (enabled + chain, solo en el archivo), `providers` (por proveedor `type`/`enabled`/`baseURL`/`apiKey`/`apiKeyEnv`/`model`). Las configuraciones antiguas con `priority` se migran solas; un proveedor que declara `apiKeyEnv` resuelve la clave desde esa variable en cada petición (el `apiKey` literal queda como respaldo) y ninguna clave resuelta se escribe de vuelta en `config.json`; un `null` en un parche borra ese campo, que es como la interfaz vacía uno
- El **descubrimiento DSH** lee `settings.yaml` (`llm-pi-ai.providers`) y `.credentials.yaml` (`refs`) del harness al cargar; los proveedores detectados se marcan con `source: "dsh"`, las claves resueltas se quedan en memoria (nunca en `config.json`) y la ruta `/_xlate/dsh-scan` los relee cuando hace falta
- **Mitad host** (`lib/index.js`): adaptadores de proveedor, caché LRU (600), `/_xlate/models`, `/_xlate/model/pull` + `pull-status` (configura automáticamente al terminar)
- **Mitad cliente** (`lib/client.js`): UI en 8 idiomas, traducción por lotes, filas Think en streaming, persistencia en localStorage
- Capa de visualización pura: los originales permanecen en la transcripción y el contexto del modelo

## 🛠 Desarrollo

- Sin paso de compilación: `lib/client.js` es el bundle del navegador (fuente = artefacto); `lib/index.js` es el ESM del host
- Cambios en el cliente se aplican al refrescar; cambios en el host requieren reiniciar web
- Las cadenas de 8 idiomas viven en el diccionario `UI_TEXT` de `lib/client.js`

## 📄 Licencia

MIT
