vipcode 0.2.2 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.en.md CHANGED
@@ -2,13 +2,13 @@
2
2
 
3
3
  [![npm](https://img.shields.io/npm/v/vipcode.svg)](https://www.npmjs.com/package/vipcode) [![Tests](https://github.com/PabloVip/vipcode/actions/workflows/ci.yml/badge.svg)](https://github.com/PabloVip/vipcode/actions/workflows/ci.yml) [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) · [Español](README.md)
4
4
 
5
- A coding agent for your terminal (command `vipcode`), in the style of opencode, that only uses **free AI models** and **automatically switches provider** when one runs out. The interface and messages are in Spanish.
5
+ A coding agent for your terminal (command `vipcode`) that only uses **free AI models** and **automatically switches provider** when one runs out. The interface and messages are in Spanish.
6
6
 
7
7
  - **Works right after installing, with no keys or sign-up**: it uses providers that allow anonymous access (Kilo Gateway, OVHcloud, LLM7 and Pollinations).
8
8
  - For higher limits and better models, add free keys from the 20+ included providers (Gemini, NVIDIA, Mistral, Cerebras, OpenRouter, Groq, Z.ai…). With OpenRouter you just sign in through the browser: `vipcode auth login openrouter`.
9
9
  - With a free [LLM Stats](https://llm-stats.com) key, the best models are tried first according to their ranking.
10
10
  - Terminal UI with Markdown, syntax highlighting, diffs, permission prompts, `@file` and `/command` completion, a command palette (Ctrl+P) and `!command` to run shell commands.
11
- - Tools: read, write and edit files, `list_dir`, `glob`, `grep`, `bash`, `webfetch`, `websearch`, todo list, subagents, LSP diagnostics, MCP tools and **skills** (the open Agent Skills format used by Claude Code and opencode).
11
+ - Tools: read, write and edit files, `list_dir`, `glob`, `grep`, `bash`, `webfetch`, `websearch`, todo list, subagents, LSP diagnostics, MCP tools and **skills** (the open Agent Skills format used by many coding agents).
12
12
  - `/undo` and `/redo` backed by git snapshots, saved sessions, automatic context compaction, images, custom agents and commands.
13
13
 
14
14
  ## Install
@@ -19,6 +19,8 @@ Requires Node.js 22 or later.
19
19
  npm install -g vipcode
20
20
  ```
21
21
 
22
+ Works on macOS, Linux and Windows. On Windows, install [Git for Windows](https://git-scm.com/download/win): vipcode runs commands with its bash (models write bash commands) and uses git for `/undo`; without it, it falls back to PowerShell and tells the model. `VIPCODE_SHELL` picks another shell (`pwsh`, `powershell`, `cmd` or a path to bash).
23
+
22
24
  To update, type `/update` inside vipcode or run `vipcode update` (it installs the latest published version, or pulls the repository if you installed from source). Without the npm registry you can also install the latest GitHub release (`npm install -g https://github.com/PabloVip/vipcode/releases/latest/download/vipcode.tgz`) or run it from source:
23
25
 
24
26
  ```bash
@@ -43,7 +45,7 @@ vipcode update # update vipcode
43
45
 
44
46
  Every conversation is saved automatically in `~/.vipcode/sessions/` as `.json` (to resume it) and `.md` (the whole conversation, readable and never truncated by context compaction). When you resume one (`vipcode -c`, `/sessions`), the previous conversation is shown on screen.
45
47
 
46
- Inside the UI: Enter sends, Tab switches between the `build` and `plan` agents, Ctrl+P opens the command palette, `@path` attaches files, `!command` runs a shell command, Esc interrupts and `/help` lists everything.
48
+ Inside the UI: Enter sends, Tab switches between the `programar` (build) and `planear` (plan) agents, `/limites` shows how much of each free plan is left today (also in the status bar), Ctrl+P opens the command palette, `@path` attaches files, `!command` runs a shell command, Esc interrupts and `/help` lists everything.
47
49
 
48
50
  ## Security
49
51
 
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![npm](https://img.shields.io/npm/v/vipcode.svg)](https://www.npmjs.com/package/vipcode) [![Pruebas](https://github.com/PabloVip/vipcode/actions/workflows/ci.yml/badge.svg)](https://github.com/PabloVip/vipcode/actions/workflows/ci.yml) [![Licencia MIT](https://img.shields.io/badge/licencia-MIT-blue.svg)](LICENSE) · [English](README.en.md)
4
4
 
5
- Agente de programación para la terminal (comando `vipcode`), al estilo de opencode, que solo usa **modelos gratuitos** y **rota automáticamente** entre proveedores cuando uno se agota.
5
+ Agente de programación para la terminal (comando `vipcode`) que solo usa **modelos gratuitos** y **rota automáticamente** entre proveedores cuando uno se agota.
6
6
 
7
7
  - **Funciona nada más instalarlo, sin claves ni registro**: usa los proveedores que permiten el acceso anónimo (Kilo Gateway, OVHcloud, LLM7 y Pollinations).
8
8
  - Si quieres más límites y mejores modelos, añade claves gratuitas de los más de 20 proveedores incluidos (Gemini, NVIDIA, Mistral, Cerebras, OpenRouter, Groq, Z.ai…); con OpenRouter basta con iniciar sesión en el navegador. Los modelos gratis nuevos se descubren solos.
@@ -32,7 +32,9 @@ npm run build
32
32
  npm link # deja el comando «vipcode» disponible en cualquier carpeta
33
33
  ```
34
34
 
35
- Probado sobre todo en macOS; las pruebas automáticas también pasan en Linux. Si algo falla, [abre un issue](https://github.com/PabloVip/vipcode/issues).
35
+ Funciona en macOS, Linux y Windows: las pruebas automáticas pasan en los tres. Si algo falla, [abre un issue](https://github.com/PabloVip/vipcode/issues).
36
+
37
+ **En Windows** conviene tener [Git para Windows](https://git-scm.com/download/win): vipcode ejecuta los comandos con su bash, porque los modelos escriben comandos de bash, y usa git para `/undo`. Sin él usa PowerShell y se lo dice al modelo. Para elegir otra shell, pon `VIPCODE_SHELL` (`pwsh`, `powershell`, `cmd` o la ruta de un bash).
36
38
 
37
39
  ## Primeros pasos
38
40
 
@@ -58,10 +60,9 @@ Con **OpenRouter** no hace falta copiar nada: `vipcode auth login openrouter` (o
58
60
  Otros inicios de sesión no se incluyen porque sus dueños no permiten usarlos desde otros programas o ya no existen:
59
61
 
60
62
  - **Google (Gemini CLI, Antigravity)**: Google bloquea las cuentas que los usan fuera de sus programas. La vía permitida es la clave gratis de https://aistudio.google.com/apikey.
61
- - **GitHub Copilot**: solo está autorizado en opencode y en los editores oficiales, y además es de pago.
63
+ - **GitHub Copilot**: GitHub solo lo permite en los editores y programas que aprueba, y además es de pago.
62
64
  - **ChatGPT**: «Iniciar sesión con ChatGPT» existe, pero solo para Plus o Pro, pide que OpenAI dé de alta la aplicación y usa otra API.
63
65
  - **Qwen Code**: su plan gratis con cuenta cerró el 15/04/2026.
64
- - **Modelos gratis de opencode (Zen)**: solo funcionan dentro de opencode.
65
66
 
66
67
  Para elegir el navegador, pon el comando en `VIPCODE_BROWSER` (por ejemplo `export VIPCODE_BROWSER=firefox`).
67
68
 
@@ -95,7 +96,7 @@ Si la misma clave está en `auth.json` y en el entorno, gana la de `auth.json`.
95
96
  | Pollinations | sin clave (opcional `POLLINATIONS_API_KEY`) | https://auth.pollinations.ai | Límite por hora y por IP |
96
97
  | Ollama, LM Studio, llama.cpp | sin clave | se detectan solos si están encendidos | En tu ordenador, sin límites |
97
98
 
98
- GitHub Models ya no aparece: cerró el 30 de julio de 2026. Los modelos gratis de OpenCode Zen tampoco: opencode los paga y solo deja usarlos desde su propia aplicación.
99
+ GitHub Models ya no aparece: cerró el 30 de julio de 2026.
99
100
 
100
101
  ## Uso
101
102
 
@@ -105,7 +106,8 @@ vipcode # interfaz
105
106
  vipcode "arregla el test" # interfaz y empieza con ese mensaje
106
107
  vipcode -c # continúa la última sesión de esta carpeta
107
108
  vipcode run "tarea" --yolo # hace la tarea sin interfaz y termina
108
- vipcode --plan # empieza en modo solo lectura
109
+ vipcode --plan # empieza con el agente planear (solo lectura)
110
+ vipcode limites # cuánto te queda hoy de cada plan gratis
109
111
  vipcode run "/review" # también acepta comandos y skills: vipcode run "/mi-skill tarea"
110
112
  vipcode update # actualiza vipcode
111
113
  vipcode trust # confiar en la configuración que trae esta carpeta (vipcode untrust lo deshace)
@@ -118,19 +120,19 @@ vipcode trust # confiar en la configuración que trae esta carpet
118
120
  - **Con npm** (`npm install -g vipcode` o el paquete de la release): mira cuál es la última versión publicada en npm y en GitHub y, si es más nueva que la tuya, la instala.
119
121
  - **Desde el código** (`git clone` + `npm link`): trae lo último del repositorio con `git pull`, instala las dependencias y compila. Si tienes cambios sin guardar en esa carpeta, no toca nada y te avisa.
120
122
 
121
- Después cierra vipcode y vuelve a abrirlo. Además, una vez al día vipcode mira si hay una versión nueva y te avisa al abrirlo; se desactiva con `"checkUpdates": false` en la configuración.
123
+ Después cierra vipcode y vuelve a abrirlo. Además, una vez al día vipcode mira si hay una versión nueva y te avisa al abrirlo con un recuadro verde, y te lo recuerda en la barra de abajo hasta que actualizas; se desactiva con `"checkUpdates": false` en la configuración.
122
124
 
123
125
  ### En la interfaz
124
126
 
125
127
  - **Enter** envía. **Alt+Enter** o `\` al final de la línea añade una línea nueva.
126
128
  - **@ruta** adjunta un fichero, una carpeta o una imagen (con autocompletado). **Ctrl+V** pega una imagen del portapapeles, y arrastrar una imagen a la terminal también la adjunta.
127
- - **Tab** cambia entre los agentes principales (`build` y `plan`, más los tuyos). **↑/↓** recorren el historial.
129
+ - **Tab** cambia entre los agentes principales (`programar` y `planear`, más los tuyos). **↑/↓** recorren el historial.
128
130
  - **Ctrl+P** abre la paleta con todos los comandos, tus comandos y tus skills; escribe para filtrar.
129
131
  - **!comando** lo ejecuta en la terminal sin salir de vipcode (por ejemplo `!git status` o `!npm test`). La salida se ve en pantalla y le llega al agente junto con tu siguiente mensaje.
130
132
  - **Esc** interrumpe al agente. Mientras trabaja puedes seguir escribiendo: el mensaje se le entrega al acabar el paso actual.
131
133
  - **Ctrl+C** interrumpe, cierra el diálogo o borra lo escrito; dos veces seguidas sale.
132
134
 
133
- Mientras trabaja ves qué modelo está pensando, cada herramienta con su acción en español («Lee», «Edita», «Ejecuta»…), las líneas añadidas y quitadas y lo que tarda. Debajo de cada respuesta aparece el modelo que ha contestado, su nota, el tiempo y los tokens. La barra de abajo muestra el agente, el modelo, cuánto contexto llevas gastado (▰▰▱▱), los modelos disponibles y los mensajes en cola.
135
+ Mientras trabaja ves qué modelo está pensando, cada herramienta con su acción en español («Lee», «Edita», «Ejecuta»…), las líneas añadidas y quitadas y lo que tarda. Debajo de cada respuesta aparece el modelo que ha contestado, su nota, el tiempo y los tokens. La barra de abajo muestra el agente, el modelo, cuánto te queda de su plan gratis (ver [Cuánto te queda](#cuánto-te-queda)), cuánto contexto llevas gastado (▰▰▱▱), los modelos disponibles y los mensajes en cola.
134
136
 
135
137
  Antes de editar un fichero, ejecutar un comando o salir a internet, vipcode pregunta enseñando el diff o el comando. Puedes contestar que sí una vez, que sí a todo lo de ese tipo durante la sesión, que sí siempre a un comando concreto (por ejemplo `npm test*`), que no, o que no y explicarle qué hacer.
136
138
 
@@ -150,12 +152,13 @@ Para volver a una conversación: `vipcode -c` (la última de esta carpeta), `/se
150
152
  | `/models` | Lista de modelos y su estado; elige uno preferido. `/models refresh` busca modelos gratis nuevos |
151
153
  | `/model <p/m>` | Fija un modelo (`/model auto` vuelve a la rotación) |
152
154
  | `/connect`, `/disconnect`, `/providers` | Añadir, quitar y ver las claves de los proveedores |
153
- | `/agents`, `/agent <nombre>`, `/plan`, `/build` | Cambiar de agente |
155
+ | `/agents`, `/agent <nombre>`, `/planear`, `/programar` | Cambiar de agente (también valen `/plan` y `/build`) |
154
156
  | `/undo`, `/redo`, `/diff [all]` | Deshacer y rehacer el último mensaje (ficheros y conversación); ver los cambios |
155
157
  | `/todos` | Lista de tareas del agente |
156
158
  | `/skills` | Skills instaladas; elige una para usarla (o escribe `/nombre-de-la-skill tarea`) |
157
159
  | `/compact` | Resumir la conversación |
158
160
  | `/new`, `/sessions`, `/load <n>`, `/delete <n>`, `/export` | Sesiones |
161
+ | `/limites` | Cuánto te queda hoy de cada plan gratis (ver [Cuánto te queda](#cuánto-te-queda)) |
159
162
  | `/usage` | Tokens usados |
160
163
  | `/mcp`, `/lsp` | Estado de los servidores MCP y de lenguaje |
161
164
  | `/yolo [on\|off]` | Aprobar todo sin preguntar durante la sesión |
@@ -167,9 +170,11 @@ Para volver a una conversación: `vipcode -c` (la última de esta carpeta), `/se
167
170
 
168
171
  ### Agentes
169
172
 
170
- - **build**: el principal; puede editar y ejecutar.
171
- - **plan**: solo lectura; investiga y propone un plan. Los subagentes que lance tampoco pueden editar.
172
- - **general** y **explore**: subagentes que el agente principal lanza con la herramienta `task` para investigar o hacer subtareas con su propio contexto. Si pide varios a la vez, trabajan en paralelo.
173
+ - **programar**: el principal; puede editar y ejecutar.
174
+ - **planear**: solo lectura; investiga y propone un plan. Los subagentes que lance tampoco pueden editar.
175
+ - **ayudante** y **explorar**: subagentes que el agente principal lanza con la herramienta `task` para hacer subtareas con su propio contexto (ayudante puede editar; explorar solo busca y lee). Si pide varios a la vez, trabajan en paralelo.
176
+
177
+ Antes se llamaban `build`, `plan`, `general` y `explore`, y esos nombres siguen valiendo en `/agent`, `--agent`, la configuración y los ficheros de agentes.
173
178
 
174
179
  ## Cómo funciona la rotación
175
180
 
@@ -204,6 +209,15 @@ vipcode salta al siguiente de la lista. Lo que pasa con el que ha fallado depend
204
209
 
205
210
  Las pausas se guardan en `~/.vipcode/state.json`, así que se recuerdan entre ejecuciones. Si todos están en pausa menos de 90 s, vipcode espera; si no, te dice cuándo vuelve el primero.
206
211
 
212
+ ### Cuánto te queda
213
+
214
+ `/limites` (o `vipcode limites` en la terminal) enseña lo que llevas hoy en cada proveedor y en cada modelo (peticiones y tokens), cuánto te queda y qué está en pausa y hasta cuándo. La barra de abajo dice lo que queda del modelo que estás usando, en amarillo si queda poco y en rojo si se ha acabado.
215
+
216
+ - **«quedan»** es lo que dice el propio proveedor en cada respuesta (Groq y Cerebras, por ejemplo, dicen cuántas peticiones te quedan hoy y cuántos tokens por minuto).
217
+ - **«≈ quedan»** es la cuenta de vipcode cuando el proveedor no lo dice: los límites conocidos de su plan gratis (OpenRouter, ModelScope, Kilo, LLM7…) menos lo que ha pedido vipcode. Solo cuenta lo de este ordenador: si usas la misma clave en otros programas, te quedará menos.
218
+
219
+ El día cuenta en hora UTC, como en la mayoría de proveedores.
220
+
207
221
  Una vez al día (o con `/models refresh`, o `vipcode models refresh` desde la terminal) vipcode pregunta a cada proveedor qué modelos tiene, también a los que no piden clave (Kilo, OVHcloud y LLM7), añade los gratis nuevos y quita los que ya no existen.
208
222
 
209
223
  ## Configuración
@@ -240,7 +254,7 @@ Una vez al día (o con `/models refresh`, o `vipcode models refresh` desde la te
240
254
  "pyright": false,
241
255
  "mi-lsp": { "command": ["mi-lsp", "--stdio"], "extensions": [".foo"] }
242
256
  },
243
- "agents": { "plan": { "model": "gemini/*" } },
257
+ "agents": { "planear": { "model": "gemini/*" } },
244
258
  "commands": { "tests": { "template": "Ejecuta los tests y arregla lo que falle. $ARGUMENTS", "description": "Arregla los tests" } },
245
259
  "instructions": ["docs/estilo.md", ".cursor/rules/*.md"],
246
260
  "maxSteps": 50,
@@ -262,12 +276,12 @@ Una vez al día (o con `/models refresh`, o `vipcode models refresh` desde la te
262
276
  - **providers**: si el nombre coincide con uno del catálogo, solo cambia lo que pongas (los modelos se añaden o se sobrescriben por id; con `"replaceModels": true` se usan solo los tuyos). Si es nuevo, es un proveedor propio compatible con la API de OpenAI y va el primero en la rotación. Admite `apiKeyEnv`, `apiKey`, `headers`, `noKey`, `discover: "openai"` para descubrir sus modelos, y en cada modelo `context`, `vision` y `disabled`.
263
277
  - **order**: patrones `proveedor/modelo` que van primero. **model**: modelo fijado al arrancar.
264
278
  - **permission**: `allow`, `ask` o `deny`. En `bash` y `mcp` gana el patrón más concreto, y los comandos encadenados (`&&`, `&`, `|`, `;`, saltos de línea) se comprueban por separado. Aunque un comando esté permitido, se pregunta siempre si escribe en un fichero (`>`, `--output`) o lleva `$(…)` o comillas invertidas. Las reglas `deny` se respetan incluso con `--yolo`.
265
- - **mcp**: servidores locales (`command`) o remotos (`url`, con HTTP o SSE). Sus herramientas aparecen como `servidor_herramienta`. En modo plan solo se usan las marcadas como de solo lectura.
279
+ - **mcp**: servidores locales (`command`) o remotos (`url`, con HTTP o SSE). Los remotos que piden iniciar sesión con OAuth todavía no funcionan; los que usan una cabecera con token, sí. Sus herramientas aparecen como `servidor_herramienta`. En modo plan solo se usan las marcadas como de solo lectura.
266
280
  - **lsp**: `false` desactiva los diagnósticos; `"id": false` desactiva un servidor concreto.
267
281
 
268
282
  ### Agentes y comandos propios
269
283
 
270
- Ficheros Markdown en `~/.vipcode/agents/`, `.vipcode/agents/` o `.opencode/agent/` (compatible con opencode):
284
+ Ficheros Markdown en `~/.vipcode/agents/` (para todos tus proyectos) o `.vipcode/agents/` (solo para ese proyecto):
271
285
 
272
286
  ```markdown
273
287
  ---
@@ -283,12 +297,12 @@ tools:
283
297
  Eres un experto en seguridad. Busca inyecciones, secretos en el código y permisos mal puestos.
284
298
  ```
285
299
 
286
- Comandos en `~/.vipcode/commands/`, `.vipcode/commands/` o `.opencode/command/`. Se lanzan con `/nombre argumentos`:
300
+ Comandos en `~/.vipcode/commands/` o `.vipcode/commands/`. Se lanzan con `/nombre argumentos`:
287
301
 
288
302
  ```markdown
289
303
  ---
290
304
  description: Arregla los tests que fallan
291
- agent: build
305
+ agent: programar
292
306
  ---
293
307
  Estos son los tests que fallan ahora mismo:
294
308
  !`npm test 2>&1 | tail -40`
@@ -298,11 +312,11 @@ Arréglalos. Céntrate en $ARGUMENTS.
298
312
 
299
313
  `$ARGUMENTS` es todo lo que escribes detrás del comando, `$1`…`$9` cada palabra (respetando comillas), y `` !`comando` `` se sustituye por su salida. Con `subtask: true` el comando se ejecuta como subagente y no llena la conversación.
300
314
 
301
- Los agentes y comandos que traiga un proyecto se cargan siempre, pero hasta que confías en la carpeta un agente del proyecto no puede cambiar sus permisos (`permission`, `readOnly`) y los `` !`comando` `` de sus comandos no se ejecutan.
315
+ Los agentes y comandos que traiga un proyecto (también los de `.opencode/agent/` y `.opencode/command/`, si ya los tiene) se cargan siempre, pero hasta que confías en la carpeta un agente del proyecto no puede cambiar sus permisos (`permission`, `readOnly`) y los `` !`comando` `` de sus comandos no se ejecutan.
302
316
 
303
317
  ### Skills
304
318
 
305
- Una skill es una carpeta con un `SKILL.md`: instrucciones (y, si hace falta, scripts y documentos) para un tipo de tarea concreto, como rellenar PDF, seguir la guía de estilo de la empresa o preparar un informe. Es el formato abierto [Agent Skills](https://agentskills.io), el mismo que usan Claude Code y opencode, así que las que encuentres para ellos también sirven aquí.
319
+ Una skill es una carpeta con un `SKILL.md`: instrucciones (y, si hace falta, scripts y documentos) para un tipo de tarea concreto, como rellenar PDF, seguir la guía de estilo de la empresa o preparar un informe. Es el formato abierto [Agent Skills](https://agentskills.io), que usan muchos agentes de programación, así que las skills que encuentres para ellos también sirven aquí.
306
320
 
307
321
  ```markdown
308
322
  ---
@@ -330,13 +344,13 @@ vipcode skills remove informes-semanales
330
344
 
331
345
  `vipcode skills add` copia las skills a `~/.vipcode/skills`, o con `--project` a `.vipcode/skills`. Si ya existe una con el mismo nombre la deja como está, salvo que añadas `--force`. Para los repositorios hace falta tener `git` instalado.
332
346
 
333
- vipcode también lee las skills de `~/.claude/skills`, `~/.config/opencode/skill`, `~/.agents/skills` y las mismas carpetas dentro del proyecto. Si dos tienen el mismo nombre, gana la del proyecto. En la configuración:
347
+ vipcode también lee las skills que ya tengas de otros programas (`~/.claude/skills`, `~/.config/opencode/skill`, `~/.agents/skills` y las mismas carpetas dentro del proyecto). Si dos tienen el mismo nombre, gana la del proyecto. En la configuración:
334
348
 
335
349
  ```json
336
350
  "skills": { "enabled": true, "paths": ["~/mis-skills"], "disabled": ["una-que-no-quiero"], "external": true }
337
351
  ```
338
352
 
339
- `paths` añade carpetas, `disabled` ignora skills por nombre y `external: false` deja de leer las carpetas de Claude Code, opencode y `.agents`. En la cabecera de la skill, `user-invocable: false` hace que solo la use el agente, y `disable-model-invocation: true` que solo la uses tú con `/nombre`.
353
+ `paths` añade carpetas, `disabled` ignora skills por nombre y `external: false` deja de leer esas carpetas de otros programas. En la cabecera de la skill, `user-invocable: false` hace que solo la use el agente, y `disable-model-invocation: true` que solo la uses tú con `/nombre`.
340
354
 
341
355
  Las skills pueden traer scripts: revisa las que instales si no conoces su origen. vipcode no ejecuta nada por su cuenta; si la skill pide lanzar un script, el agente usa `bash` y te pide permiso igual que con cualquier otro comando.
342
356
 
@@ -352,7 +366,7 @@ Después de cada edición, vipcode pregunta al servidor de lenguaje si hay error
352
366
 
353
367
  vipcode ejecuta lo que le pide un modelo de IA, así que está hecho para que nada importante pase sin que lo veas:
354
368
 
355
- - **Permisos.** Antes de editar un fichero, ejecutar un comando, salir a internet o usar una herramienta MCP, pregunta enseñando el diff o el comando. De serie solo se aprueban solos unos pocos comandos que no cambian nada (`git status`, `git diff`, `git log`, `git show`, `ls`, `pwd`), y ni siquiera esos si llevan otro comando detrás (`&`, `;`, `&&`, `|`), escriben en un fichero (`>`, `--output`) o llevan `$(…)`. Con `--yolo` o `/yolo` se aprueba todo menos lo que tengas en `deny`: úsalo solo en carpetas sin nada que perder.
369
+ - **Permisos.** Antes de editar un fichero, ejecutar un comando, salir a internet o usar una herramienta MCP, pregunta enseñando el diff o el comando. De serie solo se aprueban solos unos pocos comandos que no cambian nada (`git status`, `git diff`, `git log`, `git show`, `ls`, `pwd`), y ni siquiera esos si llevan otro comando detrás (`&`, `;`, `&&`, `|`), escriben en un fichero (`>`, `--output`) o llevan `$(…)`. Con `--yolo` o `/yolo` se aprueba todo menos lo que tengas en `deny`: úsalo solo en carpetas sin nada que perder, porque los comandos no se ejecutan aislados en un sandbox.
356
370
  - **Carpetas en las que confías.** Un proyecto puede traer su propia configuración de vipcode (`vipcode.json`, `.vipcode/config.json`, agentes con permisos propios, comandos con `` !`órdenes` ``). Como eso podría arrancar programas, mandar tus claves a otro servidor o quitar las preguntas de permiso, vipcode no lo usa hasta que confías en la carpeta. Al abrirlo te enseña qué cambiaría y te pregunta; con `vipcode run` solo avisa. Si la configuración cambia después (por ejemplo tras un `git pull`), vuelve a preguntar. `vipcode trust` y `vipcode untrust` lo cambian a mano.
357
371
  - **Ficheros.** Las herramientas solo leen y escriben dentro de la carpeta del proyecto. Un enlace simbólico que lleve fuera (por ejemplo a `~/.ssh` o a tus claves) se rechaza.
358
372
  - **vipcode no puede tocarse a sí mismo.** Aunque lo abras en una carpeta que las contenga (por ejemplo tu carpeta personal), el agente no puede leer ni cambiar `~/.vipcode` (tus claves, tu configuración y las carpetas en las que confías) ni modificar la carpeta donde está instalado vipcode, así que tampoco puede desactivar estas protecciones. Los comandos que nombran esas carpetas se preguntan siempre, aunque tengas una regla `allow` o hayas dicho «sí a todo», y con `--yolo` sin nadie delante se rechazan.
@@ -371,7 +385,7 @@ Los planes gratuitos tienen letra pequeña: los proveedores anónimos (Kilo, OVH
371
385
 
372
386
  Todo está en `~/.vipcode` (o en `VIPCODE_HOME` si la defines):
373
387
 
374
- - `config.json`: tu configuración. `auth.json`: claves (permisos 600). `state.json`: pausas de los proveedores. `notices.json`: avisos que ya has visto. `update.json`: última comprobación de versiones nuevas. `trusted.json`: carpetas en las que confías.
388
+ - `config.json`: tu configuración. `auth.json`: claves (permisos 600). `state.json`: pausas de los proveedores y lo que llevas usado hoy. `notices.json`: avisos que ya has visto. `update.json`: última comprobación de versiones nuevas. `trusted.json`: carpetas en las que confías.
375
389
  - `models.json`: modelos descubiertos. `ranking.json`: puntuaciones de LLM Stats descargadas con tu clave. `sessions/`: conversaciones (un `.json` para seguirlas y un `.md` para leerlas). `history.jsonl`: lo que has escrito.
376
390
  - `snapshots/`: instantáneas para `/undo` (un repositorio git aparte por proyecto; no toca tu `.git`).
377
391
  - `exports/`: conversaciones exportadas. `agents/`, `commands/` y `skills/`: tus agentes, comandos y skills globales.
@@ -396,14 +410,6 @@ npm run release -- 0.3.0 # o patch, minor o major
396
410
 
397
411
  Sube el número en `package.json`, pasa las pruebas, crea el commit y la etiqueta, lo sube a GitHub, crea la release con el paquete compilado y lo publica en npm. Quien ya tenga vipcode verá el aviso de versión nueva en menos de un día.
398
412
 
399
- ## Lo que aún no tiene respecto a opencode
400
-
401
- - La interfaz se dibuja en la propia terminal, no en pantalla completa con paneles.
402
- - No hay `/share` para publicar la conversación en la web: `/export` la guarda en Markdown.
403
- - Los servidores MCP remotos con OAuth no funcionan; sí los que usan una cabecera con token.
404
- - No tiene integración con GitHub (responder a issues o PR) ni cliente/servidor para controlarlo desde otras aplicaciones.
405
- - `bash` no está aislado en un sandbox: se protege con los permisos.
406
-
407
413
  ## Licencia
408
414
 
409
415
  [MIT](LICENSE) © Pablo Vicente Juan.
package/dist/agent.js CHANGED
@@ -1,4 +1,4 @@
1
- import { subagents, toolEnabled } from "./agents.js";
1
+ import { MAIN_AGENT, agentName, subagents, toolEnabled } from "./agents.js";
2
2
  import { systemPrompt } from "./prompt.js";
3
3
  import { estimateTokens } from "./router.js";
4
4
  import { saveSession } from "./session.js";
@@ -22,10 +22,10 @@ export class Agent {
22
22
  running = false;
23
23
  // Aviso para el modelo que se añade al siguiente mensaje (por ejemplo tras /undo)
24
24
  pendingNote = "";
25
- constructor(deps, session, agentName = "build") {
25
+ constructor(deps, session, name = MAIN_AGENT) {
26
26
  this.deps = deps;
27
27
  this.session = session;
28
- this.agent = deps.agents.find((agent) => agent.name === agentName) || deps.agents.find((agent) => agent.name === "build");
28
+ this.agent = deps.agents.find((agent) => agent.name === agentName(name)) || deps.agents.find((agent) => agent.name === MAIN_AGENT);
29
29
  }
30
30
  get mode() {
31
31
  if (this.agent.readOnly) {
@@ -34,7 +34,7 @@ export class Agent {
34
34
  return "build";
35
35
  }
36
36
  setAgent(name) {
37
- const found = this.deps.agents.find((agent) => agent.name === name);
37
+ const found = this.deps.agents.find((agent) => agent.name === agentName(name));
38
38
  if (!found) {
39
39
  return false;
40
40
  }
@@ -413,9 +413,9 @@ export class Agent {
413
413
  }
414
414
  // Un subagente trabaja con su propio historial y devuelve solo su informe final
415
415
  async runSubagent(type, prompt, description, parent, signal) {
416
- let sub = subagents(this.deps.agents).find((agent) => agent.name === type);
416
+ let sub = subagents(this.deps.agents).find((agent) => agent.name === agentName(type));
417
417
  if (!sub) {
418
- sub = subagents(this.deps.agents).find((agent) => agent.name === "general");
418
+ sub = subagents(this.deps.agents).find((agent) => agent.name === "ayudante");
419
419
  }
420
420
  if (!sub) {
421
421
  return `Error: no existe el subagente ${type}.`;
package/dist/agents.js CHANGED
@@ -13,7 +13,7 @@ Use glob, grep, list_dir and read_file to answer the question about the codebase
13
13
  Your final answer is the only thing the main agent will see: give precise findings with file paths and line numbers.`;
14
14
  const BUILTIN = [
15
15
  {
16
- name: "build",
16
+ name: "programar",
17
17
  description: "Agente principal: lee, edita ficheros y ejecuta comandos",
18
18
  mode: "primary",
19
19
  prompt: "",
@@ -23,7 +23,7 @@ const BUILTIN = [
23
23
  builtIn: true,
24
24
  },
25
25
  {
26
- name: "plan",
26
+ name: "planear",
27
27
  description: "Solo lectura: investiga y propone un plan sin tocar nada",
28
28
  mode: "primary",
29
29
  prompt: PLAN_PROMPT,
@@ -34,7 +34,7 @@ const BUILTIN = [
34
34
  builtIn: true,
35
35
  },
36
36
  {
37
- name: "general",
37
+ name: "ayudante",
38
38
  description: "Subagente para investigar preguntas complejas o hacer tareas de varios pasos de forma autónoma (puede editar)",
39
39
  mode: "subagent",
40
40
  prompt: GENERAL_PROMPT,
@@ -44,7 +44,7 @@ const BUILTIN = [
44
44
  builtIn: true,
45
45
  },
46
46
  {
47
- name: "explore",
47
+ name: "explorar",
48
48
  description: "Subagente rápido de solo lectura para encontrar ficheros, símbolos o entender cómo funciona algo del código",
49
49
  mode: "subagent",
50
50
  prompt: EXPLORE_PROMPT,
@@ -54,6 +54,14 @@ const BUILTIN = [
54
54
  builtIn: true,
55
55
  },
56
56
  ];
57
+ // Los agentes integrados se llamaban como en opencode: esos nombres siguen valiendo (en /agent, --agent, el config,
58
+ // los ficheros .md que los ajustan, las sesiones guardadas y lo que pida el modelo a la herramienta task)
59
+ const AGENT_ALIASES = { build: "programar", plan: "planear", general: "ayudante", explore: "explorar" };
60
+ export const MAIN_AGENT = "programar";
61
+ // Nombre de verdad de un agente aunque se use el antiguo
62
+ export function agentName(name) {
63
+ return AGENT_ALIASES[name] || name;
64
+ }
57
65
  // Nombres de herramientas de opencode → los de vipcode
58
66
  const ALIASES = {
59
67
  read: "read_file",
@@ -122,10 +130,11 @@ export function loadAgents(root, config, trusted = projectTrust(root).trusted) {
122
130
  const disabled = new Set();
123
131
  const apply = (name, input, source) => {
124
132
  if (input.disable) {
125
- disabled.add(name);
133
+ disabled.add(agentName(name));
126
134
  return;
127
135
  }
128
- agents.set(name, fromInput(name, input, agents.get(name), source));
136
+ const real = agentName(name);
137
+ agents.set(real, fromInput(real, input, agents.get(real), source));
129
138
  };
130
139
  for (const entry of readMarkdownDir(dirs)) {
131
140
  const data = entry.data;
@@ -151,8 +160,8 @@ export function loadAgents(root, config, trusted = projectTrust(root).trusted) {
151
160
  for (const name of disabled) {
152
161
  agents.delete(name);
153
162
  }
154
- if (!agents.has("build")) {
155
- agents.set("build", { ...BUILTIN[0] });
163
+ if (!agents.has(MAIN_AGENT)) {
164
+ agents.set(MAIN_AGENT, { ...BUILTIN[0] });
156
165
  }
157
166
  return [...agents.values()];
158
167
  }
package/dist/app.js CHANGED
@@ -2,13 +2,14 @@ import { spawn } from "node:child_process";
2
2
  import fs from "node:fs";
3
3
  import pc from "picocolors";
4
4
  import { Agent } from "./agent.js";
5
- import { loadAgents, primaryAgents, subagents } from "./agents.js";
5
+ import { MAIN_AGENT, agentName, loadAgents, primaryAgents, subagents } from "./agents.js";
6
6
  import { envNames, maskKey, readAuth, removeAuth, resolveCredentials, saveAuth, urlVars } from "./auth.js";
7
7
  import { CATALOG } from "./catalog.js";
8
8
  import { expandCommand, loadCommands } from "./commands.js";
9
9
  import { CONFIG_PATH, configNotices, isAnonymous, loadConfig, setGlobalConfigValue } from "./config.js";
10
10
  import { buildProviders, detectLocal, refreshModels } from "./discovery.js";
11
11
  import { isRemoteSession, loginOpenRouter, openBrowser } from "./login.js";
12
+ import { limitsReport } from "./limits.js";
12
13
  import { LspManager } from "./lsp.js";
13
14
  import { McpManager } from "./mcp.js";
14
15
  import { AUTH_PATH, HOME_DIR, NOTICES_PATH, STATE_PATH, ensureHomeDir } from "./paths.js";
@@ -18,6 +19,7 @@ import { Router } from "./router.js";
18
19
  import { loadSkills, skillContent } from "./skills.js";
19
20
  import { deleteSession, listSessions, newSession, saveExport, saveSession, sessionMarkdownPath } from "./session.js";
20
21
  import { Snapshots } from "./snapshot.js";
22
+ import { commandShell, killTree } from "./shell.js";
21
23
  import { updateVipcode } from "./update.js";
22
24
  import { formatTodos, truncate } from "./tools.js";
23
25
  import { projectTrust } from "./trust.js";
@@ -30,8 +32,9 @@ export const BUILTIN_COMMANDS = [
30
32
  { name: "providers", description: "proveedores gratuitos, si tienes clave y dónde conseguirla" },
31
33
  { name: "agents", description: "agentes disponibles (Tab cambia entre los principales)" },
32
34
  { name: "agent", args: "<nombre>", description: "cambiar de agente" },
33
- { name: "plan", description: "agente de solo lectura" },
34
- { name: "build", description: "agente que puede modificar ficheros" },
35
+ { name: "planear", description: "agente de solo lectura: investiga y propone un plan (antes /plan)" },
36
+ { name: "programar", description: "agente que puede modificar ficheros (antes /build)" },
37
+ { name: "limites", description: "cuánto te queda hoy de cada plan gratis" },
35
38
  { name: "undo", description: "deshacer el último mensaje (ficheros y conversación)" },
36
39
  { name: "redo", description: "rehacer lo deshecho" },
37
40
  { name: "diff", args: "[all]", description: "cambios del último mensaje (o de toda la sesión)" },
@@ -127,6 +130,10 @@ export class App {
127
130
  yolo = false;
128
131
  local = {};
129
132
  lastSessions = [];
133
+ // Versión nueva de vipcode publicada: la interfaz la recuerda abajo hasta que la instalas con /update
134
+ newVersion = null;
135
+ // /update ya la ha instalado: se usa al cerrar y volver a abrir vipcode
136
+ updateInstalled = false;
130
137
  // La interfaz pone aquí cómo preguntar los permisos
131
138
  promptPermission = async () => ({
132
139
  allow: false,
@@ -171,7 +178,7 @@ export class App {
171
178
  snapshots: this.snapshots,
172
179
  skills: this.skills,
173
180
  ask: (request, agent) => this.ask(request, agent),
174
- }, options.session || newSession(root), options.agentName || options.session?.agent || "build");
181
+ }, options.session || newSession(root), options.agentName || options.session?.agent || MAIN_AGENT);
175
182
  }
176
183
  ask(request, agent) {
177
184
  const permission = permissionsFor(this.config.permission, agent.permission);
@@ -206,7 +213,11 @@ export class App {
206
213
  }
207
214
  privacyNotice() {
208
215
  const names = [...new Set(this.router.slots.filter((slot) => slot.anonymous).map((slot) => (slot.provider.label || slot.provider.name).replace(/ \(sin clave\)$/, "")))];
209
- return `Sin clave, vipcode usa proveedores gratuitos que no piden registro (${names.join(", ")}). Pueden guardar lo que les envías y usarlo para mejorar sus modelos: no les mandes contraseñas, claves ni código confidencial. Con /connect añades un proveedor con clave, y con "keyless": false en la configuración dejas de usar los anónimos.`;
216
+ return [
217
+ `Para que puedas empezar ya mismo, vipcode usa IAs gratuitas que no piden registro (${names.join(", ")}).`,
218
+ "Como son gratis, pueden guardar lo que les escribes para mejorar sus modelos, así que mejor no compartas contraseñas, claves ni datos privados.",
219
+ "Cuando quieras, conecta una cuenta gratuita con /connect y tendrás más mensajes y más modelos.",
220
+ ].join("\n");
210
221
  }
211
222
  acceptPrivacyNotice() {
212
223
  let data = {};
@@ -303,7 +314,7 @@ export class App {
303
314
  }
304
315
  anonymousNotice() {
305
316
  const names = [...new Set(this.router.slots.map((slot) => (slot.provider.label || slot.provider.name).replace(/ \(sin clave\)/, "")))];
306
- return `Sin claves: usando modelos gratis anónimos (${names.join(", ")}). Tienen pocas peticiones por hora y pueden guardar lo que envías; con /connect añades claves gratis con más límites.`;
317
+ return `Estás usando IAs gratuitas sin registro (${names.join(", ")}). Consejo: conecta una cuenta gratuita con /connect para tener más mensajes y más modelos (y recuerda no compartir datos privados).`;
307
318
  }
308
319
  // Siguiente agente principal (Tab)
309
320
  cycleAgent(direction = 1) {
@@ -333,12 +344,12 @@ export class App {
333
344
  this.router.pinned = options.model;
334
345
  }
335
346
  if (options.subtask) {
336
- const report = await this.agent.runSubagent(options.agent || "general", input.text, "comando", this.agent.agent, signal);
347
+ const report = await this.agent.runSubagent(options.agent || "ayudante", input.text, "comando", this.agent.agent, signal);
337
348
  this.agent.events.onText?.(report, 0);
338
349
  this.agent.events.onTextEnd?.(0);
339
350
  return;
340
351
  }
341
- if (options.agent && this.agents.some((agent) => agent.name === options.agent)) {
352
+ if (options.agent && this.agents.some((agent) => agent.name === agentName(options.agent))) {
342
353
  this.agent.setAgent(options.agent);
343
354
  }
344
355
  await this.agent.run(input, signal);
@@ -698,7 +709,7 @@ export class App {
698
709
  return {};
699
710
  }
700
711
  case "/agent": {
701
- const found = this.agents.find((agent) => agent.name === arg);
712
+ const found = this.agents.find((agent) => agent.name === agentName(arg));
702
713
  if (!found) {
703
714
  ui.error(`No existe el agente «${arg}». Mira /agents`);
704
715
  }
@@ -858,6 +869,10 @@ export class App {
858
869
  }
859
870
  return {};
860
871
  }
872
+ case "/limites":
873
+ case "/limits":
874
+ ui.block(limitsReport(this.router));
875
+ return {};
861
876
  case "/usage": {
862
877
  const usage = this.agent.session.usage;
863
878
  ui.info(`Tokens en esta sesión: ${usage.prompt} de entrada y ${usage.completion} de salida (todo gratis). Última petición: ~${this.agent.lastTokens} tokens con ${this.agent.lastSlot || "—"}.`);
@@ -913,6 +928,8 @@ export class App {
913
928
  }
914
929
  else {
915
930
  ui.info(result.message);
931
+ this.newVersion = null;
932
+ this.updateInstalled ||= result.status === "updated";
916
933
  }
917
934
  return {};
918
935
  }
@@ -941,7 +958,8 @@ export class App {
941
958
  const task = arg ? `\n\nTarea: ${arg}` : "";
942
959
  return { run: { input: { text: `Usa la skill «${skill.name}» para esto.${task}\n\n${skillContent(skill)}`, display: text.trim() }, options: {} } };
943
960
  }
944
- const agent = this.primaryAgents().find((item) => item.name === name);
961
+ // /programar, /planear y los tuyos (también /build y /plan, como antes)
962
+ const agent = this.primaryAgents().find((item) => item.name === agentName(name));
945
963
  if (agent) {
946
964
  this.agent.setAgent(agent.name);
947
965
  ui.info(`Agente ${agent.name}: ${agent.description}`);
@@ -979,13 +997,18 @@ export class App {
979
997
  // y guarda la salida para que el agente la vea con tu siguiente mensaje
980
998
  runShell(command, onOutput, signal) {
981
999
  return new Promise((resolve) => {
982
- let shell = process.env.SHELL || "bash";
983
- let args = ["-lc", command];
984
- if (process.platform === "win32") {
985
- shell = "cmd.exe";
986
- args = ["/c", command];
1000
+ // Tu shell de siempre; en Windows, la misma que usa el agente (el bash de Git o PowerShell)
1001
+ let shell = { file: process.env.SHELL || "bash", args: ["-lc", command], env: {} };
1002
+ if (process.platform === "win32" || process.env.VIPCODE_SHELL) {
1003
+ const found = commandShell();
1004
+ shell = { file: found.file, args: found.args(command), env: found.env };
987
1005
  }
988
- const child = spawn(shell, args, { cwd: this.root, stdio: ["ignore", "pipe", "pipe"], env: { ...process.env, GIT_PAGER: "cat", PAGER: "cat" } });
1006
+ const child = spawn(shell.file, shell.args, {
1007
+ cwd: this.root,
1008
+ stdio: ["ignore", "pipe", "pipe"],
1009
+ env: { ...process.env, ...shell.env, GIT_PAGER: "cat", PAGER: "cat" },
1010
+ windowsHide: true,
1011
+ });
989
1012
  let output = "";
990
1013
  const add = (data) => {
991
1014
  const text = data.toString();
@@ -994,8 +1017,8 @@ export class App {
994
1017
  };
995
1018
  child.stdout.on("data", add);
996
1019
  child.stderr.on("data", add);
997
- const timer = setTimeout(() => child.kill("SIGTERM"), this.config.bashTimeoutMs);
998
- const stop = () => child.kill("SIGTERM");
1020
+ const stop = () => killTree(child);
1021
+ const timer = setTimeout(stop, this.config.bashTimeoutMs);
999
1022
  signal?.addEventListener("abort", stop, { once: true });
1000
1023
  let done = false;
1001
1024
  const finish = (code) => {
package/dist/catalog.js CHANGED
@@ -97,6 +97,7 @@ export const CATALOG = [
97
97
  discover: "openai",
98
98
  pruneMissing: true,
99
99
  limitScope: "model",
100
+ freeLimits: { perDay: 14400 },
100
101
  defaultContext: 60000,
101
102
  contextCap: 60000,
102
103
  models: [m("gpt-oss-120b", 60000), m("qwen-3.8-27b", 60000, V)],
@@ -115,6 +116,7 @@ export const CATALOG = [
115
116
  freeOnly: true,
116
117
  pruneMissing: true,
117
118
  limitScope: "provider",
119
+ freeLimits: { perDay: 50 },
118
120
  defaultContext: 128000,
119
121
  models: [
120
122
  m("nvidia/nemotron-3-ultra-550b-a55b:free", 1000000),
@@ -144,6 +146,8 @@ export const CATALOG = [
144
146
  discover: "openai",
145
147
  pruneMissing: true,
146
148
  limitScope: "model",
149
+ freeLimits: { perDay: 1000 },
150
+ rateHeaders: { requests: "day", tokens: "minute" },
147
151
  defaultContext: 7000,
148
152
  // El plan gratis de Groq limita los tokens por minuto, así que solo vale para conversaciones cortas
149
153
  contextCap: 11000,
@@ -309,6 +313,7 @@ export const CATALOG = [
309
313
  signup: "https://modelscope.cn/my/myaccesstoken",
310
314
  freeInfo: "2.000 llamadas gratis al día (hay que vincular una cuenta de Alibaba Cloud).",
311
315
  limitScope: "provider",
316
+ freeLimits: { perDay: 2000 },
312
317
  models: [
313
318
  m("Qwen/Qwen3-Coder-30B-A3B-Instruct", 262144),
314
319
  m("Qwen/Qwen3-235B-A22B-Instruct-2507", 262144),
@@ -371,6 +376,7 @@ export const CATALOG = [
371
376
  freeOnly: true,
372
377
  pruneMissing: true,
373
378
  limitScope: "provider",
379
+ freeLimits: { perHour: 200, keyless: true },
374
380
  defaultContext: 128000,
375
381
  // Primero modelos concretos y buenos con herramientas; kilo-auto/free elige uno al azar (a veces flojo)
376
382
  models: [
@@ -422,6 +428,7 @@ export const CATALOG = [
422
428
  freeOnly: true,
423
429
  pruneMissing: true,
424
430
  limitScope: "provider",
431
+ freeLimits: { perHour: 60, keyless: true },
425
432
  defaultContext: 128000,
426
433
  models: [
427
434
  m("minimax-m2.7", 180000),