@korl3one/ccode 2.0.1 → 2.2.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 +140 -226
- package/dist/ai/deepseek.d.ts +11 -0
- package/dist/ai/deepseek.js +35 -0
- package/dist/ai/gemini.d.ts +10 -0
- package/dist/ai/gemini.js +31 -0
- package/dist/ai/groq.d.ts +11 -0
- package/dist/ai/groq.js +35 -0
- package/dist/ai/manager.d.ts +2 -1
- package/dist/ai/manager.js +12 -0
- package/dist/ai/openai.d.ts +10 -0
- package/dist/ai/openai.js +34 -0
- package/dist/cli/index.js +269 -16
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,328 +5,242 @@
|
|
|
5
5
|
██║ ██║ ██║ ██║██║ ██║██╔══╝
|
|
6
6
|
╚██████╗╚██████╗ ╚██████╔╝██████╔╝███████╗
|
|
7
7
|
╚═════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝
|
|
8
|
-
Context-Persistent AI Development v2.0
|
|
9
8
|
```
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
# CCODE — Contexto Persistente para Desarrollo Asistido
|
|
14
|
-
|
|
15
|
-
## QUE es CCODE
|
|
16
|
-
|
|
17
|
-
CCODE es una herramienta CLI que genera y mantiene el **contexto de trabajo** de un proyecto de software. Genera documentacion profesional, arquitectura, reglas de desarrollo y un checklist de tareas verificables — todo adaptado automaticamente a la complejidad real del proyecto.
|
|
18
|
-
|
|
19
|
-
**CCODE no genera codigo.** Genera el contexto que guia el desarrollo.
|
|
20
|
-
|
|
21
|
-
Cuando ejecutas `ccode init`, un wizard interactivo te pregunta sobre tu proyecto y una IA genera:
|
|
22
|
-
|
|
23
|
-
| Archivo | Contenido |
|
|
24
|
-
|---------|-----------|
|
|
25
|
-
| `project.md` | Vision, objetivos, alcance y funcionalidades |
|
|
26
|
-
| `architecture.md` | Estructura del sistema adaptada a la complejidad |
|
|
27
|
-
| `rules.md` | Estandares de desarrollo especificos al stack |
|
|
28
|
-
| `tasks.json` | Checklist de tareas con criterios de aceptacion |
|
|
29
|
-
| `state.json` | Tarea activa y etapa del workflow |
|
|
30
|
-
| `context.json` | Configuracion general del proyecto |
|
|
31
|
-
| `memory.md` | Historial de decisiones y tareas completadas |
|
|
32
|
-
| `config.json` | Configuracion del proveedor de IA |
|
|
33
|
-
|
|
34
|
-
Todo vive en la carpeta `.ccode/` dentro del repositorio. Cualquier desarrollador o IA puede leerla y entender el proyecto al instante.
|
|
10
|
+
# CCODE
|
|
35
11
|
|
|
36
|
-
|
|
12
|
+
**Persistent context CLI for AI-assisted development.**
|
|
37
13
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
Cuando trabajas con IA en un proyecto grande, el contexto se pierde al cambiar de sesion, modelo o herramienta. Cada vez hay que re-explicar todo. CCODE resuelve esto almacenando el contexto en el repositorio como archivos versionables con Git.
|
|
41
|
-
|
|
42
|
-
---
|
|
43
|
-
|
|
44
|
-
## COMO funciona
|
|
45
|
-
|
|
46
|
-
### Instalacion
|
|
14
|
+
Stop re-explaining your project to AI every time the session resets.
|
|
47
15
|
|
|
48
16
|
```bash
|
|
49
17
|
npm install -g @korl3one/ccode
|
|
18
|
+
ccode init
|
|
50
19
|
```
|
|
51
20
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
Si quieres colaborar con el proyecto:
|
|
21
|
+
[](https://www.npmjs.com/package/@korl3one/ccode)
|
|
22
|
+
[](LICENSE)
|
|
23
|
+
[](https://nodejs.org)
|
|
57
24
|
|
|
58
|
-
|
|
59
|
-
git clone https://github.com/iDevelop25/ccode.git
|
|
60
|
-
cd ccode
|
|
61
|
-
npm install
|
|
62
|
-
npm run build
|
|
63
|
-
npm link
|
|
64
|
-
```
|
|
25
|
+
---
|
|
65
26
|
|
|
66
|
-
|
|
27
|
+
## The problem
|
|
67
28
|
|
|
68
|
-
|
|
29
|
+
Every time you switch sessions, models, or tools when working with AI, you lose your project context. You end up re-explaining the architecture, previous decisions, and current state over and over again.
|
|
69
30
|
|
|
70
|
-
|
|
71
|
-
cd mi-proyecto
|
|
72
|
-
ccode init
|
|
73
|
-
```
|
|
31
|
+
## The solution
|
|
74
32
|
|
|
75
|
-
|
|
33
|
+
CCODE stores your project context **inside the repository**. One command generates professional documentation, architecture, rules, and a verifiable task checklist — all adapted to your project's actual complexity.
|
|
76
34
|
|
|
77
|
-
|
|
78
|
-
●○○○ Paso 1/4 — Descripcion del proyecto
|
|
79
|
-
> "Una app de gestion de tareas con autenticacion y dashboard"
|
|
35
|
+
Any developer or AI can read `.ccode/` and understand the project instantly.
|
|
80
36
|
|
|
81
|
-
|
|
82
|
-
> "Login, registro, CRUD de tareas, filtros, estadisticas"
|
|
37
|
+
---
|
|
83
38
|
|
|
84
|
-
|
|
85
|
-
> "Next.js, TypeScript, Prisma, PostgreSQL"
|
|
39
|
+
## Demo
|
|
86
40
|
|
|
87
|
-
●●●● Paso 4/4 — Tipo de proyecto
|
|
88
|
-
> "Aplicacion web"
|
|
89
41
|
```
|
|
42
|
+
$ ccode init
|
|
90
43
|
|
|
91
|
-
|
|
44
|
+
██████╗ ██████╗ ██████╗ ██████╗ ███████╗
|
|
45
|
+
██╔════╝██╔════╝ ██╔═══██╗██╔══██╗██╔════╝
|
|
46
|
+
██║ ██║ ██║ ██║██║ ██║█████╗
|
|
47
|
+
╚██████╗╚██████╗ ╚██████╔╝██████╔╝███████╗
|
|
48
|
+
╚═════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝
|
|
92
49
|
|
|
93
|
-
|
|
94
|
-
- **Medio** (app estandar): contexto moderado, 5-8 tareas
|
|
95
|
-
- **Complejo** (multiples modulos, integraciones): contexto completo con patrones y diagramas, 8-12 tareas
|
|
50
|
+
●●●● Paso 4/4
|
|
96
51
|
|
|
97
|
-
|
|
52
|
+
✓ Contexto generado exitosamente
|
|
98
53
|
|
|
99
|
-
|
|
54
|
+
.ccode/
|
|
55
|
+
├── project.md Documentacion del proyecto
|
|
56
|
+
├── architecture.md Arquitectura del sistema
|
|
57
|
+
├── rules.md Estandares de desarrollo
|
|
58
|
+
├── tasks.json Checklist de tareas (8 tareas)
|
|
59
|
+
├── context.json Configuracion
|
|
60
|
+
├── state.json Estado del workflow
|
|
61
|
+
└── memory.md Historial de decisiones
|
|
100
62
|
|
|
101
|
-
|
|
63
|
+
CCODE sigue observando tu proyecto...
|
|
102
64
|
|
|
103
|
-
```
|
|
104
65
|
████████████░░░░░░░░ 60% (3/5)
|
|
105
66
|
> Tarea activa: TASK-002 — Crear formulario de login
|
|
106
67
|
|
|
107
68
|
? Que hacemos?
|
|
108
69
|
> Verificar progreso (se detectaron cambios)
|
|
109
70
|
Marcar tarea como completada
|
|
110
|
-
Iniciar siguiente tarea
|
|
111
|
-
Generar / actualizar plan de tareas
|
|
71
|
+
Iniciar siguiente tarea
|
|
112
72
|
Ver estado completo
|
|
113
|
-
Ver contexto generado
|
|
114
73
|
Salir
|
|
115
74
|
```
|
|
116
75
|
|
|
117
|
-
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Why CCODE?
|
|
118
79
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
80
|
+
| | CCODE | Manual prompts |
|
|
81
|
+
|---|:---:|:---:|
|
|
82
|
+
| Persistent project context | ✅ | ❌ |
|
|
83
|
+
| Architecture adapted to complexity | ✅ | ❌ |
|
|
84
|
+
| AI-ready documentation | ✅ | ❌ |
|
|
85
|
+
| Verifiable task checklist | ✅ | ❌ |
|
|
86
|
+
| Auto-detect file changes | ✅ | ❌ |
|
|
87
|
+
| AI-powered task verification | ✅ | ❌ |
|
|
88
|
+
| Works with 6 AI providers | ✅ | ❌ |
|
|
89
|
+
| Context lives in the repo (Git) | ✅ | ❌ |
|
|
124
90
|
|
|
125
|
-
|
|
91
|
+
---
|
|
126
92
|
|
|
127
|
-
|
|
93
|
+
## How it works
|
|
128
94
|
|
|
129
|
-
|
|
95
|
+
### 1. Initialize
|
|
130
96
|
|
|
97
|
+
```bash
|
|
98
|
+
cd my-project
|
|
99
|
+
ccode init
|
|
131
100
|
```
|
|
132
|
-
> Verificar progreso con IA
|
|
133
101
|
|
|
134
|
-
|
|
102
|
+
A step-by-step wizard asks about your project and an AI generates the full context. CCODE adapts automatically:
|
|
135
103
|
|
|
136
|
-
|
|
137
|
-
|
|
104
|
+
- **Simple project** (prototype, few features) → lightweight context, 3-5 tasks
|
|
105
|
+
- **Medium project** (standard app) → moderate context, 5-8 tasks
|
|
106
|
+
- **Complex project** (multiple modules, integrations) → detailed architecture, 8-12 tasks
|
|
138
107
|
|
|
139
|
-
|
|
140
|
-
Falta: Campo de contrasena no encontrado, validacion pendiente
|
|
108
|
+
### 2. Persistent session
|
|
141
109
|
|
|
142
|
-
|
|
143
|
-
```
|
|
110
|
+
After init, CCODE stays active — watching your project in real time:
|
|
144
111
|
|
|
145
|
-
|
|
112
|
+
- Detects file changes automatically
|
|
113
|
+
- Suggests verifying tasks when it sees progress
|
|
114
|
+
- Adapts the menu to your current workflow state
|
|
115
|
+
- Recovers from errors without crashing
|
|
146
116
|
|
|
147
|
-
|
|
117
|
+
You code in your editor. CCODE runs in another terminal as a companion.
|
|
148
118
|
|
|
149
|
-
|
|
150
|
-
|--------|----------|
|
|
151
|
-
| **Conectar IA** | Configura Claude o Ollama como proveedor |
|
|
152
|
-
| **Siguiente tarea** | Muestra la tarea mas prioritaria y ofrece iniciarla |
|
|
153
|
-
| **Verificar progreso** | La IA escanea el proyecto y actualiza estados |
|
|
154
|
-
| **Completar tarea** | Marca como completada, registra en memoria |
|
|
155
|
-
| **Re-planificar** | Genera nuevas tareas considerando lo ya completado |
|
|
156
|
-
| **Ver estado** | Dashboard con barra de progreso y estadisticas |
|
|
157
|
-
| **Ver contexto** | Muestra cualquier archivo de `.ccode/` |
|
|
119
|
+
### 3. AI verification
|
|
158
120
|
|
|
159
|
-
|
|
121
|
+
CCODE compares **acceptance criteria** against **actual project files**:
|
|
160
122
|
|
|
161
|
-
|
|
123
|
+
```
|
|
124
|
+
✓ TASK-001: Setup project base — COMPLETED
|
|
125
|
+
Evidence: package.json, tsconfig.json found
|
|
162
126
|
|
|
163
|
-
|
|
127
|
+
◐ TASK-002: Create login form — IN PROGRESS
|
|
128
|
+
Missing: password field not found, validation pending
|
|
164
129
|
|
|
165
|
-
|
|
130
|
+
○ TASK-003: Implement JWT auth — PENDING
|
|
131
|
+
```
|
|
166
132
|
|
|
167
|
-
###
|
|
133
|
+
### 4. Context export
|
|
168
134
|
|
|
169
|
-
|
|
135
|
+
```bash
|
|
136
|
+
ccode export
|
|
137
|
+
```
|
|
170
138
|
|
|
171
|
-
|
|
172
|
-
- **Independencia de modelo:** Cualquier IA (Claude, GPT, Ollama, la que sea) puede leer `.ccode/` y entender el proyecto al instante.
|
|
173
|
-
- **Trazabilidad:** Cada cambio queda en archivos versionables con Git. Puedes ver cuando se tomo cada decision.
|
|
174
|
-
- **Consistencia:** Todos los colaboradores y herramientas operan con la misma fuente de verdad.
|
|
175
|
-
- **Workflow explicito:** El estado del workflow evita que se ejecuten acciones fuera de orden.
|
|
139
|
+
Generates a single `.md` file with your full project context — ready to paste into any AI chat (ChatGPT, Claude, Gemini, etc.) without connecting an API.
|
|
176
140
|
|
|
177
|
-
###
|
|
141
|
+
### 5. Project health check
|
|
178
142
|
|
|
179
|
-
|
|
143
|
+
```bash
|
|
144
|
+
ccode doctor
|
|
145
|
+
```
|
|
180
146
|
|
|
181
147
|
```
|
|
182
|
-
|
|
183
|
-
|
|
148
|
+
✓ Contexto generado
|
|
149
|
+
✓ Proveedor de IA configurado
|
|
150
|
+
⚠ 2 tareas sin completar
|
|
151
|
+
⚠ architecture.md no refleja 3 archivos nuevos
|
|
152
|
+
✓ Conexion con IA activa
|
|
184
153
|
```
|
|
185
154
|
|
|
186
|
-
Esto permite que cualquier desarrollador (humano o IA) ejecute las tareas con su propio criterio tecnico. CCODE guia el rumbo, no dicta la implementacion.
|
|
187
|
-
|
|
188
155
|
---
|
|
189
156
|
|
|
190
|
-
##
|
|
157
|
+
## Supported AI Providers
|
|
158
|
+
|
|
159
|
+
| Provider | Models | Note |
|
|
160
|
+
|----------|--------|------|
|
|
161
|
+
| **Claude** (Anthropic) | Sonnet 4, Haiku 3.5, Opus 4 | Recommended |
|
|
162
|
+
| **OpenAI** (ChatGPT) | GPT-4o, GPT-4o mini, GPT-4.1, o3-mini | Most popular |
|
|
163
|
+
| **Google Gemini** | 2.5 Flash, 2.5 Pro, 2.0 Flash | Free tier available |
|
|
164
|
+
| **DeepSeek** | Chat, Reasoner | Budget-friendly |
|
|
165
|
+
| **Groq** | Llama 3.3 70B, Llama 3.1 8B, Mixtral 8x7B | Ultra-fast, free tier |
|
|
166
|
+
| **Ollama** | Any local model | Offline, no API key |
|
|
191
167
|
|
|
192
|
-
|
|
168
|
+
---
|
|
193
169
|
|
|
194
|
-
|
|
195
|
-
- **Guia paso a paso** sin que te pierdas en un proyecto grande
|
|
196
|
-
- **Detecta tu progreso** automaticamente mientras programas
|
|
197
|
-
- **Adapta la complejidad** al tamano real del proyecto
|
|
170
|
+
## Available commands
|
|
198
171
|
|
|
199
|
-
|
|
172
|
+
| Command | What it does |
|
|
173
|
+
|---------|-------------|
|
|
174
|
+
| `ccode init` | Interactive wizard — generates full project context |
|
|
175
|
+
| `ccode update` | Re-analyze project and refresh context |
|
|
176
|
+
| `ccode export` | Export context as a single `.md` file for any AI |
|
|
177
|
+
| `ccode explain` | Quick project summary for onboarding |
|
|
178
|
+
| `ccode doctor` | Health check — what's good, what's missing |
|
|
179
|
+
| `ccode connect` | Configure AI provider |
|
|
180
|
+
| `ccode status` | Dashboard with progress bar and stats |
|
|
200
181
|
|
|
201
|
-
|
|
202
|
-
- **Onboarding rapido:** Un nuevo miembro lee `.ccode/` y entiende todo
|
|
203
|
-
- **Decisiones trazables:** El historial de memoria muestra por que se tomaron decisiones
|
|
182
|
+
---
|
|
204
183
|
|
|
205
|
-
|
|
184
|
+
## What gets generated
|
|
206
185
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
186
|
+
Everything lives in `.ccode/` inside your repository:
|
|
187
|
+
|
|
188
|
+
| File | Content |
|
|
189
|
+
|------|---------|
|
|
190
|
+
| `project.md` | Vision, objectives, scope |
|
|
191
|
+
| `architecture.md` | System structure adapted to complexity |
|
|
192
|
+
| `rules.md` | Development standards for your stack |
|
|
193
|
+
| `tasks.json` | Task checklist with acceptance criteria |
|
|
194
|
+
| `state.json` | Active task, workflow stage |
|
|
195
|
+
| `memory.md` | Decision history |
|
|
196
|
+
| `config.json` | AI provider config |
|
|
210
197
|
|
|
211
198
|
---
|
|
212
199
|
|
|
213
|
-
##
|
|
200
|
+
## Architecture
|
|
214
201
|
|
|
215
202
|
```
|
|
216
203
|
src/
|
|
217
|
-
cli/
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
core/
|
|
222
|
-
context.ts → ContextEngine (configuracion + estado del workflow)
|
|
223
|
-
tasks.ts → TaskEngine (checklist de tareas con prioridades)
|
|
224
|
-
prompt-builder.ts → Meta-prompts adaptativos, generacion y verificacion
|
|
225
|
-
ai/
|
|
226
|
-
provider.ts → Interfaz comun IAIProvider (patron Adapter)
|
|
227
|
-
claude.ts → Adapter para Claude (API de Anthropic)
|
|
228
|
-
ollama.ts → Adapter para Ollama (modelos locales)
|
|
229
|
-
manager.ts → Gestion de configuracion y conexion
|
|
230
|
-
utils/
|
|
231
|
-
files.ts → Abstraccion del sistema de archivos
|
|
204
|
+
cli/ → Session, branding, file watcher
|
|
205
|
+
core/ → Context engine, tasks, prompt builder
|
|
206
|
+
ai/ → 6 provider adapters (Adapter pattern)
|
|
207
|
+
utils/ → File system abstraction
|
|
232
208
|
```
|
|
233
209
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
| Patron | Donde | Por que |
|
|
237
|
-
|--------|-------|---------|
|
|
238
|
-
| **Adapter** | `ai/` | Proveedores intercambiables sin cambiar el core |
|
|
239
|
-
| **State Machine** | `context.ts` | Workflow explicito (created → connected → planned → in_progress → idle) |
|
|
240
|
-
| **Observer** | `watcher.ts` | Deteccion reactiva de cambios en archivos |
|
|
241
|
-
| **Builder** | `prompt-builder.ts` | Construccion incremental de prompts complejos |
|
|
242
|
-
|
|
243
|
-
### Paleta de colores
|
|
244
|
-
|
|
245
|
-
| Color | Hex | Uso |
|
|
246
|
-
|-------|-----|-----|
|
|
247
|
-
| Primary | `#00B4D8` | Elementos principales, headers |
|
|
248
|
-
| Secondary | `#0077B6` | Acentos secundarios |
|
|
249
|
-
| Accent | `#90E0EF` | Highlights, info destacada |
|
|
250
|
-
| Success | `#2DC653` | Operaciones exitosas |
|
|
251
|
-
| Warning | `#FFB703` | Advertencias |
|
|
252
|
-
| Error | `#E63946` | Errores |
|
|
253
|
-
|
|
254
|
-
### Logo gradiente
|
|
255
|
-
|
|
256
|
-
El logo ASCII usa un gradiente de 6 tonos de azul/cyan:
|
|
257
|
-
`#90E0EF → #48CAE4 → #00B4D8 → #0096C7 → #0077B6 → #023E8A`
|
|
210
|
+
Key patterns: **Adapter** (AI providers), **Observer** (file watcher), **State Machine** (workflow), **Builder** (prompts).
|
|
258
211
|
|
|
259
212
|
---
|
|
260
213
|
|
|
261
|
-
##
|
|
262
|
-
|
|
263
|
-
| Tecnologia | Rol |
|
|
264
|
-
|------------|-----|
|
|
265
|
-
| **Node.js** | Runtime |
|
|
266
|
-
| **TypeScript** | Tipado estatico, interfaces |
|
|
267
|
-
| **ESM** | Sistema de modulos (`"type": "module"`, `NodeNext`) |
|
|
268
|
-
| **Commander.js** | Definicion de comandos CLI |
|
|
269
|
-
| **Inquirer v13** | Prompts interactivos y menus |
|
|
270
|
-
| **Chalk v5** | Colores en terminal |
|
|
271
|
-
| **Ora v8** | Spinners de progreso |
|
|
272
|
-
| **Axios** | HTTP client para APIs de IA |
|
|
273
|
-
| **fs-extra** | Operaciones de archivos mejoradas |
|
|
274
|
-
| **Vitest** | Testing |
|
|
214
|
+
## Contributing
|
|
275
215
|
|
|
276
|
-
|
|
216
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for setup instructions and guidelines.
|
|
277
217
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
```bash
|
|
281
|
-
# Ejecutar tests
|
|
282
|
-
npm test
|
|
283
|
-
|
|
284
|
-
# Tests en modo watch
|
|
285
|
-
npm test:watch
|
|
286
|
-
```
|
|
287
|
-
|
|
288
|
-
19 tests cubriendo:
|
|
289
|
-
- `PromptBuilder.parseJSON` — parsing robusto de respuestas de IA (directo, envuelto en texto, bloques markdown)
|
|
290
|
-
- `TaskEngine` — CRUD de tareas, priorizacion, estadisticas, manejo de errores
|
|
291
|
-
- `FileWatcher` — Estado inicial, flush, stop seguro
|
|
218
|
+
Adding a new AI provider? Just implement `IAIProvider`, add it to the manager switch, done.
|
|
292
219
|
|
|
293
220
|
---
|
|
294
221
|
|
|
295
|
-
##
|
|
222
|
+
## Learn more
|
|
296
223
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
npm test # Ejecutar tests
|
|
302
|
-
npm run test:watch # Tests en modo watch
|
|
303
|
-
```
|
|
224
|
+
- [Learning guide](docs/learning/README.md) — 6 modules following QP2C methodology
|
|
225
|
+
- [AGENTS.md](AGENTS.md) — Engineering roles
|
|
226
|
+
- [SKILLS.md](SKILLS.md) — Technical competencies
|
|
227
|
+
- [YouTube @CreativeCode25](https://www.youtube.com/@CreativeCode25) — Tutorials and walkthroughs
|
|
304
228
|
|
|
305
229
|
---
|
|
306
230
|
|
|
307
|
-
##
|
|
308
|
-
|
|
309
|
-
El proyecto incluye una guia de aprendizaje modular bajo la metodologia **QP2C** (Que, Como, Por que, Para que):
|
|
231
|
+
## Support the project
|
|
310
232
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
| [00 — Introduccion](docs/learning/modules/00-intro.md) | Que es CCODE y que problema resuelve |
|
|
314
|
-
| [01 — CLI y Sesion](docs/learning/modules/01-cli-session.md) | Arquitectura CLI, loop persistente, menu contextual |
|
|
315
|
-
| [02 — Contexto Persistente](docs/learning/modules/02-context-persistence.md) | ContextEngine, TaskEngine, estado en `.ccode/` |
|
|
316
|
-
| [03 — Generacion de Contexto](docs/learning/modules/03-context-generation.md) | PromptBuilder, meta-prompts, adaptacion de complejidad |
|
|
317
|
-
| [04 — Proveedores de IA](docs/learning/modules/04-ai-providers.md) | Patron Adapter, Claude, Ollama, AIManager |
|
|
318
|
-
| [05 — Watcher y Verificacion](docs/learning/modules/05-watcher-verify.md) | FileWatcher, verificacion automatica de tareas |
|
|
233
|
+
If CCODE helps you, consider giving it a **star on GitHub** ⭐
|
|
234
|
+
It helps the project grow and reach more developers.
|
|
319
235
|
|
|
320
|
-
|
|
321
|
-
- [`AGENTS.md`](AGENTS.md) — Roles de ingenieria del proyecto
|
|
322
|
-
- [`SKILLS.md`](SKILLS.md) — Competencias tecnicas requeridas
|
|
236
|
+
[](https://github.com/iDevelop25/ccode)
|
|
323
237
|
|
|
324
238
|
---
|
|
325
239
|
|
|
326
|
-
##
|
|
240
|
+
## License
|
|
327
241
|
|
|
328
242
|
ISC
|
|
329
243
|
|
|
330
244
|
---
|
|
331
245
|
|
|
332
|
-
*CCODE
|
|
246
|
+
*CCODE doesn't tell you how to code — it tells you what to build and makes sure you don't lose track.*
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { IAIProvider, IAIConfig } from './provider.js';
|
|
2
|
+
/**
|
|
3
|
+
* Adaptador para DeepSeek.
|
|
4
|
+
* Usa formato compatible con OpenAI.
|
|
5
|
+
*/
|
|
6
|
+
export declare class DeepSeekAdapter implements IAIProvider {
|
|
7
|
+
private config;
|
|
8
|
+
constructor(config: IAIConfig);
|
|
9
|
+
getName(): string;
|
|
10
|
+
generate(prompt: string): Promise<string>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
/**
|
|
3
|
+
* Adaptador para DeepSeek.
|
|
4
|
+
* Usa formato compatible con OpenAI.
|
|
5
|
+
*/
|
|
6
|
+
export class DeepSeekAdapter {
|
|
7
|
+
config;
|
|
8
|
+
constructor(config) {
|
|
9
|
+
this.config = {
|
|
10
|
+
apiKey: config.apiKey || '',
|
|
11
|
+
model: config.model || 'deepseek-chat',
|
|
12
|
+
baseUrl: config.baseUrl || 'https://api.deepseek.com/v1/chat/completions',
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
getName() {
|
|
16
|
+
return `DeepSeek (${this.config.model})`;
|
|
17
|
+
}
|
|
18
|
+
async generate(prompt) {
|
|
19
|
+
if (!this.config.apiKey) {
|
|
20
|
+
throw new Error('API Key de DeepSeek no configurada.');
|
|
21
|
+
}
|
|
22
|
+
const response = await axios.post(this.config.baseUrl, {
|
|
23
|
+
model: this.config.model,
|
|
24
|
+
max_tokens: 8096,
|
|
25
|
+
messages: [{ role: 'user', content: prompt }],
|
|
26
|
+
}, {
|
|
27
|
+
headers: {
|
|
28
|
+
'Authorization': `Bearer ${this.config.apiKey}`,
|
|
29
|
+
'Content-Type': 'application/json',
|
|
30
|
+
},
|
|
31
|
+
timeout: 120000,
|
|
32
|
+
});
|
|
33
|
+
return response.data.choices[0].message.content;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { IAIProvider, IAIConfig } from './provider.js';
|
|
2
|
+
/**
|
|
3
|
+
* Adaptador para Google Gemini.
|
|
4
|
+
*/
|
|
5
|
+
export declare class GeminiAdapter implements IAIProvider {
|
|
6
|
+
private config;
|
|
7
|
+
constructor(config: IAIConfig);
|
|
8
|
+
getName(): string;
|
|
9
|
+
generate(prompt: string): Promise<string>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
/**
|
|
3
|
+
* Adaptador para Google Gemini.
|
|
4
|
+
*/
|
|
5
|
+
export class GeminiAdapter {
|
|
6
|
+
config;
|
|
7
|
+
constructor(config) {
|
|
8
|
+
this.config = {
|
|
9
|
+
apiKey: config.apiKey || '',
|
|
10
|
+
model: config.model || 'gemini-2.5-flash',
|
|
11
|
+
baseUrl: config.baseUrl || 'https://generativelanguage.googleapis.com/v1beta/models',
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
getName() {
|
|
15
|
+
return `Gemini (${this.config.model})`;
|
|
16
|
+
}
|
|
17
|
+
async generate(prompt) {
|
|
18
|
+
if (!this.config.apiKey) {
|
|
19
|
+
throw new Error('API Key de Google AI no configurada.');
|
|
20
|
+
}
|
|
21
|
+
const url = `${this.config.baseUrl}/${this.config.model}:generateContent?key=${this.config.apiKey}`;
|
|
22
|
+
const response = await axios.post(url, {
|
|
23
|
+
contents: [{ parts: [{ text: prompt }] }],
|
|
24
|
+
generationConfig: { maxOutputTokens: 8096 },
|
|
25
|
+
}, {
|
|
26
|
+
headers: { 'Content-Type': 'application/json' },
|
|
27
|
+
timeout: 120000,
|
|
28
|
+
});
|
|
29
|
+
return response.data.candidates[0].content.parts[0].text;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { IAIProvider, IAIConfig } from './provider.js';
|
|
2
|
+
/**
|
|
3
|
+
* Adaptador para Groq (inferencia ultra-rápida).
|
|
4
|
+
* Usa formato compatible con OpenAI.
|
|
5
|
+
*/
|
|
6
|
+
export declare class GroqAdapter implements IAIProvider {
|
|
7
|
+
private config;
|
|
8
|
+
constructor(config: IAIConfig);
|
|
9
|
+
getName(): string;
|
|
10
|
+
generate(prompt: string): Promise<string>;
|
|
11
|
+
}
|
package/dist/ai/groq.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
/**
|
|
3
|
+
* Adaptador para Groq (inferencia ultra-rápida).
|
|
4
|
+
* Usa formato compatible con OpenAI.
|
|
5
|
+
*/
|
|
6
|
+
export class GroqAdapter {
|
|
7
|
+
config;
|
|
8
|
+
constructor(config) {
|
|
9
|
+
this.config = {
|
|
10
|
+
apiKey: config.apiKey || '',
|
|
11
|
+
model: config.model || 'llama-3.3-70b-versatile',
|
|
12
|
+
baseUrl: config.baseUrl || 'https://api.groq.com/openai/v1/chat/completions',
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
getName() {
|
|
16
|
+
return `Groq (${this.config.model})`;
|
|
17
|
+
}
|
|
18
|
+
async generate(prompt) {
|
|
19
|
+
if (!this.config.apiKey) {
|
|
20
|
+
throw new Error('API Key de Groq no configurada.');
|
|
21
|
+
}
|
|
22
|
+
const response = await axios.post(this.config.baseUrl, {
|
|
23
|
+
model: this.config.model,
|
|
24
|
+
max_tokens: 8096,
|
|
25
|
+
messages: [{ role: 'user', content: prompt }],
|
|
26
|
+
}, {
|
|
27
|
+
headers: {
|
|
28
|
+
'Authorization': `Bearer ${this.config.apiKey}`,
|
|
29
|
+
'Content-Type': 'application/json',
|
|
30
|
+
},
|
|
31
|
+
timeout: 60000,
|
|
32
|
+
});
|
|
33
|
+
return response.data.choices[0].message.content;
|
|
34
|
+
}
|
|
35
|
+
}
|
package/dist/ai/manager.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { IAIProvider } from './provider.js';
|
|
2
|
+
export type ProviderName = 'claude' | 'openai' | 'gemini' | 'deepseek' | 'groq' | 'ollama';
|
|
2
3
|
export interface ICCODEConfig {
|
|
3
|
-
provider:
|
|
4
|
+
provider: ProviderName;
|
|
4
5
|
apiKey?: string;
|
|
5
6
|
model?: string;
|
|
6
7
|
baseUrl?: string;
|
package/dist/ai/manager.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import * as path from 'path';
|
|
2
2
|
import { ClaudeAdapter } from './claude.js';
|
|
3
|
+
import { OpenAIAdapter } from './openai.js';
|
|
4
|
+
import { GeminiAdapter } from './gemini.js';
|
|
5
|
+
import { DeepSeekAdapter } from './deepseek.js';
|
|
6
|
+
import { GroqAdapter } from './groq.js';
|
|
3
7
|
import { OllamaAdapter } from './ollama.js';
|
|
4
8
|
import { FileUtils } from '../utils/files.js';
|
|
5
9
|
/**
|
|
@@ -22,6 +26,14 @@ export class AIManager {
|
|
|
22
26
|
switch (config.provider) {
|
|
23
27
|
case 'claude':
|
|
24
28
|
return new ClaudeAdapter({ apiKey: config.apiKey, model: config.model });
|
|
29
|
+
case 'openai':
|
|
30
|
+
return new OpenAIAdapter({ apiKey: config.apiKey, model: config.model });
|
|
31
|
+
case 'gemini':
|
|
32
|
+
return new GeminiAdapter({ apiKey: config.apiKey, model: config.model });
|
|
33
|
+
case 'deepseek':
|
|
34
|
+
return new DeepSeekAdapter({ apiKey: config.apiKey, model: config.model });
|
|
35
|
+
case 'groq':
|
|
36
|
+
return new GroqAdapter({ apiKey: config.apiKey, model: config.model });
|
|
25
37
|
case 'ollama':
|
|
26
38
|
return new OllamaAdapter({ model: config.model, baseUrl: config.baseUrl });
|
|
27
39
|
default:
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { IAIProvider, IAIConfig } from './provider.js';
|
|
2
|
+
/**
|
|
3
|
+
* Adaptador para OpenAI (ChatGPT).
|
|
4
|
+
*/
|
|
5
|
+
export declare class OpenAIAdapter implements IAIProvider {
|
|
6
|
+
private config;
|
|
7
|
+
constructor(config: IAIConfig);
|
|
8
|
+
getName(): string;
|
|
9
|
+
generate(prompt: string): Promise<string>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
/**
|
|
3
|
+
* Adaptador para OpenAI (ChatGPT).
|
|
4
|
+
*/
|
|
5
|
+
export class OpenAIAdapter {
|
|
6
|
+
config;
|
|
7
|
+
constructor(config) {
|
|
8
|
+
this.config = {
|
|
9
|
+
apiKey: config.apiKey || '',
|
|
10
|
+
model: config.model || 'gpt-4o',
|
|
11
|
+
baseUrl: config.baseUrl || 'https://api.openai.com/v1/chat/completions',
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
getName() {
|
|
15
|
+
return `OpenAI (${this.config.model})`;
|
|
16
|
+
}
|
|
17
|
+
async generate(prompt) {
|
|
18
|
+
if (!this.config.apiKey) {
|
|
19
|
+
throw new Error('API Key de OpenAI no configurada.');
|
|
20
|
+
}
|
|
21
|
+
const response = await axios.post(this.config.baseUrl, {
|
|
22
|
+
model: this.config.model,
|
|
23
|
+
max_tokens: 8096,
|
|
24
|
+
messages: [{ role: 'user', content: prompt }],
|
|
25
|
+
}, {
|
|
26
|
+
headers: {
|
|
27
|
+
'Authorization': `Bearer ${this.config.apiKey}`,
|
|
28
|
+
'Content-Type': 'application/json',
|
|
29
|
+
},
|
|
30
|
+
timeout: 120000,
|
|
31
|
+
});
|
|
32
|
+
return response.data.choices[0].message.content;
|
|
33
|
+
}
|
|
34
|
+
}
|
package/dist/cli/index.js
CHANGED
|
@@ -39,37 +39,73 @@ async function promptAIConfig() {
|
|
|
39
39
|
message: 'Proveedor de IA:',
|
|
40
40
|
choices: [
|
|
41
41
|
{ name: ' Claude (Anthropic) — Recomendado', value: 'claude' },
|
|
42
|
-
{ name: '
|
|
42
|
+
{ name: ' OpenAI (ChatGPT)', value: 'openai' },
|
|
43
|
+
{ name: ' Google Gemini', value: 'gemini' },
|
|
44
|
+
{ name: ' DeepSeek', value: 'deepseek' },
|
|
45
|
+
{ name: ' Groq (ultra-rápido)', value: 'groq' },
|
|
46
|
+
{ name: ' Ollama (local, sin API key)', value: 'ollama' },
|
|
43
47
|
],
|
|
44
48
|
}]);
|
|
45
49
|
const config = { provider };
|
|
46
|
-
|
|
50
|
+
// Modelos por proveedor
|
|
51
|
+
const modelChoices = {
|
|
52
|
+
claude: [
|
|
53
|
+
{ name: 'Claude Sonnet 4 (recomendado)', value: 'claude-sonnet-4-20250514' },
|
|
54
|
+
{ name: 'Claude Haiku 3.5 (rápido)', value: 'claude-haiku-4-5-20251001' },
|
|
55
|
+
{ name: 'Claude Opus 4 (máxima calidad)', value: 'claude-opus-4-20250514' },
|
|
56
|
+
],
|
|
57
|
+
openai: [
|
|
58
|
+
{ name: 'GPT-4o (recomendado)', value: 'gpt-4o' },
|
|
59
|
+
{ name: 'GPT-4o mini (rápido)', value: 'gpt-4o-mini' },
|
|
60
|
+
{ name: 'GPT-4.1 (último)', value: 'gpt-4.1' },
|
|
61
|
+
{ name: 'o3-mini (razonamiento)', value: 'o3-mini' },
|
|
62
|
+
],
|
|
63
|
+
gemini: [
|
|
64
|
+
{ name: 'Gemini 2.5 Flash (recomendado)', value: 'gemini-2.5-flash' },
|
|
65
|
+
{ name: 'Gemini 2.5 Pro (máxima calidad)', value: 'gemini-2.5-pro' },
|
|
66
|
+
{ name: 'Gemini 2.0 Flash (rápido)', value: 'gemini-2.0-flash' },
|
|
67
|
+
],
|
|
68
|
+
deepseek: [
|
|
69
|
+
{ name: 'DeepSeek Chat (recomendado)', value: 'deepseek-chat' },
|
|
70
|
+
{ name: 'DeepSeek Reasoner', value: 'deepseek-reasoner' },
|
|
71
|
+
],
|
|
72
|
+
groq: [
|
|
73
|
+
{ name: 'Llama 3.3 70B (recomendado)', value: 'llama-3.3-70b-versatile' },
|
|
74
|
+
{ name: 'Llama 3.1 8B (rápido)', value: 'llama-3.1-8b-instant' },
|
|
75
|
+
{ name: 'Mixtral 8x7B', value: 'mixtral-8x7b-32768' },
|
|
76
|
+
],
|
|
77
|
+
};
|
|
78
|
+
// API Key (todos excepto Ollama)
|
|
79
|
+
if (provider !== 'ollama') {
|
|
80
|
+
const providerNames = {
|
|
81
|
+
claude: 'Anthropic', openai: 'OpenAI', gemini: 'Google AI',
|
|
82
|
+
deepseek: 'DeepSeek', groq: 'Groq',
|
|
83
|
+
};
|
|
47
84
|
const { apiKey } = await inquirer.prompt([{
|
|
48
85
|
type: 'password',
|
|
49
86
|
name: 'apiKey',
|
|
50
|
-
message:
|
|
87
|
+
message: `API Key de ${providerNames[provider]}:`,
|
|
51
88
|
mask: '*',
|
|
52
89
|
validate: (v) => v.length > 10 || 'Ingresa una API Key válida',
|
|
53
90
|
}]);
|
|
54
91
|
config.apiKey = apiKey;
|
|
92
|
+
}
|
|
93
|
+
// Selección de modelo
|
|
94
|
+
if (provider === 'ollama') {
|
|
55
95
|
const { model } = await inquirer.prompt([{
|
|
56
|
-
type: '
|
|
96
|
+
type: 'input',
|
|
57
97
|
name: 'model',
|
|
58
|
-
message: 'Modelo:',
|
|
59
|
-
|
|
60
|
-
{ name: 'Claude Sonnet 4 (recomendado)', value: 'claude-sonnet-4-20250514' },
|
|
61
|
-
{ name: 'Claude Haiku 3.5 (rápido)', value: 'claude-haiku-4-5-20251001' },
|
|
62
|
-
{ name: 'Claude Opus 4 (máxima calidad)', value: 'claude-opus-4-20250514' },
|
|
63
|
-
],
|
|
98
|
+
message: 'Modelo de Ollama:',
|
|
99
|
+
default: 'llama3',
|
|
64
100
|
}]);
|
|
65
101
|
config.model = model;
|
|
66
102
|
}
|
|
67
103
|
else {
|
|
68
104
|
const { model } = await inquirer.prompt([{
|
|
69
|
-
type: '
|
|
105
|
+
type: 'select',
|
|
70
106
|
name: 'model',
|
|
71
|
-
message: 'Modelo
|
|
72
|
-
|
|
107
|
+
message: 'Modelo:',
|
|
108
|
+
choices: modelChoices[provider],
|
|
73
109
|
}]);
|
|
74
110
|
config.model = model;
|
|
75
111
|
}
|
|
@@ -143,7 +179,7 @@ async function startSession() {
|
|
|
143
179
|
if (!hasConfig) {
|
|
144
180
|
choices.push({ name: ' 🔌 Conectar proveedor de IA', value: 'connect' });
|
|
145
181
|
}
|
|
146
|
-
choices.push({ name: ' 📋 Generar / actualizar plan de tareas', value: 'plan' }, { name: ` 📊 Ver estado completo`, value: 'status' }, { name: ' 📄 Ver contexto generado', value: 'context' });
|
|
182
|
+
choices.push({ name: ' 📋 Generar / actualizar plan de tareas', value: 'plan' }, { name: ` 📊 Ver estado completo`, value: 'status' }, { name: ' 📄 Ver contexto generado', value: 'context' }, { name: ' 🔄 Actualizar contexto (re-analizar proyecto)', value: 'update' }, { name: ' 📤 Exportar contexto para otra IA', value: 'export' }, { name: ' 💡 Explicar proyecto (resumen rápido)', value: 'explain' }, { name: ' 🩺 Doctor (diagnóstico de salud)', value: 'doctor' });
|
|
147
183
|
if (hasConfig) {
|
|
148
184
|
choices.push({ name: ' 🔌 Reconfigurar IA', value: 'connect' });
|
|
149
185
|
}
|
|
@@ -175,6 +211,10 @@ async function startSession() {
|
|
|
175
211
|
complete: handleComplete,
|
|
176
212
|
status: handleStatus,
|
|
177
213
|
context: handleContext,
|
|
214
|
+
update: handleUpdate,
|
|
215
|
+
export: handleExport,
|
|
216
|
+
explain: handleExplain,
|
|
217
|
+
doctor: handleDoctor,
|
|
178
218
|
};
|
|
179
219
|
if (handlers[action]) {
|
|
180
220
|
try {
|
|
@@ -353,7 +393,7 @@ async function handleConnect() {
|
|
|
353
393
|
}
|
|
354
394
|
else {
|
|
355
395
|
spinner.fail(c.error('No se pudo conectar'));
|
|
356
|
-
showError('Verifica
|
|
396
|
+
showError('Verifica tu API Key, conexión a internet, o que Ollama esté corriendo.');
|
|
357
397
|
}
|
|
358
398
|
}
|
|
359
399
|
// ─── PLAN ───────────────────────────────────────────────────────────
|
|
@@ -684,13 +724,222 @@ async function handleContext() {
|
|
|
684
724
|
}
|
|
685
725
|
console.log('');
|
|
686
726
|
}
|
|
727
|
+
// ─── UPDATE ─────────────────────────────────────────────────────────
|
|
728
|
+
async function handleUpdate() {
|
|
729
|
+
if (!(await requireInit()))
|
|
730
|
+
return;
|
|
731
|
+
const config = await requireAI();
|
|
732
|
+
if (!config)
|
|
733
|
+
return;
|
|
734
|
+
showHeader('Actualizar Contexto');
|
|
735
|
+
const spinner = ora({ text: 'Analizando proyecto...', color: 'cyan', spinner: 'dots' }).start();
|
|
736
|
+
try {
|
|
737
|
+
const ccodePath = path.join(process.cwd(), '.ccode');
|
|
738
|
+
const contextEngine = new ContextEngine();
|
|
739
|
+
await contextEngine.load();
|
|
740
|
+
const ctx = contextEngine.getContext();
|
|
741
|
+
// Leer archivos del proyecto
|
|
742
|
+
const projectFiles = listProjectFiles(process.cwd());
|
|
743
|
+
// Leer contexto actual
|
|
744
|
+
const currentProject = await FileUtils.readFileSafe(path.join(ccodePath, 'project.md'));
|
|
745
|
+
const currentArch = await FileUtils.readFileSafe(path.join(ccodePath, 'architecture.md'));
|
|
746
|
+
const currentRules = await FileUtils.readFileSafe(path.join(ccodePath, 'rules.md'));
|
|
747
|
+
spinner.text = 'Actualizando con IA...';
|
|
748
|
+
const provider = AIManager.getProvider(config);
|
|
749
|
+
const updatePrompt = `Eres un arquitecto de software. Analiza el estado ACTUAL del proyecto y actualiza la documentación existente.
|
|
750
|
+
|
|
751
|
+
=== DOCUMENTACIÓN ACTUAL ===
|
|
752
|
+
${currentProject}
|
|
753
|
+
|
|
754
|
+
=== ARQUITECTURA ACTUAL ===
|
|
755
|
+
${currentArch}
|
|
756
|
+
|
|
757
|
+
=== REGLAS ACTUALES ===
|
|
758
|
+
${currentRules}
|
|
759
|
+
|
|
760
|
+
=== ARCHIVOS EN EL PROYECTO ===
|
|
761
|
+
${projectFiles.join('\n')}
|
|
762
|
+
|
|
763
|
+
Actualiza la documentación para reflejar los archivos y estructura actuales del proyecto. Mantén lo que siga siendo válido, actualiza lo que haya cambiado, agrega lo nuevo.
|
|
764
|
+
|
|
765
|
+
Responde ÚNICAMENTE con JSON válido:
|
|
766
|
+
{
|
|
767
|
+
"project": "Contenido actualizado de project.md",
|
|
768
|
+
"architecture": "Contenido actualizado de architecture.md",
|
|
769
|
+
"rules": "Contenido actualizado de rules.md",
|
|
770
|
+
"changes": ["Lista de cambios detectados"]
|
|
771
|
+
}`;
|
|
772
|
+
const response = await provider.generate(updatePrompt);
|
|
773
|
+
const result = PromptBuilder.parseJSON(response);
|
|
774
|
+
await FileUtils.writeFile(path.join(ccodePath, 'project.md'), result.project);
|
|
775
|
+
await FileUtils.writeFile(path.join(ccodePath, 'architecture.md'), result.architecture);
|
|
776
|
+
await FileUtils.writeFile(path.join(ccodePath, 'rules.md'), result.rules);
|
|
777
|
+
spinner.succeed(c.success('Contexto actualizado'));
|
|
778
|
+
if (result.changes && result.changes.length > 0) {
|
|
779
|
+
console.log('');
|
|
780
|
+
console.log(c.accent(' Cambios detectados:'));
|
|
781
|
+
result.changes.forEach(change => console.log(c.dim(` • ${change}`)));
|
|
782
|
+
}
|
|
783
|
+
console.log('');
|
|
784
|
+
}
|
|
785
|
+
catch (error) {
|
|
786
|
+
spinner.fail('Error');
|
|
787
|
+
showError(error instanceof Error ? error.message : String(error));
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
// ─── EXPORT ─────────────────────────────────────────────────────────
|
|
791
|
+
async function handleExport() {
|
|
792
|
+
if (!(await requireInit()))
|
|
793
|
+
return;
|
|
794
|
+
showHeader('Exportar Contexto');
|
|
795
|
+
const pb = new PromptBuilder();
|
|
796
|
+
const fullContext = await pb.buildContextPrompt();
|
|
797
|
+
const exportPath = path.join(process.cwd(), '.ccode', 'context-export.md');
|
|
798
|
+
await FileUtils.writeFile(exportPath, `# CCODE — Project Context Export\n\n${fullContext}`);
|
|
799
|
+
showSuccess('Contexto exportado a .ccode/context-export.md');
|
|
800
|
+
showInfo('Copia el contenido y pégalo en cualquier chat de IA (ChatGPT, Claude, Gemini, etc.).');
|
|
801
|
+
console.log('');
|
|
802
|
+
}
|
|
803
|
+
// ─── EXPLAIN ────────────────────────────────────────────────────────
|
|
804
|
+
async function handleExplain() {
|
|
805
|
+
if (!(await requireInit()))
|
|
806
|
+
return;
|
|
807
|
+
showHeader('Resumen del Proyecto');
|
|
808
|
+
const ccodePath = path.join(process.cwd(), '.ccode');
|
|
809
|
+
const projectMd = await FileUtils.readFileSafe(path.join(ccodePath, 'project.md'));
|
|
810
|
+
const archMd = await FileUtils.readFileSafe(path.join(ccodePath, 'architecture.md'));
|
|
811
|
+
const taskEngine = new TaskEngine();
|
|
812
|
+
await taskEngine.load();
|
|
813
|
+
const stats = taskEngine.getStats();
|
|
814
|
+
const projectFiles = listProjectFiles(process.cwd());
|
|
815
|
+
// Extraer info clave
|
|
816
|
+
console.log(c.bold(' Proyecto'));
|
|
817
|
+
projectMd.split('\n').slice(0, 8).forEach(line => {
|
|
818
|
+
if (line.trim())
|
|
819
|
+
console.log(` ${line}`);
|
|
820
|
+
});
|
|
821
|
+
console.log('');
|
|
822
|
+
console.log(c.bold(' Arquitectura'));
|
|
823
|
+
archMd.split('\n').slice(0, 12).forEach(line => {
|
|
824
|
+
if (line.trim())
|
|
825
|
+
console.log(` ${line}`);
|
|
826
|
+
});
|
|
827
|
+
console.log('');
|
|
828
|
+
console.log(c.bold(' Archivos detectados'));
|
|
829
|
+
const dirs = projectFiles.filter(f => f.endsWith('/')).slice(0, 10);
|
|
830
|
+
dirs.forEach(d => console.log(c.accent(` ${d}`)));
|
|
831
|
+
const fileCount = projectFiles.filter(f => !f.endsWith('/')).length;
|
|
832
|
+
console.log(c.dim(` ${fileCount} archivos en total`));
|
|
833
|
+
console.log('');
|
|
834
|
+
console.log(c.bold(' Progreso'));
|
|
835
|
+
console.log(` ${showProgressBar(stats.completed, stats.total)}`);
|
|
836
|
+
console.log(c.dim(` ${stats.completed} completadas, ${stats.in_progress} en progreso, ${stats.pending} pendientes, ${stats.failed} fallidas`));
|
|
837
|
+
console.log('');
|
|
838
|
+
}
|
|
839
|
+
// ─── DOCTOR ─────────────────────────────────────────────────────────
|
|
840
|
+
async function handleDoctor() {
|
|
841
|
+
if (!(await requireInit()))
|
|
842
|
+
return;
|
|
843
|
+
showHeader('Diagnóstico del Proyecto');
|
|
844
|
+
const ccodePath = path.join(process.cwd(), '.ccode');
|
|
845
|
+
let issues = 0;
|
|
846
|
+
// 1. Verificar archivos de contexto
|
|
847
|
+
const requiredFiles = [
|
|
848
|
+
{ file: 'context.json', label: 'Configuración del proyecto' },
|
|
849
|
+
{ file: 'state.json', label: 'Estado del workflow' },
|
|
850
|
+
{ file: 'project.md', label: 'Documentación del proyecto' },
|
|
851
|
+
{ file: 'architecture.md', label: 'Arquitectura' },
|
|
852
|
+
{ file: 'rules.md', label: 'Reglas de desarrollo' },
|
|
853
|
+
{ file: 'tasks.json', label: 'Checklist de tareas' },
|
|
854
|
+
{ file: 'memory.md', label: 'Historial de decisiones' },
|
|
855
|
+
];
|
|
856
|
+
console.log(c.bold(' Archivos de contexto'));
|
|
857
|
+
for (const { file, label } of requiredFiles) {
|
|
858
|
+
const exists = await FileUtils.exists(path.join(ccodePath, file));
|
|
859
|
+
if (exists) {
|
|
860
|
+
const content = await FileUtils.readFileSafe(path.join(ccodePath, file));
|
|
861
|
+
if (content.trim().length < 5) {
|
|
862
|
+
console.log(c.warning(` ⚠ ${label} (${file}) — existe pero está vacío`));
|
|
863
|
+
issues++;
|
|
864
|
+
}
|
|
865
|
+
else {
|
|
866
|
+
console.log(c.success(` ✓ ${label}`));
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
else {
|
|
870
|
+
console.log(c.error(` ✗ ${label} (${file}) — no encontrado`));
|
|
871
|
+
issues++;
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
// 2. Proveedor de IA
|
|
875
|
+
console.log('');
|
|
876
|
+
console.log(c.bold(' Proveedor de IA'));
|
|
877
|
+
const config = await AIManager.loadConfig();
|
|
878
|
+
if (config) {
|
|
879
|
+
console.log(c.success(` ✓ Configurado: ${config.provider} (${config.model || 'default'})`));
|
|
880
|
+
// Test de conexión
|
|
881
|
+
const spinner = ora({ text: ' Probando conexión...', color: 'cyan', spinner: 'dots' }).start();
|
|
882
|
+
const connected = await AIManager.testConnection(config);
|
|
883
|
+
if (connected) {
|
|
884
|
+
spinner.succeed(c.success('Conexión activa'));
|
|
885
|
+
}
|
|
886
|
+
else {
|
|
887
|
+
spinner.fail(c.error('No se pudo conectar'));
|
|
888
|
+
issues++;
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
else {
|
|
892
|
+
console.log(c.warning(` ⚠ No configurado — ejecuta "Conectar IA"`));
|
|
893
|
+
issues++;
|
|
894
|
+
}
|
|
895
|
+
// 3. Tareas
|
|
896
|
+
console.log('');
|
|
897
|
+
console.log(c.bold(' Tareas'));
|
|
898
|
+
const taskEngine = new TaskEngine();
|
|
899
|
+
await taskEngine.load();
|
|
900
|
+
const stats = taskEngine.getStats();
|
|
901
|
+
if (stats.total === 0) {
|
|
902
|
+
console.log(c.warning(' ⚠ No hay tareas — ejecuta "Generar plan"'));
|
|
903
|
+
issues++;
|
|
904
|
+
}
|
|
905
|
+
else {
|
|
906
|
+
console.log(c.success(` ✓ ${stats.total} tareas en total`));
|
|
907
|
+
if (stats.completed > 0)
|
|
908
|
+
console.log(c.success(` ✓ ${stats.completed} completadas`));
|
|
909
|
+
if (stats.in_progress > 0)
|
|
910
|
+
console.log(c.accent(` ◐ ${stats.in_progress} en progreso`));
|
|
911
|
+
if (stats.pending > 0)
|
|
912
|
+
console.log(c.warning(` ⚠ ${stats.pending} pendientes`));
|
|
913
|
+
if (stats.failed > 0) {
|
|
914
|
+
console.log(c.error(` ✗ ${stats.failed} fallidas — necesitan replantearse`));
|
|
915
|
+
issues++;
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
// 4. Archivos del proyecto
|
|
919
|
+
console.log('');
|
|
920
|
+
console.log(c.bold(' Proyecto'));
|
|
921
|
+
const projectFiles = listProjectFiles(process.cwd());
|
|
922
|
+
const fileCount = projectFiles.filter(f => !f.endsWith('/')).length;
|
|
923
|
+
const dirCount = projectFiles.filter(f => f.endsWith('/')).length;
|
|
924
|
+
console.log(c.success(` ✓ ${fileCount} archivos en ${dirCount} directorios`));
|
|
925
|
+
// Resumen
|
|
926
|
+
console.log('');
|
|
927
|
+
console.log(c.dim(' ─────────────────────────────────────────────'));
|
|
928
|
+
if (issues === 0) {
|
|
929
|
+
console.log(c.success(' ✓ Todo en orden — el proyecto está saludable'));
|
|
930
|
+
}
|
|
931
|
+
else {
|
|
932
|
+
console.log(c.warning(` ⚠ ${issues} problema${issues > 1 ? 's' : ''} encontrado${issues > 1 ? 's' : ''}`));
|
|
933
|
+
}
|
|
934
|
+
console.log('');
|
|
935
|
+
}
|
|
687
936
|
// ─── CLI Setup ──────────────────────────────────────────────────────
|
|
688
937
|
async function main() {
|
|
689
938
|
const program = new Command();
|
|
690
939
|
program
|
|
691
940
|
.name('ccode')
|
|
692
941
|
.description('CCODE: Contexto Persistente para Desarrollo con IA')
|
|
693
|
-
.version('2.
|
|
942
|
+
.version('2.2.0');
|
|
694
943
|
// Comandos individuales (para uso rápido sin sesión)
|
|
695
944
|
program.command('init').description('Inicializa el contexto del proyecto').action(async () => {
|
|
696
945
|
await handleInit();
|
|
@@ -704,6 +953,10 @@ async function main() {
|
|
|
704
953
|
program.command('complete').description('Completa una tarea').action(handleComplete);
|
|
705
954
|
program.command('status').description('Estado del proyecto').action(handleStatus);
|
|
706
955
|
program.command('context').description('Ver contexto generado').action(handleContext);
|
|
956
|
+
program.command('update').description('Re-analiza y actualiza el contexto').action(handleUpdate);
|
|
957
|
+
program.command('export').description('Exporta contexto como .md para cualquier IA').action(handleExport);
|
|
958
|
+
program.command('explain').description('Resumen rápido del proyecto').action(handleExplain);
|
|
959
|
+
program.command('doctor').description('Diagnóstico de salud del proyecto').action(handleDoctor);
|
|
707
960
|
if (process.argv.length <= 2) {
|
|
708
961
|
// Sin argumentos → sesión interactiva
|
|
709
962
|
const isInitialized = await FileUtils.exists(path.join(process.cwd(), '.ccode'));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@korl3one/ccode",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "CLI de contexto persistente para desarrollo asistido por IA. Genera documentacion, arquitectura, reglas y tareas verificables.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/cli/index.js",
|