vipcode 0.2.3 → 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 +5 -3
- package/README.md +37 -31
- package/dist/agent.js +6 -6
- package/dist/agents.js +17 -8
- package/dist/app.js +29 -16
- package/dist/catalog.js +7 -0
- package/dist/commands.js +10 -19
- package/dist/images.js +30 -15
- package/dist/index.js +11 -4
- package/dist/limits.js +160 -0
- package/dist/login.js +4 -2
- package/dist/lsp.js +14 -7
- package/dist/paths.js +8 -0
- package/dist/permissions.js +14 -4
- package/dist/prompt.js +17 -1
- package/dist/router.js +139 -2
- package/dist/shell.js +107 -0
- package/dist/tools.js +38 -27
- package/dist/trust.js +5 -2
- package/dist/tui/app.js +11 -1
- package/dist/tui/dialogs.js +1 -1
- package/dist/ui.js +3 -3
- package/dist/update.js +4 -6
- package/package.json +3 -2
package/README.en.md
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/vipcode) [](https://github.com/PabloVip/vipcode/actions/workflows/ci.yml) [](LICENSE) · [Español](README.md)
|
|
4
4
|
|
|
5
|
-
A coding agent for your terminal (command `vipcode`)
|
|
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
|
|
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 `
|
|
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
|
[](https://www.npmjs.com/package/vipcode) [](https://github.com/PabloVip/vipcode/actions/workflows/ci.yml) [](LICENSE) · [English](README.en.md)
|
|
4
4
|
|
|
5
|
-
Agente de programación para la terminal (comando `vipcode`)
|
|
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
|
-
|
|
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
|
|
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.
|
|
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
|
|
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)
|
|
@@ -124,13 +126,13 @@ Después cierra vipcode y vuelve a abrirlo. Además, una vez al día vipcode mir
|
|
|
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 (`
|
|
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>`, `/
|
|
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
|
-
- **
|
|
171
|
-
- **
|
|
172
|
-
- **
|
|
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": { "
|
|
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
|
|
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
|
|
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:
|
|
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),
|
|
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
|
|
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,
|
|
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 ===
|
|
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 === "
|
|
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: "
|
|
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: "
|
|
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: "
|
|
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: "
|
|
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
|
-
|
|
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(
|
|
155
|
-
agents.set(
|
|
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: "
|
|
34
|
-
{ name: "
|
|
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)" },
|
|
@@ -175,7 +178,7 @@ export class App {
|
|
|
175
178
|
snapshots: this.snapshots,
|
|
176
179
|
skills: this.skills,
|
|
177
180
|
ask: (request, agent) => this.ask(request, agent),
|
|
178
|
-
}, options.session || newSession(root), options.agentName || options.session?.agent ||
|
|
181
|
+
}, options.session || newSession(root), options.agentName || options.session?.agent || MAIN_AGENT);
|
|
179
182
|
}
|
|
180
183
|
ask(request, agent) {
|
|
181
184
|
const permission = permissionsFor(this.config.permission, agent.permission);
|
|
@@ -341,12 +344,12 @@ export class App {
|
|
|
341
344
|
this.router.pinned = options.model;
|
|
342
345
|
}
|
|
343
346
|
if (options.subtask) {
|
|
344
|
-
const report = await this.agent.runSubagent(options.agent || "
|
|
347
|
+
const report = await this.agent.runSubagent(options.agent || "ayudante", input.text, "comando", this.agent.agent, signal);
|
|
345
348
|
this.agent.events.onText?.(report, 0);
|
|
346
349
|
this.agent.events.onTextEnd?.(0);
|
|
347
350
|
return;
|
|
348
351
|
}
|
|
349
|
-
if (options.agent && this.agents.some((agent) => agent.name === options.agent)) {
|
|
352
|
+
if (options.agent && this.agents.some((agent) => agent.name === agentName(options.agent))) {
|
|
350
353
|
this.agent.setAgent(options.agent);
|
|
351
354
|
}
|
|
352
355
|
await this.agent.run(input, signal);
|
|
@@ -706,7 +709,7 @@ export class App {
|
|
|
706
709
|
return {};
|
|
707
710
|
}
|
|
708
711
|
case "/agent": {
|
|
709
|
-
const found = this.agents.find((agent) => agent.name === arg);
|
|
712
|
+
const found = this.agents.find((agent) => agent.name === agentName(arg));
|
|
710
713
|
if (!found) {
|
|
711
714
|
ui.error(`No existe el agente «${arg}». Mira /agents`);
|
|
712
715
|
}
|
|
@@ -866,6 +869,10 @@ export class App {
|
|
|
866
869
|
}
|
|
867
870
|
return {};
|
|
868
871
|
}
|
|
872
|
+
case "/limites":
|
|
873
|
+
case "/limits":
|
|
874
|
+
ui.block(limitsReport(this.router));
|
|
875
|
+
return {};
|
|
869
876
|
case "/usage": {
|
|
870
877
|
const usage = this.agent.session.usage;
|
|
871
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 || "—"}.`);
|
|
@@ -951,7 +958,8 @@ export class App {
|
|
|
951
958
|
const task = arg ? `\n\nTarea: ${arg}` : "";
|
|
952
959
|
return { run: { input: { text: `Usa la skill «${skill.name}» para esto.${task}\n\n${skillContent(skill)}`, display: text.trim() }, options: {} } };
|
|
953
960
|
}
|
|
954
|
-
|
|
961
|
+
// /programar, /planear y los tuyos (también /build y /plan, como antes)
|
|
962
|
+
const agent = this.primaryAgents().find((item) => item.name === agentName(name));
|
|
955
963
|
if (agent) {
|
|
956
964
|
this.agent.setAgent(agent.name);
|
|
957
965
|
ui.info(`Agente ${agent.name}: ${agent.description}`);
|
|
@@ -989,13 +997,18 @@ export class App {
|
|
|
989
997
|
// y guarda la salida para que el agente la vea con tu siguiente mensaje
|
|
990
998
|
runShell(command, onOutput, signal) {
|
|
991
999
|
return new Promise((resolve) => {
|
|
992
|
-
|
|
993
|
-
let
|
|
994
|
-
if (process.platform === "win32") {
|
|
995
|
-
|
|
996
|
-
|
|
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 };
|
|
997
1005
|
}
|
|
998
|
-
const child = spawn(shell, args, {
|
|
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
|
+
});
|
|
999
1012
|
let output = "";
|
|
1000
1013
|
const add = (data) => {
|
|
1001
1014
|
const text = data.toString();
|
|
@@ -1004,8 +1017,8 @@ export class App {
|
|
|
1004
1017
|
};
|
|
1005
1018
|
child.stdout.on("data", add);
|
|
1006
1019
|
child.stderr.on("data", add);
|
|
1007
|
-
const
|
|
1008
|
-
const
|
|
1020
|
+
const stop = () => killTree(child);
|
|
1021
|
+
const timer = setTimeout(stop, this.config.bashTimeoutMs);
|
|
1009
1022
|
signal?.addEventListener("abort", stop, { once: true });
|
|
1010
1023
|
let done = false;
|
|
1011
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),
|
package/dist/commands.js
CHANGED
|
@@ -2,6 +2,7 @@ import { spawn } from "node:child_process";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { readMarkdownDir } from "./frontmatter.js";
|
|
4
4
|
import { GLOBAL_COMMANDS_DIR } from "./paths.js";
|
|
5
|
+
import { commandShell, killTree, splitArgs } from "./shell.js";
|
|
5
6
|
import { truncate } from "./tools.js";
|
|
6
7
|
import { isProjectFile, projectTrust } from "./trust.js";
|
|
7
8
|
const INIT_TEMPLATE = `Analiza este proyecto y crea (o mejora, si ya existe) el fichero AGENTS.md en la raíz, con las instrucciones que necesitaría otro agente de programación para trabajar aquí sin perder tiempo.
|
|
@@ -23,7 +24,7 @@ Para cada problema di el fichero y la línea, por qué es un problema y cómo lo
|
|
|
23
24
|
$ARGUMENTS`;
|
|
24
25
|
const BUILTIN = [
|
|
25
26
|
{ name: "init", description: "Crea o mejora AGENTS.md con las instrucciones del proyecto", template: INIT_TEMPLATE, subtask: false, builtIn: true },
|
|
26
|
-
{ name: "review", description: "Revisa los cambios sin confirmar (no modifica nada)", template: REVIEW_TEMPLATE, agent: "
|
|
27
|
+
{ name: "review", description: "Revisa los cambios sin confirmar (no modifica nada)", template: REVIEW_TEMPLATE, agent: "planear", subtask: false, builtIn: true },
|
|
27
28
|
];
|
|
28
29
|
// Comandos integrados + ~/.vipcode/commands + .vipcode/commands y .opencode/command(s) del proyecto + "commands" del config
|
|
29
30
|
export function loadCommands(root, config, trusted = projectTrust(root).trusted) {
|
|
@@ -67,27 +68,17 @@ export function loadCommands(root, config, trusted = projectTrust(root).trusted)
|
|
|
67
68
|
}
|
|
68
69
|
return [...commands.values()];
|
|
69
70
|
}
|
|
70
|
-
// Separa los argumentos respetando las comillas: a "b c" d → [a, b c, d]
|
|
71
|
-
export function splitArgs(text) {
|
|
72
|
-
const result = [];
|
|
73
|
-
const pattern = /"([^"]*)"|'([^']*)'|(\S+)/g;
|
|
74
|
-
let match;
|
|
75
|
-
while ((match = pattern.exec(text)) !== null) {
|
|
76
|
-
result.push(match[1] ?? match[2] ?? match[3]);
|
|
77
|
-
}
|
|
78
|
-
return result;
|
|
79
|
-
}
|
|
80
71
|
function runShell(command, cwd) {
|
|
81
72
|
return new Promise((resolve) => {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
73
|
+
const shell = commandShell();
|
|
74
|
+
const child = spawn(shell.file, shell.args(command), {
|
|
75
|
+
cwd,
|
|
76
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
77
|
+
env: { ...process.env, ...shell.env, GIT_PAGER: "cat", PAGER: "cat" },
|
|
78
|
+
windowsHide: true,
|
|
79
|
+
});
|
|
89
80
|
let output = "";
|
|
90
|
-
const timer = setTimeout(() => child
|
|
81
|
+
const timer = setTimeout(() => killTree(child), 30000);
|
|
91
82
|
child.stdout.on("data", (d) => (output += d.toString()));
|
|
92
83
|
child.stderr.on("data", (d) => (output += d.toString()));
|
|
93
84
|
child.on("error", (err) => {
|