# dsh-coding-remote-kit
**v0.7.1** · DeepSeek Harness `0.1.1-rc.2` / `0.1.5-rc.2` · GitHub `dsh-coding-remote-kit`
**Acceso remoto por teléfono a [DeepSeek Harness](https://github.com/deepseek-ai/dsh).** Empareja un teléfono con el escritorio que ya ejecuta `dsh web`, observa sesiones y realiza un conjunto limitado de escrituras — sin exponer la API Web completa.
[](https://www.npmjs.com/package/dsh-coding-remote-kit)
[](LICENSE)
[](CONTRIBUTING.md)
*[English](README.md) · [中文版](README.zh-CN.md) · [日本語](README.ja.md) · [한국어](README.ko.md) · [Português (BR)](README.pt-BR.md) · [Español](README.es.md) · [Français](README.fr.md) · [Deutsch](README.de.md) · [Русский](README.ru.md)*
---
> **Upgrade / 升级:** Follow the versioned steps in [`INSTALL.md`](INSTALL.md). Install into the existing `web` profile, keep profile/config/credential files, and restart one existing DSH Web process after all packages are updated. When Hub and Subscription are both used, `dsh-coding-oauth-core@0.1.2` is their shared npm dependency, not a separate DSH plugin.
---
Plugin de la comunidad. **No está afiliado ni respaldado por DeepSeek.** La intención del producto está más cerca de [Orca Mobile Companion](https://www.onorca.dev/docs/mobile) que de una segunda copia del IDE de escritorio.
Lee [`AGENTS.md`](AGENTS.md) antes de cambiar este repositorio: **no reinicies tú mismo el `dsh-web` de producción.** Prepara el tarball; el operador reinicia.
## Nombres
Se desarrolló primero como GitHub `dsh-mobile-remote`. El nombre npm **`dsh-mobile-remote` es otro proyecto** (plugin de control remoto WeChat). Este plugin se publica como `dsh-coding-remote-kit`.
| | Usa esto | Notas |
|---|---|---|
| npm | `dsh-coding-remote-kit@0.7.1` | `dsh plugin --profile web add dsh-coding-remote-kit@0.7.1` |
| GitHub | [`lninghaha/dsh-coding-remote-kit`](https://github.com/lninghaha/dsh-coding-remote-kit) | nombre anterior del checkout `dsh-mobile-remote` |
| id del plugin Cordis | `mobile-remote` | sin cambios |
| HTTP de la página de ajustes | `/api/mobile-remote/*` | sin cambios |
| Almacenamiento | `$DSH_HOME/storages/mobile-remote/` | sin cambios |
**No** ejecutes `dsh plugin add dsh-mobile-remote` — instala el plugin WeChat no relacionado.
## Estado
| Hito | Estado |
| --- | --- |
| Investigación (Orca / ecosistema DSH) | hecho — [`docs/research/`](docs/research/) |
| M1 esqueleto del plugin + ADR / modelo de amenazas | hecho |
| M2 emparejamiento / plano de datos LAN | hecho |
| M3 RPC restringido / aprobaciones | hecho |
| M4 HTTPS firmado / app nativa | no iniciado |
| M5 Worker de rendezvous autohospedado | hecho — [`docs/05-cloud-relay.md`](docs/05-cloud-relay.md) |
## Características
- **IU bilingüe** — chino e inglés en Ajustes del escritorio y el companion del teléfono (`?lang=` / cambio en la app; por defecto `navigator.language`).
- **Empareja una vez** — el escritorio muestra un código QR o un PIN de 8 dígitos; el teléfono fija la clave pública X25519 del escritorio y guarda un `deviceToken` (el servidor almacena solo el SHA-256).
- **Plano dual** — las rutas de gestión se quedan en el `dsh web` de loopback; el plano de datos móvil es un puerto dedicado (por defecto `6879`) con una lista de RPC permitidos.
- **E2EE tras el handshake** — tweetnacl secretbox en `/m/ws`; los sockets no autenticados nunca ven el contenido de la sesión.
- **Escrituras estrechas** — observar sesiones, responder aprobaciones/preguntas, respuestas cortas; la edición pesada se queda en el escritorio.
- **Red privada primero** — se prefiere LAN / Tailscale. El Cloudflare Quick Tunnel opcional expone **solo** el plano de datos, nunca el puerto `3080`. Worker de rendezvous autohospedado opcional: escritorio y teléfono salen outbound; los frames de negocio siguen en E2EE.
- **Forma estándar de plugin** — un plugin Cordis de servidor + página de ajustes classic-script. `dsh plugin --profile web add` con un **file tarball**, nunca un árbol de trabajo `link:`.
## Capturas de pantalla
Escritorio Settings → Mobile Remote: crear oferta de emparejamiento (izquierda) · estado del canal y dispositivos (derecha)
Companion en el teléfono: introducir PIN / escanear (izquierda) · lista de sesiones tras el emparejamiento (derecha)
## Problemas que resuelve este plugin
| Buscaste / viste | Qué estaba realmente roto | Qué hace este plugin |
|---|---|---|
| “companion de teléfono estilo Orca para DSH” | El DSH oficial no tiene una app móvil emparejada de primera clase | Companion semántico: emparejamiento + E2EE + RPC en allowlist |
| `dsh-pocket` / `dsh-web-remote` en el teléfono | Superficie completa de `dsh web` en LAN/pública | Plano dual; los métodos RPC desconocidos son `forbidden` |
| Teléfono en red móvil, escritorio en LAN | Una página HTTP LAN cruda puede sufrir MITM | Prefiere Tailscale; Quick Tunnel opcional (TLS en el borde, origen localhost) |
| El `import` del plugin falló y el puerto 3080 murió | DSH hace fail-fast de todo el árbol de plugins | Puerta de sandbox + tarball copiado *fuera* del repo; sin `link:` |
## Inicio rápido
```bash
dsh plugin --profile web add dsh-coding-remote-kit@0.7.1
```
Después el **operador** reinicia el proceso `dsh web` existente en su propia ventana. Abre **Settings → 移動远程**, crea una oferta de emparejamiento, escanea el QR (o escribe el PIN) en el teléfono.
Desde un checkout de código (desarrollo):
```bash
pnpm test:sandbox
pnpm pack
mkdir -p "$HOME/.dsh/packages"
cp dsh-coding-remote-kit-0.7.1.tgz "$HOME/.dsh/packages/"
dsh plugin --profile web add "$HOME/.dsh/packages/dsh-coding-remote-kit-0.7.1.tgz"
```
No ejecutes `dsh plugin add ./` en este árbol de trabajo. pnpm 11 trata algunas rutas `file:` de tarball como fuente `link:`, y un import de entrada fallido tumba toda la GUI.
## Tabla de contenidos
- [Nombres](#nombres)
- [Estado](#estado)
- [Características](#características)
- [Capturas de pantalla](#capturas-de-pantalla)
- [Problemas que resuelve este plugin](#problemas-que-resuelve-este-plugin)
- [Inicio rápido](#inicio-rápido)
- [Instalación](#instalación)
- [Cómo funciona](#cómo-funciona)
- [Página de ajustes](#página-de-ajustes)
- [RPC móvil](#rpc-móvil)
- [Túnel público](#túnel-público)
- [Seguridad](#seguridad)
- [Arquitectura](#arquitectura)
- [Documentación](#documentación)
- [Relacionado](#relacionado)
- [Contribuir](#contribuir)
- [Licencia](#licencia)
## Instalación
Requiere DeepSeek Harness `0.1.1-rc.2` (fijado) y Node.js 22.19+. Pasos completos, emparejamiento y notas de túnel: [INSTALL.md](INSTALL.md).
Desarrollo:
```bash
pnpm install && pnpm build && pnpm test # inside the Docker sandbox, not on a live GUI host
pnpm test:sandbox # Dockerfile targets check / isolated-install / verify
```
Salidas de la build:
- `lib/server/index.js` — entrada Cordis (`name` / `inject` / `Config` / `apply`)
- `lib/client.js` — classic-script de la página de ajustes
- `lib/mobile/` — página del teléfono servida en `/m`
## Cómo funciona
```text
Settings (loopback) Phone browser
│ │
│ QR / PIN ────────────────┤
▼ ▼
/api/mobile-remote/* GET /m + WS /m/ws
(dsh web, :3080) (data plane, :6879, E2EE)
```
La gestión se queda detrás de la valla de loopback del Web del host. El plano de datos es un servidor separado `node:http` + `ws`. El emparejamiento puede volver a enlazarlo de `127.0.0.1` a `0.0.0.0` para clientes LAN; un Quick Tunnel activo anuncia su origen HTTPS en lugar de ensanchar el bind.
## Página de ajustes
Abre **Settings → 移動远程**:
- estado (bind, puerto, escuchando, dispositivos activos, túnel, rendezvous)
- canales **LAN** / **Quick Tunnel** / **rendezvous**
- crear oferta → QR + PIN de 8 dígitos
- lista de dispositivos y revocación
- instalación opcional del `cloudflared` oficial (nunca se ejecuta en el `apply()` del plugin)
- diagnósticos de conexión (candidatos sanitizados, pin/verify de cloudflared, versión del aviso)
- casilla de aviso de Quick Tunnel (obligatoria antes de Start)
## RPC móvil
Métodos en la allowlist (todo lo demás es `forbidden`):
`status.get` · `session.list` · `session.history` · `session.subscribe` · `session.unsubscribe` · `host.subscribe` · `session.prompt` · `session.cancel` · `session.create` · `respond` · `device.name`
Los pushes incluyen eventos de sesión más `approval.requested` / `question.requested` (con `rpcId` para `respond`). Formato de cable: [docs/03-protocol.md](docs/03-protocol.md).
## Túnel público
Por defecto **apagado**. Inicia desde Ajustes solo tras aceptar el aviso (`disclaimerAccepted: true`). El Quick Tunnel de `cloudflared` apunta **solo** a `127.0.0.1:`. `/m` queda alcanzable en una URL `https://.trycloudflare.com`; el emparejamiento sigue necesitando el token de fragmento (o PIN) y E2EE. El proceso hijo se mata al unload / Stop del plugin.
Nunca hagas túnel del puerto `3080` / `dsh web`. Un Worker de rendezvous autohospedado (escritorio y teléfono ambos outbound, frames de negocio aún E2EE) es opcional; ver [docs/05-cloud-relay.md](docs/05-cloud-relay.md). Necesita un plan Cloudflare Workers Paid y **no** es un relé público operado por este proyecto.
## Seguridad
Invariantes (modelo completo: [docs/04-threat-model.md](docs/04-threat-model.md)):
1. Las conexiones no autenticadas solo manejan el handshake.
2. `deviceToken` se almacena como SHA-256; las claves y los archivos de registro son `0600`.
3. Allowlist de RPC, denegación por defecto; las escrituras se auditan a `deviceId`.
4. El plano de gestión es loopback + Host + CSRF.
5. El plugin no debilita `/api` de `dsh web` y no toma proveedores `api-proxy`.
**Límite honesto de v0:** la primera descarga HTTP de `/m` en una LAN cruda puede sufrir MITM. Prefiere una VPN overlay.
Prohibiciones:
- No compartas credenciales de otra persona.
- No supervises cuentas sin autorización.
- No enlaces el puerto del plano de datos en `0.0.0.0` a Internet pública (el Quick Tunnel iniciado explícitamente por el usuario es la excepción).
- No impliques respaldo oficial de DeepSeek.
Los ejemplos de la documentación usan solo `example.com`, `127.0.0.1` y `YOUR_TOKEN`.
## Arquitectura
Plano dual, mapa de módulos, almacenamiento y handshake: [docs/02-architecture.md](docs/02-architecture.md) · [中文](docs/02-architecture.zh-CN.md).
Decisión del MVP (ruta B): [docs/01-mvp-scope.md](docs/01-mvp-scope.md).
## Documentación
| Doc | Propósito |
|---|---|
| [INSTALL.md](INSTALL.md) | Instalar, emparejar, túnel |
| [CHANGELOG.md](CHANGELOG.md) | Historial de versiones |
| [docs/00-project-rules.md](docs/00-project-rules.md) | Versionado, publicar vs solo local, límite del DSH anfitrión |
| [docs/01-mvp-scope.md](docs/01-mvp-scope.md) | ADR: alcance del MVP (chino) |
| [docs/02-architecture.md](docs/02-architecture.md) | Arquitectura interna · [中文](docs/02-architecture.zh-CN.md) |
| [docs/03-protocol.md](docs/03-protocol.md) | Allowlist RPC y sobres de push (chino) |
| [docs/04-threat-model.md](docs/04-threat-model.md) | Activos, atacantes, invariantes (chino) |
| [docs/05-cloud-relay.md](docs/05-cloud-relay.md) | Worker de rendezvous autohospedado (M5) |
| [CONTRIBUTING.md](CONTRIBUTING.md) | Guía de contribución |
| [AGENTS.md](AGENTS.md) | Reglas de agent/operador (sin reinicio de producción) |
## Relacionado
- [dsh-coding-subscription-oauth](https://github.com/lninghaha/dsh-coding-subscription-oauth) — plugin hermano; el diseño de la documentación está modelado en él.
- GitHub: [`lninghaha/dsh-coding-remote-kit`](https://github.com/lninghaha/dsh-coding-remote-kit).
- Este plugin es independiente del plugin de centro de uso `dsh-hub-oauth-gateway`.
- No sustituye a `@deepseek-ai/dsh`.
## Contribuir
Issues y PRs son bienvenidos. Consulta [CONTRIBUTING.md](CONTRIBUTING.md) para el sandbox Docker, las convenciones de commit y las capas de documentos.
## Licencia
[MIT](LICENSE).