xonecode 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 +167 -0
- package/dist/agent/authEnDisco.js +56 -0
- package/dist/agent/authEnDisco.js.map +1 -0
- package/dist/agent/configEnDisco.js +109 -0
- package/dist/agent/configEnDisco.js.map +1 -0
- package/dist/agent/crearProyecto.js +34 -0
- package/dist/agent/crearProyecto.js.map +1 -0
- package/dist/agent/entorno.js +124 -0
- package/dist/agent/entorno.js.map +1 -0
- package/dist/agent/guionizado.js +53 -0
- package/dist/agent/guionizado.js.map +1 -0
- package/dist/agent/instantanea.js +129 -0
- package/dist/agent/instantanea.js.map +1 -0
- package/dist/agent/interrupts.js +83 -0
- package/dist/agent/interrupts.js.map +1 -0
- package/dist/agent/mensajes.js +24 -0
- package/dist/agent/mensajes.js.map +1 -0
- package/dist/agent/modelos.js +42 -0
- package/dist/agent/modelos.js.map +1 -0
- package/dist/agent/normalizar.js +20 -0
- package/dist/agent/normalizar.js.map +1 -0
- package/dist/agent/perfiles.js +103 -0
- package/dist/agent/perfiles.js.map +1 -0
- package/dist/agent/proyecto.js +107 -0
- package/dist/agent/proyecto.js.map +1 -0
- package/dist/agent/puente.js +142 -0
- package/dist/agent/puente.js.map +1 -0
- package/dist/agent/resumenDeTool.js +48 -0
- package/dist/agent/resumenDeTool.js.map +1 -0
- package/dist/agent/skills.js +65 -0
- package/dist/agent/skills.js.map +1 -0
- package/dist/agent/textoDeTool.js +113 -0
- package/dist/agent/textoDeTool.js.map +1 -0
- package/dist/agent/turnoReal.js +173 -0
- package/dist/agent/turnoReal.js.map +1 -0
- package/dist/agent/verificador.js +65 -0
- package/dist/agent/verificador.js.map +1 -0
- package/dist/agent/xoneAgent.js +106 -0
- package/dist/agent/xoneAgent.js.map +1 -0
- package/dist/bin.js +9 -0
- package/dist/bin.js.map +1 -0
- package/dist/cli/aprobar.js +82 -0
- package/dist/cli/aprobar.js.map +1 -0
- package/dist/cli/config.js +133 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/consola.js +346 -0
- package/dist/cli/consola.js.map +1 -0
- package/dist/cli/describe.js +53 -0
- package/dist/cli/describe.js.map +1 -0
- package/dist/cli/doctor.js +45 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/main.js +520 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/markdown.js +90 -0
- package/dist/cli/markdown.js.map +1 -0
- package/dist/cli/run.js +164 -0
- package/dist/cli/run.js.map +1 -0
- package/dist/cli/spinner.js +89 -0
- package/dist/cli/spinner.js.map +1 -0
- package/dist/cli/stdio.js +193 -0
- package/dist/cli/stdio.js.map +1 -0
- package/dist/cli/tema.js +40 -0
- package/dist/cli/tema.js.map +1 -0
- package/dist/cli/verify.js +62 -0
- package/dist/cli/verify.js.map +1 -0
- package/dist/core/bitacora.js +30 -0
- package/dist/core/bitacora.js.map +1 -0
- package/dist/core/config.js +236 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/contextos.js +56 -0
- package/dist/core/contextos.js.map +1 -0
- package/dist/core/deps.js +51 -0
- package/dist/core/deps.js.map +1 -0
- package/dist/core/diff.js +79 -0
- package/dist/core/diff.js.map +1 -0
- package/dist/core/esqueleto.js +366 -0
- package/dist/core/esqueleto.js.map +1 -0
- package/dist/core/events.js +2 -0
- package/dist/core/events.js.map +1 -0
- package/dist/core/modelos.js +85 -0
- package/dist/core/modelos.js.map +1 -0
- package/dist/core/notify.js +106 -0
- package/dist/core/notify.js.map +1 -0
- package/dist/core/ports.js +114 -0
- package/dist/core/ports.js.map +1 -0
- package/dist/core/turno.js +127 -0
- package/dist/core/turno.js.map +1 -0
- package/dist/vendor/hitl.js +103 -0
- package/dist/vendor/hitl.js.map +1 -0
- package/dist/vendor/skillLoaders/catalog.js +74 -0
- package/dist/vendor/skillLoaders/catalog.js.map +1 -0
- package/dist/vendor/tokenTracking.js +58 -0
- package/dist/vendor/tokenTracking.js.map +1 -0
- package/package.json +41 -0
- package/skills/xone-debugging/SKILL.md +52 -0
- package/skills/xone-debugging/references/faq.md +561 -0
- package/skills/xone-debugging/references/troubleshooting-y-glosario.md +429 -0
- package/skills/xone-development/SKILL.md +105 -0
- package/skills/xone-development/references/anti-patrones.md +94 -0
- package/skills/xone-development/references/css/atributos-por-categoria.md +509 -0
- package/skills/xone-development/references/css/buenas-practicas-y-parser.md +419 -0
- package/skills/xone-development/references/css/dinamicos-cascada-y-componentes.md +550 -0
- package/skills/xone-development/references/css/patrones-material-y-temas.md +1140 -0
- package/skills/xone-development/references/css/propiedades-y-herencia.md +885 -0
- package/skills/xone-development/references/css/selectores-unidades-colores.md +840 -0
- package/skills/xone-development/references/datos/appdata-referencia-ampliada.md +457 -0
- package/skills/xone-development/references/datos/appdata.md +611 -0
- package/skills/xone-development/references/datos/http-sqlmanager-y-crypto.md +720 -0
- package/skills/xone-development/references/datos/http.md +366 -0
- package/skills/xone-development/references/datos/oauth2-y-replica.md +156 -0
- package/skills/xone-development/references/device/biometria-imagedrawing-y-otros.md +544 -0
- package/skills/xone-development/references/device/objetos-de-dispositivo.md +583 -0
- package/skills/xone-development/references/device/systemsettings-referencia-ampliada.md +396 -0
- package/skills/xone-development/references/device/systemsettings-y-permisos.md +342 -0
- package/skills/xone-development/references/fundamentos/conceptos-clave.md +695 -0
- package/skills/xone-development/references/fundamentos/configuracion-app-xml-ini-mappings.md +668 -0
- package/skills/xone-development/references/fundamentos/errores-comunes.md +312 -0
- package/skills/xone-development/references/fundamentos/navegacion-convenciones-y-primer-proyecto.md +576 -0
- package/skills/xone-development/references/fundamentos/plataforma-y-anatomia-de-proyecto.md +387 -0
- package/skills/xone-development/references/indice-completo.md +77 -0
- package/skills/xone-development/references/javascript/coleccion-error-y-usuario.md +260 -0
- package/skills/xone-development/references/javascript/debugging-y-best-practices.md +245 -0
- package/skills/xone-development/references/javascript/metodos-de-los-controles.md +556 -0
- package/skills/xone-development/references/javascript/metodos-nativos-de-la-vista.md +114 -0
- package/skills/xone-development/references/javascript/motor-js-y-contexto-de-ejecucion.md +319 -0
- package/skills/xone-development/references/javascript/objeto-ai-llm-en-dispositivo.md +358 -0
- package/skills/xone-development/references/javascript/objetos-creables-a-m.md +527 -0
- package/skills/xone-development/references/javascript/objetos-creables-n-z.md +385 -0
- package/skills/xone-development/references/javascript/patrones-criticos-seguridad-y-rendimiento.md +595 -0
- package/skills/xone-development/references/javascript/patrones-de-navegacion-datos-y-codigo.md +751 -0
- package/skills/xone-development/references/javascript/patrones-de-ui-voz-integracion-y-seguridad.md +701 -0
- package/skills/xone-development/references/javascript/plantillas-y-funciones-utilitarias.md +647 -0
- package/skills/xone-development/references/javascript/self-y-dataobject.md +449 -0
- package/skills/xone-development/references/javascript/singletons-globales.md +361 -0
- package/skills/xone-development/references/javascript/ui-catalogo-de-metodos.md +464 -0
- package/skills/xone-development/references/javascript/ui-gps-camara-y-multimedia.md +506 -0
- package/skills/xone-development/references/javascript/ui-navegacion-mensajes-y-vista.md +422 -0
- package/skills/xone-development/references/resumen-js-datos-dispositivo.md +80 -0
- package/skills/xone-development/references/resumen-xml-y-css.md +74 -0
- package/skills/xone-development/references/tipos-de-prop.md +28 -0
- package/skills/xone-development/references/xml-ui/asfilter-visibilidad-eventos-y-macros.md +576 -0
- package/skills/xone-development/references/xml-ui/atributos-coll-group-frame.md +235 -0
- package/skills/xone-development/references/xml-ui/atributos-method-macro-script-event-app.md +244 -0
- package/skills/xone-development/references/xml-ui/atributos-prop.md +439 -0
- package/skills/xone-development/references/xml-ui/contents-y-macros.md +392 -0
- package/skills/xone-development/references/xml-ui/errores-comunes-xml.md +245 -0
- package/skills/xone-development/references/xml-ui/estructura-y-nodo-coll.md +326 -0
- package/skills/xone-development/references/xml-ui/eventos-ciclo-de-vida-e-interaccion.md +704 -0
- package/skills/xone-development/references/xml-ui/eventos-sistema-login-y-personalizados.md +944 -0
- package/skills/xone-development/references/xml-ui/layouts-herencia-y-buenas-practicas.md +618 -0
- package/skills/xone-development/references/xml-ui/mapas.md +685 -0
- package/skills/xone-development/references/xml-ui/mappings-y-colecciones-separadas.md +148 -0
- package/skills/xone-development/references/xml-ui/nodos-group-y-frame.md +666 -0
- package/skills/xone-development/references/xml-ui/patrones-de-pantalla.md +643 -0
- package/skills/xone-development/references/xml-ui/prop-atributos-y-condiciones.md +298 -0
- package/skills/xone-development/references/xml-ui/prop-tipos-basicos.md +493 -0
- package/skills/xone-development/references/xml-ui/prop-tipos-combos-y-controles.md +664 -0
- package/skills/xone-development/references/xml-ui/prop-tipos-listas-y-mapas.md +412 -0
- package/skills/xone-plan-builder/SKILL.md +183 -0
- package/skills/xone-plan-builder/agents/openai.yaml +5 -0
- package/skills/xone-plan-builder/references/TASKS-FORMAT.md +132 -0
- package/skills/xone-project-generator/SKILL.md +111 -0
- package/skills/xone-project-generator/references/canonical-sizes.md +292 -0
- package/skills/xone-project-generator/references/colecciones-base.md +16 -0
- package/skills/xone-project-generator/references/convenciones-de-nombres.md +16 -0
- package/skills/xone-project-generator/references/ejemplos-por-sector-y-prohibiciones.md +140 -0
- package/skills/xone-project-generator/references/fase-3-estilos-css.md +597 -0
- package/skills/xone-project-generator/references/fase-6-colecciones.md +762 -0
- package/skills/xone-project-generator/references/fase-7-asfilter-e-integraciones.md +142 -0
- package/skills/xone-project-generator/references/fase-7-entidades-y-estructura-de-pantalla.md +494 -0
- package/skills/xone-project-generator/references/fase-7-plantilla-consola.md +477 -0
- package/skills/xone-project-generator/references/fase-7-plantillas-de-pantalla.md +302 -0
- package/skills/xone-project-generator/references/fase-7-viewmodes-graficos-y-listas.md +681 -0
- package/skills/xone-project-generator/references/fase-7-viewmodes-mapa-y-calendario.md +479 -0
- package/skills/xone-project-generator/references/fases-0-2-analisis-y-modelo-de-datos.md +350 -0
- package/skills/xone-project-generator/references/fases-10-12-readmes-y-validacion.md +194 -0
- package/skills/xone-project-generator/references/fases-4-5-estructura-y-configuracion.md +587 -0
- package/skills/xone-project-generator/references/fases-8-9-eventos-y-javascript.md +861 -0
- package/skills/xone-project-generator/references/flujo-de-generacion.md +67 -0
- package/skills/xone-project-generator/references/plantillas-estandar.md +98 -0
- package/skills/xone-project-generator/references/tamanos-canonicos.md +49 -0
- package/skills/xone-review/SKILL.md +189 -0
- package/skills/xone-spec-builder/SKILL.md +235 -0
- package/skills/xone-spec-builder/agents/openai.yaml +5 -0
- package/skills/xone-spec-builder/references/ADR-FORMAT.md +55 -0
- package/skills/xone-spec-builder/references/CONTEXT-FORMAT.md +42 -0
- package/skills/xone-spec-builder/references/PLAN-FORMAT.md +120 -0
package/README.md
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# xonecode
|
|
2
|
+
|
|
3
|
+
Consola CLI y harness de agente para desarrollar aplicaciones **XOne**, sobre LangChain,
|
|
4
|
+
LangGraph y deepagents.
|
|
5
|
+
|
|
6
|
+
XOne es una plataforma propietaria de apps móviles nativas: se programa con XML (ficheros
|
|
7
|
+
`.xne`), JavaScript ES5 y un CSS propio. **No es desarrollo web** — no existe el DOM, ni
|
|
8
|
+
`async/await` en el runtime, ni ningún framework tipo React.
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
$ cd MiApp && xonecode
|
|
12
|
+
|
|
13
|
+
xonecode · MiApp (7 colls) · ollama/glm-5.3-flash:cloud · 0 tokens
|
|
14
|
+
13 comandos: /ayuda /config /describe /doctor /verify /modelo … /salir
|
|
15
|
+
|
|
16
|
+
─ MiApp (7 colls) · ollama/glm-5.3-flash:cloud · 0 tokens · /ayuda
|
|
17
|
+
❯ ¿qué colecciones tiene este proyecto?
|
|
18
|
+
🔧 task · ls · glob · read_file ×7
|
|
19
|
+
El proyecto tiene 9 colecciones repartidas en 7 ficheros .xne: …
|
|
20
|
+
⚠ el verificador no ha corrido en este turno
|
|
21
|
+
(9.0s)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Estado
|
|
25
|
+
|
|
26
|
+
**Funciona y es usable, pero no es un producto terminado.** Lo que hay:
|
|
27
|
+
|
|
28
|
+
| | |
|
|
29
|
+
|---|---|
|
|
30
|
+
| Consola interactiva | prompt, barra de estado, 13 comandos de barra, autocompletado con Tab |
|
|
31
|
+
| Un disparo | `xonecode run "…"` — pipeable, para tuberías y CI |
|
|
32
|
+
| Aprobación humana | el agente **para y pregunta** antes de escribir; sin un sí explícito, rechaza |
|
|
33
|
+
| Verificador real | `xone-simulator` sobre el proyecto, con `/verify` y `xonecode verify` |
|
|
34
|
+
| Multi-proveedor | Gemini, OpenAI, Anthropic y **Ollama local**, con modelo por papel |
|
|
35
|
+
| Diagnóstico sin coste | `describe`, `doctor` y `config` no gastan una llamada al modelo |
|
|
36
|
+
|
|
37
|
+
Lo que **todavía no hay**, y conviene saber antes de fiarse:
|
|
38
|
+
|
|
39
|
+
- **Nadie verifica lo que el agente escribe.** El verificador existe y funciona, pero no
|
|
40
|
+
corre dentro del turno: la consola te lo avisa en cada uno. Hay que lanzar `/verify`.
|
|
41
|
+
- **No hay lazo** de plan → ejecuta → verifica → juzga → repara, con presupuestos.
|
|
42
|
+
- **No usa los servidores MCP de XOne Studio**: el proyecto tiene que estar en disco.
|
|
43
|
+
- **No hay TUI con paneles**; la consola es stdio.
|
|
44
|
+
|
|
45
|
+
## Instalación
|
|
46
|
+
|
|
47
|
+
Requiere **Node ≥ 20** y, para verificar, [`xone-linter`](https://www.npmjs.com/package/xone-linter)
|
|
48
|
+
(que instala el binario `xone-simulator`).
|
|
49
|
+
|
|
50
|
+
```sh
|
|
51
|
+
git clone https://github.com/sleiva/xonecode && cd xonecode
|
|
52
|
+
npm install
|
|
53
|
+
npm run build
|
|
54
|
+
npm link # o: ln -sf "$PWD/dist/bin.js" ~/.local/bin/xonecode
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Comprueba que el entorno está listo, sin gastar nada:
|
|
58
|
+
|
|
59
|
+
```sh
|
|
60
|
+
cd /ruta/a/TuApp
|
|
61
|
+
xonecode doctor
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Configuración
|
|
65
|
+
|
|
66
|
+
Dos ficheros con dos ciclos de vida distintos, y **las claves nunca van en el proyecto**:
|
|
67
|
+
|
|
68
|
+
| Fichero | Qué lleva |
|
|
69
|
+
|---|---|
|
|
70
|
+
| `<proyecto>/.xonecode/config.json` | modelos y proveedores. **Rechaza claves de API.** |
|
|
71
|
+
| `~/.xonecode/config.json` | lo mismo, para todos los proyectos |
|
|
72
|
+
| `~/.xonecode/auth.json` | las credenciales, con modo **0600**. Se escribe con `/provider <nombre>` |
|
|
73
|
+
|
|
74
|
+
```json
|
|
75
|
+
{
|
|
76
|
+
"modelo": "ollama/glm-5.3-flash:cloud",
|
|
77
|
+
"modelos": { "afilado": "anthropic/claude-sonnet-4-5-20250929" }
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Precedencia, y cada valor recuerda de dónde vino (`xonecode config` lo dice):
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
--modelo-<papel> > --modelo > XONECODE_MODELO > proyecto > global > omisión
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Hay **tres papeles** porque el reparto es la palanca de coste: `rapido` corre en todos los
|
|
88
|
+
turnos, `trabajo` desarrolla y `afilado` está reservado al juez. Por omisión, Ollama local.
|
|
89
|
+
|
|
90
|
+
## Cómo está construido, y por qué
|
|
91
|
+
|
|
92
|
+
Las decisiones que explican la forma del código. Ninguna es preferencia estética: todas
|
|
93
|
+
salen de un fallo medido.
|
|
94
|
+
|
|
95
|
+
**El motor de turno no sabe pintar.** `core/turno.ts` consume eventos de dominio y decide
|
|
96
|
+
qué se cuenta; la consola de stdio y (en su día) la TUI son pieles. Así el turno se prueba
|
|
97
|
+
entero sin montar un renderizador.
|
|
98
|
+
|
|
99
|
+
**Frontera de imports, y está probada.** `core/` es TypeScript puro: no importa langchain,
|
|
100
|
+
langgraph, deepagents, MCP, Ink ni React. Toda la suciedad del grafo vive en `agent/`. Hay
|
|
101
|
+
un test que recorre los ficheros de `core/` y falla si aparece un import prohibido — una
|
|
102
|
+
convención que nadie verifica dura dos semanas.
|
|
103
|
+
|
|
104
|
+
**Todo lo caro entra por un puerto, con su doble al lado.** Consecuencia buscada: la suite
|
|
105
|
+
entera corre **sin API, sin red y sin el simulador**.
|
|
106
|
+
|
|
107
|
+
**Un doble nunca se disfraza de verdad.** La marca de «esto es de pega» es un `Symbol` que
|
|
108
|
+
solo los dobles llevan, no un booleano que alguien rellena: un campo se puede olvidar, o
|
|
109
|
+
poner mal, y entonces el aviso calla justo cuando hace falta. `xonecode describe` lo canta.
|
|
110
|
+
|
|
111
|
+
**Los avisos son código, no prompt.** A un modelo al que le pides «avisa de que el
|
|
112
|
+
verificador es de pega» a veces no avisa — y ese es justo el aviso que no puede faltar.
|
|
113
|
+
|
|
114
|
+
**Y tienen alcance de TURNO.** Un aviso que salta cuando no ha pasado nada enseña al
|
|
115
|
+
usuario a ignorarlo, que es lo contrario de lo que compra.
|
|
116
|
+
|
|
117
|
+
**Aprobar ejecuta; rechazar no toca nada.** Así que lo que no se entiende es **rechazo**, y
|
|
118
|
+
el Enter a secas solo aprueba con un terminal de verdad detrás: en un pipe o en CI una línea
|
|
119
|
+
en blanco no demuestra que haya nadie mirando.
|
|
120
|
+
|
|
121
|
+
**El agente está confinado.** `FilesystemBackend` con `virtualMode: true` — medido: con el
|
|
122
|
+
default de la librería, el backend **leyó una ruta absoluta de fuera de la raíz**. Nada de
|
|
123
|
+
backends con shell: los comandos acceden a cualquier ruta y la propia librería lo impide.
|
|
124
|
+
|
|
125
|
+
**Se le ocultan las vistas aplanadas.** En XOne cada colección existe como `.xne` (la
|
|
126
|
+
fuente) y como `.xml` que genera Studio. La regla «se edita el `.xne`» no puede vivir solo
|
|
127
|
+
en un prompt: un permiso solo protege a quien lo choca. Se retira del backend, y así es una
|
|
128
|
+
propiedad del proyecto.
|
|
129
|
+
|
|
130
|
+
**La foto del ANTES es un árbol de git en un índice privado.** `GIT_INDEX_FILE` a un
|
|
131
|
+
temporal propio, `git add` y `write-tree`. No necesita commits, no necesita que el proyecto
|
|
132
|
+
sea la raíz del repo, y **no toca tu índice ni tu staging**. Medido contra un repo con cero
|
|
133
|
+
commits: `git status` daba **una** línea; el árbol privado, 107 ficheros.
|
|
134
|
+
|
|
135
|
+
## Códigos de salida
|
|
136
|
+
|
|
137
|
+
| | |
|
|
138
|
+
|---|---|
|
|
139
|
+
| 0 | bien |
|
|
140
|
+
| 1 | el proyecto tiene errores, o no es un proyecto XOne |
|
|
141
|
+
| 2 | había escrituras esperando aprobación y **nada se aplicó** |
|
|
142
|
+
| 64 | error de uso (bandera o modelo mal escritos) |
|
|
143
|
+
| 70 | fallo del **entorno**, no del proyecto |
|
|
144
|
+
|
|
145
|
+
El 2 es deliberado: un turno que se quedó esperando un permiso que nadie dio **no es un
|
|
146
|
+
éxito**, y CI no puede leerlo como tal.
|
|
147
|
+
|
|
148
|
+
## Desarrollo
|
|
149
|
+
|
|
150
|
+
```sh
|
|
151
|
+
npm run typecheck # tsc --noEmit
|
|
152
|
+
npm test # la suite entera, sin red ni claves
|
|
153
|
+
./bin/xonecode … # corre el TypeScript con tsx: siempre el código actual
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
`npm test` no puede necesitar una clave ni una conexión. Si un cambio lo rompe, está mal el
|
|
157
|
+
cambio, no el test.
|
|
158
|
+
|
|
159
|
+
`src/vendor/` son módulos propios traídos de un laboratorio anterior, con sus tests. Se
|
|
160
|
+
copiaron en vez de publicarse aparte porque son 290 líneas y no merecen un paquete.
|
|
161
|
+
|
|
162
|
+
## Más
|
|
163
|
+
|
|
164
|
+
- [`docs/COMO-PROBARLO.md`](docs/COMO-PROBARLO.md) — la guía de pruebas, paso a paso
|
|
165
|
+
- [`docs/PROBLEMA.md`](docs/PROBLEMA.md) — el enunciado del que salió el diseño
|
|
166
|
+
- [`docs/SEGUNDA-OPINION-K3.md`](docs/SEGUNDA-OPINION-K3.md) — una segunda opinión
|
|
167
|
+
independiente sobre la arquitectura, pedida a ciegas
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* El ESCRITOR de `~/.xonecode/auth.json` (el lector está en `configEnDisco.ts`).
|
|
3
|
+
*
|
|
4
|
+
* El contrato con el fichero del usuario: una escritura NUNCA destruye lo que ya
|
|
5
|
+
* había. Por eso la base de la fusión es el objeto CRUDO tal cual (no el resultado
|
|
6
|
+
* de `validarAuth`, que descarta en silencio entradas raras) y por eso ante un JSON
|
|
7
|
+
* roto se PARA sin escribir, en vez de recuperar el fichero por su cuenta.
|
|
8
|
+
*/
|
|
9
|
+
import { chmodSync, existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
10
|
+
import { dirname } from "node:path";
|
|
11
|
+
import { validarAuth } from "../core/config.js";
|
|
12
|
+
import { rutaAuth } from "./configEnDisco.js";
|
|
13
|
+
/** Un `auth.json` existente que no se puede fusionar: no se escribe nada encima. */
|
|
14
|
+
export class AuthRotoEnDisco extends Error {
|
|
15
|
+
}
|
|
16
|
+
/** Misma regla que en core/config.ts: un JSON-array NO es una raíz de fusionado. */
|
|
17
|
+
function esObjeto(v) {
|
|
18
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
19
|
+
}
|
|
20
|
+
export function guardarCredencial(proveedor, clave) {
|
|
21
|
+
const ruta = rutaAuth();
|
|
22
|
+
// 0700 en la misma llamada que crea la carpeta: un mkdir + chmod posterior dejaría
|
|
23
|
+
// una ventana con la carpeta de credenciales legible.
|
|
24
|
+
mkdirSync(dirname(ruta), { recursive: true, mode: 0o700 });
|
|
25
|
+
let base = {};
|
|
26
|
+
let avisos = [];
|
|
27
|
+
if (existsSync(ruta)) {
|
|
28
|
+
let bruto;
|
|
29
|
+
try {
|
|
30
|
+
bruto = JSON.parse(readFileSync(ruta, "utf8"));
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// El mensaje solo nombra la ruta, nunca el contenido: eso acaba en logs y captures.
|
|
34
|
+
throw new AuthRotoEnDisco(`«${ruta}»: el JSON es inválido; no se sobrescribe. Edita el fichero a mano.`);
|
|
35
|
+
}
|
|
36
|
+
if (!esObjeto(bruto)) {
|
|
37
|
+
throw new AuthRotoEnDisco(`«${ruta}»: el JSON raíz debe ser un objeto; no se sobrescribe. Edita el fichero a mano.`);
|
|
38
|
+
}
|
|
39
|
+
// Fusionar desde el result de validarAuth BORRARÍA del fichero del usuario todo lo
|
|
40
|
+
// que la validación descarta (proveedores desconocidos, credenciales de forma rara).
|
|
41
|
+
// La base es el objeto crudo; a validarAuth solo se le piden los avisos.
|
|
42
|
+
base = { ...bruto };
|
|
43
|
+
const modoReal = statSync(ruta).mode & 0o777;
|
|
44
|
+
avisos = validarAuth(bruto, ruta, modoReal, "global").avisos;
|
|
45
|
+
}
|
|
46
|
+
// Siempre la forma canónica { key } por proveedor, para que el resultado sea homogéneo
|
|
47
|
+
// aunque el fichero previo mezclara formas.
|
|
48
|
+
const fusionado = { ...base, [proveedor]: { key: clave } };
|
|
49
|
+
// El { mode } solo aplica al CREAR; en el caso de fusión el fichero conserva su modo
|
|
50
|
+
// previo, que puede haber sido malo. chmod después no viola la atomicidad: la creación
|
|
51
|
+
// sigue siendo 0600 desde el primer byte.
|
|
52
|
+
writeFileSync(ruta, JSON.stringify(fusionado, null, 2) + "\n", { mode: 0o600 });
|
|
53
|
+
chmodSync(ruta, 0o600);
|
|
54
|
+
return { ruta, avisos };
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=authEnDisco.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authEnDisco.js","sourceRoot":"","sources":["../../src/agent/authEnDisco.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAClG,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAc,MAAM,mBAAmB,CAAC;AAE5D,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,oFAAoF;AACpF,MAAM,OAAO,eAAgB,SAAQ,KAAK;CAAG;AAE7C,oFAAoF;AACpF,SAAS,QAAQ,CAAC,CAAU;IAC1B,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAClE,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,SAAoB,EAAE,KAAa;IACnE,MAAM,IAAI,GAAG,QAAQ,EAAE,CAAC;IAExB,mFAAmF;IACnF,sDAAsD;IACtD,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAE3D,IAAI,IAAI,GAA4B,EAAE,CAAC;IACvC,IAAI,MAAM,GAAY,EAAE,CAAC;IAEzB,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACrB,IAAI,KAAc,CAAC;QACnB,IAAI,CAAC;YACH,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;QACjD,CAAC;QAAC,MAAM,CAAC;YACP,oFAAoF;YACpF,MAAM,IAAI,eAAe,CACvB,IAAI,IAAI,qEAAqE,CAC9E,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACrB,MAAM,IAAI,eAAe,CACvB,IAAI,IAAI,iFAAiF,CAC1F,CAAC;QACJ,CAAC;QAED,mFAAmF;QACnF,qFAAqF;QACrF,yEAAyE;QACzE,IAAI,GAAG,EAAE,GAAG,KAAK,EAAE,CAAC;QACpB,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,GAAG,KAAK,CAAC;QAC7C,MAAM,GAAG,WAAW,CAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,MAAM,CAAC;IAC/D,CAAC;IAED,uFAAuF;IACvF,4CAA4C;IAC5C,MAAM,SAAS,GAAG,EAAE,GAAG,IAAI,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC;IAE3D,qFAAqF;IACrF,uFAAuF;IACvF,0CAA0C;IAC1C,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAChF,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAEvB,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Leer los dos ficheros de configuración del disco y volcar las credenciales en el
|
|
3
|
+
* entorno. Aquí está el I/O que `core/config.ts` no quiere: rutas, `readFileSync` y
|
|
4
|
+
* `statSync`; lo que llega a `validar`/`validarAuth` es solo datos.
|
|
5
|
+
*/
|
|
6
|
+
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
7
|
+
import { homedir } from "node:os";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
import { validar, validarAuth, } from "../core/config.js";
|
|
10
|
+
import { PROVEEDORES } from "../core/modelos.js";
|
|
11
|
+
export const NOMBRE_CARPETA = ".xonecode";
|
|
12
|
+
export function rutaConfigGlobal() {
|
|
13
|
+
// homedir() en el momento de la llamada: si se cacheara en una constante de módulo,
|
|
14
|
+
// un test que reescribe HOME después del import vería la ruta vieja.
|
|
15
|
+
return join(homedir(), NOMBRE_CARPETA, "config.json");
|
|
16
|
+
}
|
|
17
|
+
export function rutaConfigDeProyecto(raiz) {
|
|
18
|
+
return join(raiz, NOMBRE_CARPETA, "config.json");
|
|
19
|
+
}
|
|
20
|
+
export function rutaAuth() {
|
|
21
|
+
return join(homedir(), NOMBRE_CARPETA, "auth.json");
|
|
22
|
+
}
|
|
23
|
+
export function cargar(raiz) {
|
|
24
|
+
const rutas = [];
|
|
25
|
+
const avisos = [];
|
|
26
|
+
const config = {};
|
|
27
|
+
let auth = {};
|
|
28
|
+
const rutaProyecto = rutaConfigDeProyecto(raiz);
|
|
29
|
+
const existeProyecto = existsSync(rutaProyecto);
|
|
30
|
+
rutas.push({ ruta: rutaProyecto, existe: existeProyecto, procedencia: "proyecto" });
|
|
31
|
+
if (existeProyecto) {
|
|
32
|
+
try {
|
|
33
|
+
const bruto = JSON.parse(readFileSync(rutaProyecto, "utf8"));
|
|
34
|
+
const res = validar(bruto, rutaProyecto, "proyecto");
|
|
35
|
+
config.proyecto = res.config;
|
|
36
|
+
avisos.push(...res.avisos);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// El mensaje no interpola err.message: el contenido del fichero puede acabar en
|
|
40
|
+
// logs y el aviso solo dice QUÉ pasó, nunca qué contenía.
|
|
41
|
+
avisos.push({
|
|
42
|
+
texto: `«${rutaProyecto}»: el JSON es inválido; se ignora el fichero.`,
|
|
43
|
+
severidad: "aviso",
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const rutaGlobal = rutaConfigGlobal();
|
|
48
|
+
const existeGlobal = existsSync(rutaGlobal);
|
|
49
|
+
rutas.push({ ruta: rutaGlobal, existe: existeGlobal, procedencia: "global" });
|
|
50
|
+
if (existeGlobal) {
|
|
51
|
+
try {
|
|
52
|
+
const bruto = JSON.parse(readFileSync(rutaGlobal, "utf8"));
|
|
53
|
+
const res = validar(bruto, rutaGlobal, "global");
|
|
54
|
+
config.global = res.config;
|
|
55
|
+
avisos.push(...res.avisos);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
avisos.push({
|
|
59
|
+
texto: `«${rutaGlobal}»: el JSON es inválido; se ignora el fichero.`,
|
|
60
|
+
severidad: "aviso",
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const rutaAuthFichero = rutaAuth();
|
|
65
|
+
const existeAuth = existsSync(rutaAuthFichero);
|
|
66
|
+
rutas.push({ ruta: rutaAuthFichero, existe: existeAuth, procedencia: "auth" });
|
|
67
|
+
if (existeAuth) {
|
|
68
|
+
try {
|
|
69
|
+
const bruto = JSON.parse(readFileSync(rutaAuthFichero, "utf8"));
|
|
70
|
+
const modo = statSync(rutaAuthFichero).mode & 0o777;
|
|
71
|
+
const res = validarAuth(bruto, rutaAuthFichero, modo, "global");
|
|
72
|
+
auth = res.auth;
|
|
73
|
+
avisos.push(...res.avisos);
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
avisos.push({
|
|
77
|
+
texto: `«${rutaAuthFichero}»: el JSON es inválido; se ignora el fichero.`,
|
|
78
|
+
severidad: "aviso",
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return { config, auth, rutas, avisos };
|
|
83
|
+
}
|
|
84
|
+
/** Las claves ya presentes en el entorno MANDAN: `auth.json` no las machaca. */
|
|
85
|
+
const VARIABLES_POR_PROVEEDOR = {
|
|
86
|
+
anthropic: "ANTHROPIC_API_KEY",
|
|
87
|
+
openai: "OPENAI_API_KEY",
|
|
88
|
+
gemini: "GOOGLE_API_KEY",
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* Vuelca las credenciales en `process.env` y devuelve los proveedores que SÍ se
|
|
92
|
+
* aplicaron. Las que ya estaban en el entorno se dejan intactas y no se cuentan.
|
|
93
|
+
* `ollama` no tiene variable: no aparece en el mapa y se ignora.
|
|
94
|
+
*/
|
|
95
|
+
export function aplicarAuth(auth) {
|
|
96
|
+
const aplicadas = [];
|
|
97
|
+
for (const proveedor of PROVEEDORES) {
|
|
98
|
+
const variable = VARIABLES_POR_PROVEEDOR[proveedor];
|
|
99
|
+
const credencial = auth[proveedor];
|
|
100
|
+
if (variable === undefined || credencial === undefined)
|
|
101
|
+
continue;
|
|
102
|
+
if (process.env[variable] !== undefined)
|
|
103
|
+
continue;
|
|
104
|
+
process.env[variable] = credencial.key;
|
|
105
|
+
aplicadas.push(proveedor);
|
|
106
|
+
}
|
|
107
|
+
return aplicadas;
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=configEnDisco.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"configEnDisco.js","sourceRoot":"","sources":["../../src/agent/configEnDisco.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* La escritura del esqueleto en el disco del usuario.
|
|
3
|
+
*
|
|
4
|
+
* QUÉ se escribe lo decide `core/esqueleto.ts` (puro, probado sin disco); AQUÍ
|
|
5
|
+
* solo se ejecuta, al estilo de `agent/configEnDisco.ts`. La regla dura es la
|
|
6
|
+
* misma que en todo xonecode: **el disco es del usuario**, así que un fichero
|
|
7
|
+
* que ya exista no se pisa — se salta y se declara en el informe. Un proyecto
|
|
8
|
+
* a medias se completa en la siguiente corrida; un fichero del usuario
|
|
9
|
+
* destruido no se recupera.
|
|
10
|
+
*/
|
|
11
|
+
import { mkdirSync, writeFileSync, existsSync } from "node:fs";
|
|
12
|
+
import { join } from "node:path";
|
|
13
|
+
import { generarEsqueleto, carpetasDelEsqueleto } from "../core/esqueleto.js";
|
|
14
|
+
export function crearProyecto(raiz, datos) {
|
|
15
|
+
const creados = [];
|
|
16
|
+
const saltados = [];
|
|
17
|
+
for (const carpeta of carpetasDelEsqueleto()) {
|
|
18
|
+
// `recursive` y no un existsSync previo: crean lo que falte sin quejarse
|
|
19
|
+
// de lo que ya esté, que es justo lo que pide reintentar una creación a
|
|
20
|
+
// medias.
|
|
21
|
+
mkdirSync(join(raiz, carpeta), { recursive: true });
|
|
22
|
+
}
|
|
23
|
+
for (const ficha of generarEsqueleto(datos)) {
|
|
24
|
+
const destino = join(raiz, ficha.ruta);
|
|
25
|
+
if (existsSync(destino)) {
|
|
26
|
+
saltados.push(ficha.ruta);
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
writeFileSync(destino, ficha.contenido);
|
|
30
|
+
creados.push(ficha.ruta);
|
|
31
|
+
}
|
|
32
|
+
return { creados, saltados, carpetas: carpetasDelEsqueleto() };
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=crearProyecto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crearProyecto.js","sourceRoot":"","sources":["../../src/agent/crearProyecto.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAyB,MAAM,sBAAsB,CAAC;AAWrG,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,KAAuB;IACjE,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,KAAK,MAAM,OAAO,IAAI,oBAAoB,EAAE,EAAE,CAAC;QAC7C,yEAAyE;QACzE,wEAAwE;QACxE,UAAU;QACV,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACtD,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,gBAAgB,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACvC,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YACxB,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC1B,SAAS;QACX,CAAC;QACD,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;QACxC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC3B,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,oBAAoB,EAAE,EAAE,CAAC;AACjE,CAAC"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { promisify } from "node:util";
|
|
3
|
+
import { existsSync, readdirSync, statSync, realpathSync } from "node:fs";
|
|
4
|
+
import { join, basename, resolve } from "node:path";
|
|
5
|
+
const ejecutar = promisify(execFile);
|
|
6
|
+
/** Recorre la raíz sin bajar a `node_modules` ni a `.git`. */
|
|
7
|
+
function ficheros(raiz, prof = 0) {
|
|
8
|
+
if (prof > 4 || !existsSync(raiz))
|
|
9
|
+
return [];
|
|
10
|
+
const salida = [];
|
|
11
|
+
for (const entrada of readdirSync(raiz)) {
|
|
12
|
+
if (entrada === "node_modules" || entrada === ".git")
|
|
13
|
+
continue;
|
|
14
|
+
const ruta = join(raiz, entrada);
|
|
15
|
+
try {
|
|
16
|
+
if (statSync(ruta).isDirectory())
|
|
17
|
+
salida.push(...ficheros(ruta, prof + 1));
|
|
18
|
+
else
|
|
19
|
+
salida.push(ruta);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
// Un enlace roto o un permiso no es motivo para que `doctor` no conteste.
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return salida;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Las vistas aplanadas: todo `X.xml` que tenga un `X.xne` al lado.
|
|
29
|
+
*
|
|
30
|
+
* En XOne cada colección existe en dos formas, y **la que se edita es el `.xne`**. La regla
|
|
31
|
+
* no puede vivir solo en el prompt del ejecutor —un permiso solo protege a quien lo
|
|
32
|
+
* choca—, así que estos ficheros se le OCULTAN al agente. Ocultarlos y no borrarlos: el
|
|
33
|
+
* disco es del usuario.
|
|
34
|
+
*
|
|
35
|
+
* `app.xml` no tiene hermano `.xne`, así que el propio predicado lo conserva.
|
|
36
|
+
*/
|
|
37
|
+
export function vistasAplanadas(rutas) {
|
|
38
|
+
const xne = new Set(rutas.filter((r) => r.endsWith(".xne")).map((r) => r.slice(0, -4)));
|
|
39
|
+
return rutas.filter((r) => r.endsWith(".xml") && xne.has(r.slice(0, -4)));
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* ¿Sirve git para dar el diff y el deshacer de ESTE proyecto?
|
|
43
|
+
*
|
|
44
|
+
* Las tres condiciones salen de medir, no de suponer, contra el disco real del usuario:
|
|
45
|
+
*
|
|
46
|
+
* 1. **El repo tiene que ser el del PROYECTO.** Medido: los proyectos viven dentro de un
|
|
47
|
+
* repo cuya raíz está por encima, con cientos de entradas sin trackear que no tienen nada
|
|
48
|
+
* que ver. Un diff de ese repo no habla del proyecto.
|
|
49
|
+
* 2. **Tiene que haber al menos un commit.** Ese repo está en `main` con CERO commits:
|
|
50
|
+
* `git rev-parse HEAD` falla, y sin commit no hay rama de la que partir, ni worktree
|
|
51
|
+
* que añadir, ni nada contra lo que diffear.
|
|
52
|
+
* 3. **Y aunque acotes al subdirectorio, no vale.** Medido: `git status --porcelain -- .`
|
|
53
|
+
* desde dentro del proyecto devuelve UNA línea —`?? proyecto_example/`— porque git no
|
|
54
|
+
* desciende en directorios sin trackear. O sea que el diff habría dicho «1 fichero
|
|
55
|
+
* nuevo» tocara el agente lo que tocara: un fallo MUDO que reporta algo plausible.
|
|
56
|
+
* (`--untracked-files=all` lo expande, pero eso no arregla 1 ni 2.)
|
|
57
|
+
*/
|
|
58
|
+
export async function inspeccionarGit(raiz) {
|
|
59
|
+
let raizRepo;
|
|
60
|
+
try {
|
|
61
|
+
const { stdout } = await ejecutar("git", ["rev-parse", "--show-toplevel"], { cwd: raiz });
|
|
62
|
+
raizRepo = stdout.trim() || undefined;
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return { dentro: false, esRaiz: false, tieneCommits: false, prefijo: "", usable: false };
|
|
66
|
+
}
|
|
67
|
+
if (!raizRepo)
|
|
68
|
+
return { dentro: false, esRaiz: false, tieneCommits: false, prefijo: "", usable: false };
|
|
69
|
+
// `realpath` en los DOS lados, y no `resolve`. Medido en macOS: git devuelve el
|
|
70
|
+
// toplevel con los symlinks ya resueltos (`/private/var/...` para un `/var/...`), así
|
|
71
|
+
// que comparar rutas sin resolver da «no es la raíz» sobre un proyecto que SÍ lo es —
|
|
72
|
+
// y xonecode caería al modo huellas sin necesidad. `/tmp` y `/var` son symlinks en
|
|
73
|
+
// macOS, o sea que el caso no es exótico: es cualquier proyecto bajo uno de ellos.
|
|
74
|
+
const real = (r) => {
|
|
75
|
+
try {
|
|
76
|
+
return realpathSync(r);
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return resolve(r);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
const esRaiz = real(raizRepo) === real(raiz);
|
|
83
|
+
let tieneCommits = false;
|
|
84
|
+
try {
|
|
85
|
+
await ejecutar("git", ["rev-parse", "HEAD"], { cwd: raiz });
|
|
86
|
+
tieneCommits = true;
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
tieneCommits = false; // repo recién creado, sin nada commiteado
|
|
90
|
+
}
|
|
91
|
+
let prefijo = "";
|
|
92
|
+
try {
|
|
93
|
+
const { stdout } = await ejecutar("git", ["rev-parse", "--show-prefix"], { cwd: raiz });
|
|
94
|
+
prefijo = stdout.trim();
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
prefijo = "";
|
|
98
|
+
}
|
|
99
|
+
return { dentro: true, raizRepo, esRaiz, tieneCommits, prefijo, usable: true };
|
|
100
|
+
}
|
|
101
|
+
export async function inspeccionar(raiz = process.cwd()) {
|
|
102
|
+
const rutas = ficheros(raiz);
|
|
103
|
+
let responde = false;
|
|
104
|
+
let ruta = "xone-simulator";
|
|
105
|
+
try {
|
|
106
|
+
const { stdout } = await ejecutar("xone-simulator", ["help"]);
|
|
107
|
+
responde = stdout.includes("xone-simulator");
|
|
108
|
+
const cual = await ejecutar("which", ["xone-simulator"]).catch(() => ({ stdout: "" }));
|
|
109
|
+
if (cual.stdout.trim())
|
|
110
|
+
ruta = cual.stdout.trim();
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
responde = false;
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
raiz,
|
|
117
|
+
esProyectoXone: existsSync(join(raiz, "app.xml")),
|
|
118
|
+
colecciones: rutas.filter((r) => r.endsWith(".xne")).length,
|
|
119
|
+
vistasAplanadas: vistasAplanadas(rutas).map((r) => basename(r)),
|
|
120
|
+
git: await inspeccionarGit(raiz),
|
|
121
|
+
simulador: { ruta, responde },
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=entorno.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entorno.js","sourceRoot":"","sources":["../../src/agent/entorno.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC1E,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpD,MAAM,QAAQ,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAyBrC,8DAA8D;AAC9D,SAAS,QAAQ,CAAC,IAAY,EAAE,IAAI,GAAG,CAAC;IACtC,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IAC7C,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,MAAM,OAAO,IAAI,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;QACxC,IAAI,OAAO,KAAK,cAAc,IAAI,OAAO,KAAK,MAAM;YAAE,SAAS;QAC/D,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACjC,IAAI,CAAC;YACH,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE;gBAAE,MAAM,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC;;gBACtE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC;QAAC,MAAM,CAAC;YACP,0EAA0E;QAC5E,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,eAAe,CAAC,KAAe;IAC7C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACxF,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5E,CAAC;AA+BD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAY;IAChD,IAAI,QAA4B,CAAC;IACjC,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,iBAAiB,CAAC,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1F,QAAQ,GAAG,MAAM,CAAC,IAAI,EAAE,IAAI,SAAS,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IAC3F,CAAC;IACD,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IAExG,gFAAgF;IAChF,sFAAsF;IACtF,sFAAsF;IACtF,mFAAmF;IACnF,mFAAmF;IACnF,MAAM,IAAI,GAAG,CAAC,CAAS,EAAU,EAAE;QACjC,IAAI,CAAC;YACH,OAAO,YAAY,CAAC,CAAC,CAAC,CAAC;QACzB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC;QACpB,CAAC;IACH,CAAC,CAAC;IACF,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7C,IAAI,YAAY,GAAG,KAAK,CAAC;IACzB,IAAI,CAAC;QACH,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,MAAM,CAAC,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5D,YAAY,GAAG,IAAI,CAAC;IACtB,CAAC;IAAC,MAAM,CAAC;QACP,YAAY,GAAG,KAAK,CAAC,CAAC,0CAA0C;IAClE,CAAC;IAED,IAAI,OAAO,GAAG,EAAE,CAAC;IACjB,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,eAAe,CAAC,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;QACxF,OAAO,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,EAAE,CAAC;IACf,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AACjF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,OAAe,OAAO,CAAC,GAAG,EAAE;IAC7D,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC7B,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,IAAI,GAAG,gBAAgB,CAAC;IAC5B,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,QAAQ,CAAC,gBAAgB,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;QAC9D,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;QAC7C,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,OAAO,EAAE,CAAC,gBAAgB,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;QACvF,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;YAAE,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IACpD,CAAC;IAAC,MAAM,CAAC;QACP,QAAQ,GAAG,KAAK,CAAC;IACnB,CAAC;IAED,OAAO;QACL,IAAI;QACJ,cAAc,EAAE,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QACjD,WAAW,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM;QAC3D,eAAe,EAAE,eAAe,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAC/D,GAAG,EAAE,MAAM,eAAe,CAAC,IAAI,CAAC;QAChC,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;KAC9B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { ES_DOBLE } from "../core/ports.js";
|
|
2
|
+
/**
|
|
3
|
+
* Un turno completo de pega, para ver el motor correr sin API ni red.
|
|
4
|
+
*
|
|
5
|
+
* Lleva la marca de doble: `xonecode describe` (fase 5) tiene que poder decir que lo que
|
|
6
|
+
* está montado no es el agente de verdad. Un mock que no se declara hace creer que el
|
|
7
|
+
* sistema funciona.
|
|
8
|
+
*
|
|
9
|
+
* El guion recorre a propósito las cosas que cuestan de pintar: una racha de tools, una
|
|
10
|
+
* verificación en rojo, una reparación, y una respuesta troceada en varios mensajes.
|
|
11
|
+
*/
|
|
12
|
+
export class AgenteGuionizado {
|
|
13
|
+
retardoMs;
|
|
14
|
+
[ES_DOBLE] = true;
|
|
15
|
+
constructor(retardoMs = 0) {
|
|
16
|
+
this.retardoMs = retardoMs;
|
|
17
|
+
}
|
|
18
|
+
async *turno(peticion) {
|
|
19
|
+
const pausa = async () => {
|
|
20
|
+
if (this.retardoMs > 0)
|
|
21
|
+
await new Promise((r) => setTimeout(r, this.retardoMs));
|
|
22
|
+
};
|
|
23
|
+
yield { tipo: "fase", fase: "entendiendo" };
|
|
24
|
+
await pausa();
|
|
25
|
+
yield { tipo: "fase", fase: "planificando" };
|
|
26
|
+
yield {
|
|
27
|
+
tipo: "plan",
|
|
28
|
+
tareas: [
|
|
29
|
+
{ id: "T1", descripcion: `[GUION] ${peticion}`, aceptacion: [] },
|
|
30
|
+
],
|
|
31
|
+
};
|
|
32
|
+
await pausa();
|
|
33
|
+
yield { tipo: "tarea", id: "T1", indice: 1, total: 1, estado: "en-curso" };
|
|
34
|
+
yield { tipo: "fase", fase: "ejecutando" };
|
|
35
|
+
for (let i = 0; i < 3; i++) {
|
|
36
|
+
yield { tipo: "tool", nombre: "read_file" };
|
|
37
|
+
await pausa();
|
|
38
|
+
}
|
|
39
|
+
yield { tipo: "tool", nombre: "grep" };
|
|
40
|
+
yield { tipo: "fase", fase: "verificando" };
|
|
41
|
+
yield { tipo: "verificacion", verde: false, errores: 2, avisos: 1 };
|
|
42
|
+
yield { tipo: "reparacion", intento: 1, tope: 3 };
|
|
43
|
+
yield { tipo: "tool", nombre: "edit_file" };
|
|
44
|
+
yield { tipo: "verificacion", verde: true, errores: 0, avisos: 0 };
|
|
45
|
+
yield { tipo: "tarea", id: "T1", indice: 1, total: 1, estado: "hecha" };
|
|
46
|
+
yield { tipo: "fase", fase: "respondiendo" };
|
|
47
|
+
for (const trozo of ["Listo. ", "He recorrido ", "el turno entero ", "sin llamar a ningún modelo."]) {
|
|
48
|
+
yield { tipo: "token", texto: trozo, msgId: "guion-1" };
|
|
49
|
+
await pausa();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=guionizado.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guionizado.js","sourceRoot":"","sources":["../../src/agent/guionizado.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAG5C;;;;;;;;;GASG;AACH,MAAM,OAAO,gBAAgB;IAGE;IAFpB,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC;IAE3B,YAA6B,YAAY,CAAC;QAAb,cAAS,GAAT,SAAS,CAAI;IAAG,CAAC;IAE9C,KAAK,CAAC,CAAC,KAAK,CAAC,QAAgB;QAC3B,MAAM,KAAK,GAAG,KAAK,IAAmB,EAAE;YACtC,IAAI,IAAI,CAAC,SAAS,GAAG,CAAC;gBAAE,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;QAClF,CAAC,CAAC;QAEF,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC;QAC5C,MAAM,KAAK,EAAE,CAAC;QAEd,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC;QAC7C,MAAM;YACJ,IAAI,EAAE,MAAM;YACZ,MAAM,EAAE;gBACN,EAAE,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,WAAW,QAAQ,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE;aACjE;SACF,CAAC;QACF,MAAM,KAAK,EAAE,CAAC;QAEd,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;QAC3E,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;QAC3C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3B,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;YAC5C,MAAM,KAAK,EAAE,CAAC;QAChB,CAAC;QACD,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;QAEvC,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC;QAC5C,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;QACpE,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QAClD,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;QAC5C,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;QACnE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;QAExE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC;QAC7C,KAAK,MAAM,KAAK,IAAI,CAAC,SAAS,EAAE,eAAe,EAAE,kBAAkB,EAAE,6BAA6B,CAAC,EAAE,CAAC;YACpG,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;YACxD,MAAM,KAAK,EAAE,CAAC;QAChB,CAAC;IACH,CAAC;CACF"}
|