@ketchao/nextup 0.0.0-stage → 0.1.0
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.md +153 -2
- package/dist/cli.js +6509 -0
- package/package.json +27 -4
package/README.md
CHANGED
|
@@ -1,3 +1,154 @@
|
|
|
1
|
-
#
|
|
1
|
+
# nextup (nombre provisional)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Menú de "siguientes pasos" para agentes de código. MVP: **Claude Code** y **Codex** (mismo protocolo de hooks).
|
|
4
|
+
|
|
5
|
+
> El nombre es un placeholder. Ojo: la captura de referencia es de un producto llamado "Then", así que conviene no usar ese nombre.
|
|
6
|
+
|
|
7
|
+
Al terminar cada turno sustancial, muestra hasta 4 opciones contextuales (con indicador de consumo). El usuario responde escribiendo el número en la caja normal de Claude Code.
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
◆ ¿Cómo seguimos? Escribe un número · +1 2 = varias
|
|
11
|
+
consumo ▾
|
|
12
|
+
1 Hacer commit ★ sugerida ■□□ bajo
|
|
13
|
+
2 Revisar mis cambios ■■□ medio
|
|
14
|
+
3 Escribir pruebas ■■■ alto
|
|
15
|
+
4 Dejarlo así □□□ nada
|
|
16
|
+
5 Otra cosa (libre)
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Probarlo (5 minutos)
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install
|
|
23
|
+
npm test # 76 pruebas
|
|
24
|
+
npm run preview # ver el menú sin Claude (itera el diseño aquí)
|
|
25
|
+
npm run preview -- --scenario failed --width 60
|
|
26
|
+
npm run build
|
|
27
|
+
|
|
28
|
+
# en un repo de prueba, desde el paquete publicado:
|
|
29
|
+
npm install -g @ketchao/nextup
|
|
30
|
+
nextup init --agent codex
|
|
31
|
+
claude # pide un cambio pequeño y mira qué pasa al terminar
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`init --user` instala los hooks globalmente; `init --remove` los quita. Hace un backup `settings.json.nextup.bak` la primera vez.
|
|
35
|
+
|
|
36
|
+
Probar un hook sin Claude:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
cat fixtures/stop.json | NEXTUP_ALWAYS=1 node dist/cli.js hook stop
|
|
40
|
+
cat fixtures/prompt-submit.json | node dist/cli.js hook prompt-submit
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Probar con Codex (experimental)
|
|
44
|
+
|
|
45
|
+
Los comandos `hook stop` y `hook prompt-submit` leen y escriben el mismo formato JSON que usa Codex, así que no hay adaptador nuevo: solo cambia dónde se registran.
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
node dist/cli.js init --agent codex # escribe .codex/hooks.json (o --user para ~/.codex/hooks.json)
|
|
49
|
+
codex # luego escribe /hooks y aprueba (trust) los 2 hooks de nextup
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Notas:
|
|
53
|
+
- Codex ignora los hooks nuevos o modificados hasta que los revisas con `/hooks`.
|
|
54
|
+
- En Windows nativo (Codex CLI 0.166.0, cmd) los hooks **sí se ejecutan**. El `systemMessage` aparece como "Hook · ..." con los colores ANSI y la alineación intactos.
|
|
55
|
+
- El lector de transcript (`transcript.ts`) es *best effort* y entiende los formatos de Claude Code y de Codex. Solo lee lo ocurrido en el turno actual (el hook `UserPromptSubmit` anota dónde empieza). Si algo no cuadra, activa `debug` y revisa `debug.jsonl`: la entrada `stop-signals` muestra los comandos y códigos de salida detectados, y un resumen de las líneas leídas.
|
|
56
|
+
- Codex ejecuta los hooks desde un servidor en segundo plano que **no hereda tus variables de entorno**: usa `~/.nextup/config.json` (ver abajo) o abre `codex --no-daemon`.
|
|
57
|
+
|
|
58
|
+
## Configuración
|
|
59
|
+
|
|
60
|
+
Variables de entorno **o** el archivo `~/.nextup/config.json` (las variables mandan sobre el archivo):
|
|
61
|
+
|
|
62
|
+
```json
|
|
63
|
+
{
|
|
64
|
+
"language": "es",
|
|
65
|
+
"suggestions": 4,
|
|
66
|
+
"showCustomOption": true,
|
|
67
|
+
"showTokenEstimation": true,
|
|
68
|
+
"autoSuggest": true,
|
|
69
|
+
"backgroundCheck": true,
|
|
70
|
+
"consumption": "measured",
|
|
71
|
+
"providers": { "claude": true, "codex": true, "opencode": true },
|
|
72
|
+
"debug": false,
|
|
73
|
+
"theme": "default"
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`suggestions` es el tope de filas, contando "Dejarlo así" (1–4). `showCustomOption` es la fila "Otra cosa". `showTokenEstimation` es la columna de consumo. `autoSuggest: false` deja de mostrar menús nuevos; un menú que ya está en pantalla sigue aceptando el número. `backgroundCheck` corre `npm test` (y `npm run lint` si existe) antes de armar el menú, con un tope de unos segundos: si 3 pruebas fallan, la fila dice «3 pruebas fallan, arreglarlas». `false` lo apaga. `consumption` es `measured` (el tiempo real: `1.5s`, o `—` si esa acción todavía no se midió) o `estimated` (bajo, medio, alto, nada). `providers` apaga un agente: Codex se reconoce por la ruta `.codex` del transcript. OpenCode todavía no tiene adaptador, así que su flag se guarda y no corta nada. `language` es el idioma cuando el prompt no alcanza para saberlo (un número, un «ok» o una mezcla). Si el prompt es una frase en inglés, el menú sale en inglés; si es en español, en español. Siguen valiendo `lang`, `mode`, `color`, `width`, `always` y `disabled`. El entorno manda sobre el archivo.
|
|
78
|
+
|
|
79
|
+
Para verlo o cambiarlo sin editar el JSON:
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
nextup config
|
|
83
|
+
nextup config set autoSuggest false
|
|
84
|
+
nextup config set providers.codex false
|
|
85
|
+
nextup config set showCustomOption true
|
|
86
|
+
nextup config set suggestions 3
|
|
87
|
+
nextup config set theme blue
|
|
88
|
+
nextup config set language es
|
|
89
|
+
nextup config set consumption estimated
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Los interruptores aceptan `true`/`false` (también `on`/`off` y `si`/`no`). En la caja del agente, sin salir de Codex y sin tener `nextup` en el PATH:
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
nextup theme blue
|
|
96
|
+
nextup config set consumption estimated
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
El cambio se guarda y el agente no lo ejecuta. Se ve en el menú siguiente. `color` y `default` pintan cada fila según el consumo. `blue`, `green`, `amber`, `pink`, `teal` y `violet` pintan todo el menú de un color. `mono` lo deja sin color. También valen `azul`, `ambar`, `rosa` y `cian`. `nextup init` crea el archivo con todo activo si todavía no existe, y no pisa el que ya tengas.
|
|
100
|
+
|
|
101
|
+
Con `"debug": true`, cada hook guarda lo que recibió y devolvió en `~/.nextup/state/debug.jsonl` (contiene rutas y texto de tu sesión; es solo local). Aparte, cada menú deja una línea en `~/.nextup/state/choices.jsonl`: si elegiste un número, si lo dejaste así, o si escribiste otra cosa. No guarda la frase. Si una fila sale tres veces en turnos parecidos y no la eliges, baja.
|
|
102
|
+
|
|
103
|
+
## Cómo funciona
|
|
104
|
+
|
|
105
|
+
1. **Hook `Stop`**: lee el payload, junta señales baratas (cambios en `git status`, comandos `Bash` del turno en el transcript, mensaje final), genera el menú y lo muestra con `systemMessage`. Guarda el menú pendiente en `~/.nextup/state/<session_id>.json`.
|
|
106
|
+
2. El usuario escribe el número de la fila (`2`) o varios a la vez (`+2 4`, `1 3`, `1 y 3`). El `+` es opcional.
|
|
107
|
+
3. **Hook `UserPromptSubmit`**: si hay menú pendiente y la respuesta es una selección, inyecta las instrucciones como `additionalContext` (el hook no puede reescribir el prompt; Claude recibe "3" + el contexto que lo explica). "Dejarlo así" y "Otra cosa" bloquean el prompt y no gastan tokens. Cualquier otro texto descarta el menú y pasa intacto.
|
|
108
|
+
|
|
109
|
+
Decisiones de diseño (vienen de la crítica a la maqueta):
|
|
110
|
+
- **No sugiere lo que ya pasó**: si las pruebas ya pasaron, no ofrece correrlas otra vez.
|
|
111
|
+
- **No repite lo que acabas de elegir** (solo para el menú siguiente) **ni ofrece correr pruebas si el repo no tiene ninguna configurada**: en su lugar sugiere el commit.
|
|
112
|
+
- **0 a 4 opciones, y a veces ninguna**: no hay menú si no hubo cambios, o si el agente terminó con una pregunta.
|
|
113
|
+
- **La sugerida nunca es saliente**: el esquema (`SuggestionSchema`) rechaza `recommended` + `outward` (push, deploy...).
|
|
114
|
+
- **El menú por defecto pinta la fila**: verde, ámbar, rojo o gris según el consumo, y "Otra cosa" en azul. El número va en una pastilla más clara. `blue`, `green`, `amber`, `pink`, `teal` y `violet` pintan todo el menú de un solo color. `mono` y `color: false` lo dejan en texto plano. El `☐` no se marca: se elige con el número. En la caja del agente, sin barra: `nextup theme blue` (también `verde`, `azul`, `ambar`, `rosa`, `cian`). La barra es de Codex y rechaza `/nextup`.
|
|
115
|
+
|
|
116
|
+
## Spike: lo que hay que verificar primero
|
|
117
|
+
|
|
118
|
+
Estas cuatro cosas **no están confirmadas**; todo el diseño depende de ellas:
|
|
119
|
+
|
|
120
|
+
| # | Pregunta | Cómo probarla | Si falla |
|
|
121
|
+
|---|----------|---------------|----------|
|
|
122
|
+
| 1 | ¿Se ve el `systemMessage` de un Stop sin bloqueo? | Correr `claude`, pedir un cambio, mirar al terminar | Usar `NEXTUP_MODE=block` |
|
|
123
|
+
| 2 | ¿Respeta ANSI y saltos de línea? | Comparar con `NEXTUP_COLOR=0` | Dejar color apagado por defecto |
|
|
124
|
+
| 3 | ¿Claude actúa bien con `"3"` + contexto inyectado? | Elegir opciones varias veces | Reforzar el texto de `additionalContext` |
|
|
125
|
+
| 4 | ¿El ancho detectado es correcto? | Redimensionar la terminal; probar `NEXTUP_WIDTH` | Ancho fijo o más compacto |
|
|
126
|
+
|
|
127
|
+
Además: mide la latencia real del turno (el hook arranca en ~60 ms; las reglas son locales, así que hoy no hay llamada a un modelo) y prueba también en la extensión de VS Code/Cursor, cuya interfaz puede mostrar los hooks distinto a la terminal.
|
|
128
|
+
|
|
129
|
+
## Límites conocidos
|
|
130
|
+
|
|
131
|
+
- El menú mira solo los archivos cuyo diff cambió en este turno (baseline guardado en `UserPromptSubmit`). Si esa marca no está, cae al `git status` completo.
|
|
132
|
+
- El transcript JSONL no es un contrato público: `transcript.ts` es *best effort* y degrada a "sin señales".
|
|
133
|
+
- Detección de pruebas: usa los comandos y códigos de salida del transcript (formato real de Codex verificado con `fixtures/codex-rollout-sample.jsonl`). Si el fallo parece del entorno (EPERM, "Access is denied"...), se trata como *bloqueado*, no como "pruebas rotas": la sugerida pasa a ser revisar el diff. Sin código de salida, cae a una heurística sobre el mensaje final.
|
|
134
|
+
- Sin detección de ejecuciones headless (`claude -p`); si más adelante llamas a `claude -p` desde el hook, exporta `NEXTUP_INNER=1` en esa llamada para evitar recursión.
|
|
135
|
+
- Claude y Codex comparten el protocolo de hooks (`systemMessage` / `additionalContext`). OpenCode necesita un presentador propio (añadir al prompt).
|
|
136
|
+
|
|
137
|
+
## Siguientes pasos
|
|
138
|
+
|
|
139
|
+
1. Pasar el spike (tabla de arriba) y usarlo una semana propia; registrar qué opciones se eligen.
|
|
140
|
+
2. `llm.ts`: 1 o 2 sugerencias específicas con un modelo pequeño (API key o `claude -p`), manteniendo las reglas deterministas como base.
|
|
141
|
+
3. Consumo medido (duración real de la última corrida de pruebas) en vez de fijo por tipo de acción.
|
|
142
|
+
4. Presentador de OpenCode (añadir al prompt). Claude y Codex ya comparten `src/adapters/shared/`.
|
|
143
|
+
|
|
144
|
+
## Estructura
|
|
145
|
+
|
|
146
|
+
```
|
|
147
|
+
src/core/ independiente del agente: tipos (zod), reglas, render, parser, estado
|
|
148
|
+
src/adapters/shared/ protocolo de hooks: payloads, transcript, contexto, Stop y UserPromptSubmit
|
|
149
|
+
src/adapters/claude/ instalación en .claude/settings.json
|
|
150
|
+
src/adapters/codex/ instalación en .codex/hooks.json (timeoutSec)
|
|
151
|
+
src/cli/ preview, init, config, entrada de los hooks
|
|
152
|
+
test/ parse, suggest, render, hooks (con repo git temporal), adaptadores
|
|
153
|
+
fixtures/ payloads de ejemplo
|
|
154
|
+
```
|