elsabro 2.3.0 → 3.8.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 +698 -20
- package/bin/install.js +0 -0
- package/flows/development-flow.json +452 -0
- package/flows/quick-flow.json +118 -0
- package/hooks/hooks-config-updated.json +285 -0
- package/hooks/skill-discovery.sh +539 -0
- package/package.json +3 -2
- package/references/SYSTEM_INDEX.md +400 -5
- package/references/agent-marketplace.md +2274 -0
- package/references/agent-protocol.md +1126 -0
- package/references/ai-code-suggestions.md +2413 -0
- package/references/checkpointing.md +595 -0
- package/references/collaboration-patterns.md +851 -0
- package/references/collaborative-sessions.md +1081 -0
- package/references/configuration-management.md +1810 -0
- package/references/cost-tracking.md +1095 -0
- package/references/enterprise-sso.md +2001 -0
- package/references/error-contracts-v2.md +968 -0
- package/references/event-driven.md +1031 -0
- package/references/flow-orchestration.md +940 -0
- package/references/flow-visualization.md +1557 -0
- package/references/ide-integrations.md +3513 -0
- package/references/interrupt-system.md +681 -0
- package/references/kubernetes-deployment.md +3099 -0
- package/references/memory-system.md +683 -0
- package/references/mobile-companion.md +3236 -0
- package/references/multi-llm-providers.md +2494 -0
- package/references/multi-project-memory.md +1182 -0
- package/references/observability.md +793 -0
- package/references/output-schemas.md +858 -0
- package/references/performance-profiler.md +955 -0
- package/references/plugin-system.md +1526 -0
- package/references/prompt-management.md +292 -0
- package/references/sandbox-execution.md +303 -0
- package/references/security-system.md +1253 -0
- package/references/skill-marketplace-integration.md +3901 -0
- package/references/streaming.md +696 -0
- package/references/testing-framework.md +1151 -0
- package/references/time-travel.md +802 -0
- package/references/tool-registry.md +886 -0
- package/references/voice-commands.md +3296 -0
- package/templates/agent-marketplace-config.json +220 -0
- package/templates/agent-protocol-config.json +136 -0
- package/templates/ai-suggestions-config.json +100 -0
- package/templates/checkpoint-state.json +61 -0
- package/templates/collaboration-config.json +157 -0
- package/templates/collaborative-sessions-config.json +153 -0
- package/templates/configuration-config.json +245 -0
- package/templates/cost-tracking-config.json +148 -0
- package/templates/enterprise-sso-config.json +438 -0
- package/templates/events-config.json +148 -0
- package/templates/flow-visualization-config.json +196 -0
- package/templates/ide-integrations-config.json +442 -0
- package/templates/kubernetes-config.json +764 -0
- package/templates/memory-state.json +84 -0
- package/templates/mobile-companion-config.json +600 -0
- package/templates/multi-llm-config.json +544 -0
- package/templates/multi-project-memory-config.json +145 -0
- package/templates/observability-config.json +109 -0
- package/templates/performance-profiler-config.json +125 -0
- package/templates/plugin-config.json +170 -0
- package/templates/prompt-management-config.json +86 -0
- package/templates/sandbox-config.json +185 -0
- package/templates/schemas-config.json +65 -0
- package/templates/security-config.json +120 -0
- package/templates/skill-marketplace-config.json +441 -0
- package/templates/streaming-config.json +72 -0
- package/templates/testing-config.json +81 -0
- package/templates/timetravel-config.json +62 -0
- package/templates/tool-registry-config.json +109 -0
- package/templates/voice-commands-config.json +658 -0
|
@@ -0,0 +1,595 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: checkpointing
|
|
3
|
+
description: Sistema de checkpointing persistente inspirado en LangGraph
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# ELSABRO Persistent Checkpointing System
|
|
8
|
+
|
|
9
|
+
## Vision General
|
|
10
|
+
|
|
11
|
+
El sistema de checkpointing permite guardar y restaurar el estado completo de ejecución en cualquier momento, habilitando:
|
|
12
|
+
- **Recuperación de sesiones** después de interrupciones
|
|
13
|
+
- **Time-travel debugging** para analizar decisiones pasadas
|
|
14
|
+
- **Rollback** a cualquier punto anterior
|
|
15
|
+
- **Resume from interrupt** después de pausas manuales
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
┌──────────────────────────────────────────────────────────────────────┐
|
|
19
|
+
│ CHECKPOINT LIFECYCLE │
|
|
20
|
+
├──────────────────────────────────────────────────────────────────────┤
|
|
21
|
+
│ │
|
|
22
|
+
│ START │
|
|
23
|
+
│ │ │
|
|
24
|
+
│ ▼ │
|
|
25
|
+
│ ┌─────────┐ auto-save ┌─────────┐ complete ┌────────┐ │
|
|
26
|
+
│ │ INIT │ ──────────────► │ ACTIVE │ ────────────► │ DONE │ │
|
|
27
|
+
│ └─────────┘ └─────────┘ └────────┘ │
|
|
28
|
+
│ │ │
|
|
29
|
+
│ interrupt/error │
|
|
30
|
+
│ │ │
|
|
31
|
+
│ ▼ │
|
|
32
|
+
│ ┌──────────┐ │
|
|
33
|
+
│ │ PAUSED │ │
|
|
34
|
+
│ └──────────┘ │
|
|
35
|
+
│ │ │
|
|
36
|
+
│ resume │
|
|
37
|
+
│ │ │
|
|
38
|
+
│ ▼ │
|
|
39
|
+
│ ┌──────────┐ │
|
|
40
|
+
│ │ ACTIVE │ (restored) │
|
|
41
|
+
│ └──────────┘ │
|
|
42
|
+
│ │
|
|
43
|
+
└──────────────────────────────────────────────────────────────────────┘
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Estructura del Checkpoint
|
|
49
|
+
|
|
50
|
+
### checkpoint-state.json
|
|
51
|
+
|
|
52
|
+
```json
|
|
53
|
+
{
|
|
54
|
+
"version": "3.0.0",
|
|
55
|
+
"checkpointId": "chk_2024012015300001",
|
|
56
|
+
"sessionId": "ses_abc123",
|
|
57
|
+
"createdAt": "2024-01-20T15:30:00.000Z",
|
|
58
|
+
"updatedAt": "2024-01-20T15:45:32.000Z",
|
|
59
|
+
|
|
60
|
+
"execution": {
|
|
61
|
+
"status": "ACTIVE",
|
|
62
|
+
"currentPhase": "implementation",
|
|
63
|
+
"currentWave": 2,
|
|
64
|
+
"totalWaves": 4,
|
|
65
|
+
"progress": 0.45
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
"graph": {
|
|
69
|
+
"nodes": [
|
|
70
|
+
{"id": "n1", "type": "agent", "agent": "elsabro-analyst", "status": "COMPLETE"},
|
|
71
|
+
{"id": "n2", "type": "agent", "agent": "elsabro-planner", "status": "COMPLETE"},
|
|
72
|
+
{"id": "n3", "type": "agent", "agent": "elsabro-executor", "status": "ACTIVE"},
|
|
73
|
+
{"id": "n4", "type": "agent", "agent": "elsabro-qa", "status": "PENDING"}
|
|
74
|
+
],
|
|
75
|
+
"edges": [
|
|
76
|
+
{"from": "n1", "to": "n2"},
|
|
77
|
+
{"from": "n2", "to": "n3"},
|
|
78
|
+
{"from": "n3", "to": "n4"}
|
|
79
|
+
],
|
|
80
|
+
"currentNode": "n3"
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
"state": {
|
|
84
|
+
"variables": {
|
|
85
|
+
"projectName": "my-app",
|
|
86
|
+
"targetFramework": "nextjs",
|
|
87
|
+
"currentFile": "src/components/Auth.tsx"
|
|
88
|
+
},
|
|
89
|
+
"memory": {
|
|
90
|
+
"shortTerm": [],
|
|
91
|
+
"decisions": [],
|
|
92
|
+
"artifacts": []
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
"history": [
|
|
97
|
+
{
|
|
98
|
+
"checkpointId": "chk_2024012015300000",
|
|
99
|
+
"at": "2024-01-20T15:30:00.000Z",
|
|
100
|
+
"event": "INIT",
|
|
101
|
+
"hash": "abc123"
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"checkpointId": "chk_2024012015300001",
|
|
105
|
+
"at": "2024-01-20T15:45:32.000Z",
|
|
106
|
+
"event": "PHASE_COMPLETE",
|
|
107
|
+
"phase": "planning",
|
|
108
|
+
"hash": "def456"
|
|
109
|
+
}
|
|
110
|
+
],
|
|
111
|
+
|
|
112
|
+
"interrupts": {
|
|
113
|
+
"pending": [],
|
|
114
|
+
"history": []
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Tipos de Checkpoints
|
|
122
|
+
|
|
123
|
+
### 1. Auto Checkpoints (Automáticos)
|
|
124
|
+
|
|
125
|
+
Se crean automáticamente en momentos clave:
|
|
126
|
+
|
|
127
|
+
| Trigger | Descripción |
|
|
128
|
+
|---------|-------------|
|
|
129
|
+
| `PHASE_START` | Al iniciar una nueva fase |
|
|
130
|
+
| `PHASE_COMPLETE` | Al completar una fase |
|
|
131
|
+
| `WAVE_COMPLETE` | Al completar una wave paralela |
|
|
132
|
+
| `AGENT_COMPLETE` | Al completar cada agente (opcional) |
|
|
133
|
+
| `INTERVAL` | Cada N minutos (configurable) |
|
|
134
|
+
| `FILE_MODIFY` | Después de modificar archivos importantes |
|
|
135
|
+
|
|
136
|
+
### 2. Manual Checkpoints
|
|
137
|
+
|
|
138
|
+
Creados explícitamente por el usuario o sistema:
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
/elsabro:checkpoint save "antes de refactor"
|
|
142
|
+
/elsabro:checkpoint list
|
|
143
|
+
/elsabro:checkpoint restore chk_abc123
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### 3. Interrupt Checkpoints
|
|
147
|
+
|
|
148
|
+
Creados automáticamente cuando hay interrupciones:
|
|
149
|
+
|
|
150
|
+
- Error no recuperable
|
|
151
|
+
- Timeout de sesión
|
|
152
|
+
- Usuario cancela
|
|
153
|
+
- Sistema requiere input
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## API de Checkpointing
|
|
158
|
+
|
|
159
|
+
### CheckpointManager
|
|
160
|
+
|
|
161
|
+
```javascript
|
|
162
|
+
/**
|
|
163
|
+
* CheckpointManager
|
|
164
|
+
* Gestiona checkpoints persistentes para recuperación y time-travel
|
|
165
|
+
*/
|
|
166
|
+
class CheckpointManager {
|
|
167
|
+
constructor(storageDir = '.planning/checkpoints') {
|
|
168
|
+
this.storageDir = storageDir;
|
|
169
|
+
this.currentCheckpoint = null;
|
|
170
|
+
this.config = {
|
|
171
|
+
autoSaveInterval: 5 * 60 * 1000, // 5 minutos
|
|
172
|
+
maxCheckpoints: 50,
|
|
173
|
+
compressionEnabled: true,
|
|
174
|
+
triggers: ['PHASE_START', 'PHASE_COMPLETE', 'WAVE_COMPLETE', 'INTERRUPT']
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Inicializa o carga checkpoint existente
|
|
180
|
+
*/
|
|
181
|
+
async initialize(sessionId) {
|
|
182
|
+
const existing = await this.findLatestCheckpoint(sessionId);
|
|
183
|
+
|
|
184
|
+
if (existing) {
|
|
185
|
+
return this.loadCheckpoint(existing.checkpointId);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return this.createCheckpoint({
|
|
189
|
+
sessionId,
|
|
190
|
+
execution: { status: 'INIT', currentPhase: null, currentWave: 0 },
|
|
191
|
+
graph: { nodes: [], edges: [], currentNode: null },
|
|
192
|
+
state: { variables: {}, memory: { shortTerm: [], decisions: [], artifacts: [] } },
|
|
193
|
+
history: [],
|
|
194
|
+
interrupts: { pending: [], history: [] }
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Crea un nuevo checkpoint
|
|
200
|
+
*/
|
|
201
|
+
async createCheckpoint(data, event = 'MANUAL') {
|
|
202
|
+
const checkpointId = this.generateCheckpointId();
|
|
203
|
+
const hash = this.computeHash(data);
|
|
204
|
+
|
|
205
|
+
const checkpoint = {
|
|
206
|
+
version: '3.0.0',
|
|
207
|
+
checkpointId,
|
|
208
|
+
createdAt: new Date().toISOString(),
|
|
209
|
+
updatedAt: new Date().toISOString(),
|
|
210
|
+
...data,
|
|
211
|
+
history: [
|
|
212
|
+
...(data.history || []),
|
|
213
|
+
{
|
|
214
|
+
checkpointId,
|
|
215
|
+
at: new Date().toISOString(),
|
|
216
|
+
event,
|
|
217
|
+
hash
|
|
218
|
+
}
|
|
219
|
+
]
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
await this.persistCheckpoint(checkpoint);
|
|
223
|
+
this.currentCheckpoint = checkpoint;
|
|
224
|
+
|
|
225
|
+
return checkpoint;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Actualiza el checkpoint actual
|
|
230
|
+
*/
|
|
231
|
+
async updateCheckpoint(updates, event = 'UPDATE') {
|
|
232
|
+
if (!this.currentCheckpoint) {
|
|
233
|
+
throw new Error('No active checkpoint');
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const updated = {
|
|
237
|
+
...this.currentCheckpoint,
|
|
238
|
+
...updates,
|
|
239
|
+
updatedAt: new Date().toISOString()
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
// Agregar al historial si es evento significativo
|
|
243
|
+
if (this.config.triggers.includes(event)) {
|
|
244
|
+
updated.history.push({
|
|
245
|
+
checkpointId: this.currentCheckpoint.checkpointId,
|
|
246
|
+
at: new Date().toISOString(),
|
|
247
|
+
event,
|
|
248
|
+
hash: this.computeHash(updated)
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
await this.persistCheckpoint(updated);
|
|
253
|
+
this.currentCheckpoint = updated;
|
|
254
|
+
|
|
255
|
+
return updated;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Guarda estado de interrupción para resume
|
|
260
|
+
*/
|
|
261
|
+
async saveInterrupt(reason, context = {}) {
|
|
262
|
+
const interrupt = {
|
|
263
|
+
id: `int_${Date.now()}`,
|
|
264
|
+
reason,
|
|
265
|
+
context,
|
|
266
|
+
savedAt: new Date().toISOString(),
|
|
267
|
+
resumable: true
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
await this.updateCheckpoint({
|
|
271
|
+
execution: {
|
|
272
|
+
...this.currentCheckpoint.execution,
|
|
273
|
+
status: 'PAUSED'
|
|
274
|
+
},
|
|
275
|
+
interrupts: {
|
|
276
|
+
pending: [...this.currentCheckpoint.interrupts.pending, interrupt],
|
|
277
|
+
history: this.currentCheckpoint.interrupts.history
|
|
278
|
+
}
|
|
279
|
+
}, 'INTERRUPT');
|
|
280
|
+
|
|
281
|
+
return interrupt;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Resume desde interrupción
|
|
286
|
+
*/
|
|
287
|
+
async resumeFromInterrupt(interruptId) {
|
|
288
|
+
const interrupt = this.currentCheckpoint.interrupts.pending.find(
|
|
289
|
+
i => i.id === interruptId
|
|
290
|
+
);
|
|
291
|
+
|
|
292
|
+
if (!interrupt) {
|
|
293
|
+
throw new Error(`Interrupt ${interruptId} not found`);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
await this.updateCheckpoint({
|
|
297
|
+
execution: {
|
|
298
|
+
...this.currentCheckpoint.execution,
|
|
299
|
+
status: 'ACTIVE'
|
|
300
|
+
},
|
|
301
|
+
interrupts: {
|
|
302
|
+
pending: this.currentCheckpoint.interrupts.pending.filter(
|
|
303
|
+
i => i.id !== interruptId
|
|
304
|
+
),
|
|
305
|
+
history: [
|
|
306
|
+
...this.currentCheckpoint.interrupts.history,
|
|
307
|
+
{ ...interrupt, resumedAt: new Date().toISOString() }
|
|
308
|
+
]
|
|
309
|
+
}
|
|
310
|
+
}, 'RESUME');
|
|
311
|
+
|
|
312
|
+
return interrupt.context;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Rollback a un checkpoint anterior
|
|
317
|
+
*/
|
|
318
|
+
async rollbackTo(checkpointId) {
|
|
319
|
+
const checkpoint = await this.loadCheckpoint(checkpointId);
|
|
320
|
+
|
|
321
|
+
if (!checkpoint) {
|
|
322
|
+
throw new Error(`Checkpoint ${checkpointId} not found`);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// Marcar el checkpoint actual como rolled back
|
|
326
|
+
if (this.currentCheckpoint) {
|
|
327
|
+
await this.updateCheckpoint({
|
|
328
|
+
execution: {
|
|
329
|
+
...this.currentCheckpoint.execution,
|
|
330
|
+
status: 'ROLLED_BACK'
|
|
331
|
+
}
|
|
332
|
+
}, 'ROLLBACK');
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Crear nuevo checkpoint basado en el histórico
|
|
336
|
+
return this.createCheckpoint({
|
|
337
|
+
...checkpoint,
|
|
338
|
+
history: [
|
|
339
|
+
...checkpoint.history,
|
|
340
|
+
{
|
|
341
|
+
checkpointId: checkpoint.checkpointId,
|
|
342
|
+
at: new Date().toISOString(),
|
|
343
|
+
event: 'ROLLBACK_TARGET',
|
|
344
|
+
hash: this.computeHash(checkpoint)
|
|
345
|
+
}
|
|
346
|
+
]
|
|
347
|
+
}, 'ROLLBACK');
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Lista todos los checkpoints disponibles
|
|
352
|
+
*/
|
|
353
|
+
async listCheckpoints(sessionId, options = {}) {
|
|
354
|
+
const { limit = 20, offset = 0 } = options;
|
|
355
|
+
const files = await this.listCheckpointFiles(sessionId);
|
|
356
|
+
|
|
357
|
+
return files
|
|
358
|
+
.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt))
|
|
359
|
+
.slice(offset, offset + limit)
|
|
360
|
+
.map(f => ({
|
|
361
|
+
checkpointId: f.checkpointId,
|
|
362
|
+
createdAt: f.createdAt,
|
|
363
|
+
event: f.lastEvent,
|
|
364
|
+
status: f.status
|
|
365
|
+
}));
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Time-travel: obtener estado en un punto específico
|
|
370
|
+
*/
|
|
371
|
+
async getStateAt(checkpointId) {
|
|
372
|
+
const checkpoint = await this.loadCheckpoint(checkpointId);
|
|
373
|
+
|
|
374
|
+
return {
|
|
375
|
+
checkpointId,
|
|
376
|
+
timestamp: checkpoint.createdAt,
|
|
377
|
+
execution: checkpoint.execution,
|
|
378
|
+
state: checkpoint.state,
|
|
379
|
+
graph: checkpoint.graph
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Diff entre dos checkpoints
|
|
385
|
+
*/
|
|
386
|
+
async diffCheckpoints(checkpointId1, checkpointId2) {
|
|
387
|
+
const cp1 = await this.loadCheckpoint(checkpointId1);
|
|
388
|
+
const cp2 = await this.loadCheckpoint(checkpointId2);
|
|
389
|
+
|
|
390
|
+
return {
|
|
391
|
+
execution: this.diffObjects(cp1.execution, cp2.execution),
|
|
392
|
+
state: this.diffObjects(cp1.state, cp2.state),
|
|
393
|
+
graph: this.diffObjects(cp1.graph, cp2.graph),
|
|
394
|
+
timeSpan: {
|
|
395
|
+
from: cp1.createdAt,
|
|
396
|
+
to: cp2.createdAt
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// ==================== Helpers ====================
|
|
402
|
+
|
|
403
|
+
generateCheckpointId() {
|
|
404
|
+
const timestamp = new Date().toISOString().replace(/[-:T.Z]/g, '');
|
|
405
|
+
const random = Math.random().toString(36).substring(2, 6);
|
|
406
|
+
return `chk_${timestamp}_${random}`;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
computeHash(data) {
|
|
410
|
+
// Simplified hash - in production use crypto
|
|
411
|
+
return Buffer.from(JSON.stringify(data)).toString('base64').substring(0, 12);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
async persistCheckpoint(checkpoint) {
|
|
415
|
+
const filePath = `${this.storageDir}/${checkpoint.checkpointId}.json`;
|
|
416
|
+
// Write to file system
|
|
417
|
+
return checkpoint;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
async loadCheckpoint(checkpointId) {
|
|
421
|
+
const filePath = `${this.storageDir}/${checkpointId}.json`;
|
|
422
|
+
// Read from file system
|
|
423
|
+
return null;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
async findLatestCheckpoint(sessionId) {
|
|
427
|
+
// Find most recent checkpoint for session
|
|
428
|
+
return null;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
async listCheckpointFiles(sessionId) {
|
|
432
|
+
// List all checkpoint files for session
|
|
433
|
+
return [];
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
diffObjects(obj1, obj2) {
|
|
437
|
+
// Deep diff two objects
|
|
438
|
+
return { added: [], removed: [], changed: [] };
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
---
|
|
444
|
+
|
|
445
|
+
## Integración con ELSABRO
|
|
446
|
+
|
|
447
|
+
### Auto-Checkpoint en Comandos
|
|
448
|
+
|
|
449
|
+
```javascript
|
|
450
|
+
// En cada comando principal de ELSABRO
|
|
451
|
+
async function executeCommand(command, args) {
|
|
452
|
+
const checkpointManager = new CheckpointManager();
|
|
453
|
+
|
|
454
|
+
// Cargar o crear checkpoint
|
|
455
|
+
await checkpointManager.initialize(currentSessionId);
|
|
456
|
+
|
|
457
|
+
try {
|
|
458
|
+
// Checkpoint antes de empezar
|
|
459
|
+
await checkpointManager.updateCheckpoint({
|
|
460
|
+
execution: { status: 'ACTIVE', currentPhase: command }
|
|
461
|
+
}, 'PHASE_START');
|
|
462
|
+
|
|
463
|
+
// Ejecutar comando
|
|
464
|
+
const result = await runCommand(command, args);
|
|
465
|
+
|
|
466
|
+
// Checkpoint al completar
|
|
467
|
+
await checkpointManager.updateCheckpoint({
|
|
468
|
+
execution: { status: 'COMPLETE', currentPhase: command }
|
|
469
|
+
}, 'PHASE_COMPLETE');
|
|
470
|
+
|
|
471
|
+
return result;
|
|
472
|
+
|
|
473
|
+
} catch (error) {
|
|
474
|
+
// Checkpoint de error para recovery
|
|
475
|
+
await checkpointManager.saveInterrupt('ERROR', {
|
|
476
|
+
command,
|
|
477
|
+
args,
|
|
478
|
+
error: error.message,
|
|
479
|
+
stack: error.stack
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
throw error;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
### Resume Automático
|
|
488
|
+
|
|
489
|
+
```javascript
|
|
490
|
+
// Al iniciar /elsabro:resume-work
|
|
491
|
+
async function resumeWork() {
|
|
492
|
+
const checkpointManager = new CheckpointManager();
|
|
493
|
+
const checkpoint = await checkpointManager.initialize(currentSessionId);
|
|
494
|
+
|
|
495
|
+
if (checkpoint.interrupts.pending.length > 0) {
|
|
496
|
+
const lastInterrupt = checkpoint.interrupts.pending[0];
|
|
497
|
+
|
|
498
|
+
console.log(`
|
|
499
|
+
╔════════════════════════════════════════════════════════╗
|
|
500
|
+
║ SESIÓN INTERRUMPIDA DETECTADA ║
|
|
501
|
+
╠════════════════════════════════════════════════════════╣
|
|
502
|
+
║ ║
|
|
503
|
+
║ Última actividad: ${checkpoint.updatedAt} ║
|
|
504
|
+
║ Fase: ${checkpoint.execution.currentPhase} ║
|
|
505
|
+
║ Progreso: ${Math.round(checkpoint.execution.progress * 100)}% ║
|
|
506
|
+
║ ║
|
|
507
|
+
║ Razón de interrupción: ║
|
|
508
|
+
║ > ${lastInterrupt.reason} ║
|
|
509
|
+
║ ║
|
|
510
|
+
╠════════════════════════════════════════════════════════╣
|
|
511
|
+
║ [r] Resumir desde donde quedó ║
|
|
512
|
+
║ [s] Ver estado guardado ║
|
|
513
|
+
║ [n] Empezar de nuevo ║
|
|
514
|
+
╚════════════════════════════════════════════════════════╝
|
|
515
|
+
`);
|
|
516
|
+
|
|
517
|
+
// Si usuario elige resumir
|
|
518
|
+
const context = await checkpointManager.resumeFromInterrupt(lastInterrupt.id);
|
|
519
|
+
return continueExecution(context);
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
return startFresh();
|
|
523
|
+
}
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
---
|
|
527
|
+
|
|
528
|
+
## Comandos de Usuario
|
|
529
|
+
|
|
530
|
+
### /elsabro:checkpoint
|
|
531
|
+
|
|
532
|
+
```
|
|
533
|
+
/elsabro:checkpoint save [nombre] - Guardar checkpoint manual
|
|
534
|
+
/elsabro:checkpoint list - Listar checkpoints
|
|
535
|
+
/elsabro:checkpoint restore <id> - Restaurar checkpoint
|
|
536
|
+
/elsabro:checkpoint diff <id1> <id2> - Comparar checkpoints
|
|
537
|
+
/elsabro:checkpoint delete <id> - Eliminar checkpoint
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
### Ejemplos de Uso
|
|
541
|
+
|
|
542
|
+
```bash
|
|
543
|
+
# Guardar antes de cambio riesgoso
|
|
544
|
+
/elsabro:checkpoint save "antes de refactor auth"
|
|
545
|
+
|
|
546
|
+
# Ver historial
|
|
547
|
+
/elsabro:checkpoint list
|
|
548
|
+
# Output:
|
|
549
|
+
# ID | Fecha | Evento | Estado
|
|
550
|
+
# chk_20240120_a1b2 | 2024-01-20 15:45 | PHASE_COMPLETE | planning
|
|
551
|
+
# chk_20240120_c3d4 | 2024-01-20 15:30 | PHASE_START | research
|
|
552
|
+
# chk_20240120_e5f6 | 2024-01-20 15:00 | INIT | init
|
|
553
|
+
|
|
554
|
+
# Rollback si algo sale mal
|
|
555
|
+
/elsabro:checkpoint restore chk_20240120_c3d4
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
---
|
|
559
|
+
|
|
560
|
+
## Configuración
|
|
561
|
+
|
|
562
|
+
### .planning/checkpoint-config.json
|
|
563
|
+
|
|
564
|
+
```json
|
|
565
|
+
{
|
|
566
|
+
"checkpointing": {
|
|
567
|
+
"enabled": true,
|
|
568
|
+
"autoSave": {
|
|
569
|
+
"enabled": true,
|
|
570
|
+
"intervalMinutes": 5,
|
|
571
|
+
"triggers": ["PHASE_START", "PHASE_COMPLETE", "WAVE_COMPLETE", "FILE_MODIFY"]
|
|
572
|
+
},
|
|
573
|
+
"storage": {
|
|
574
|
+
"directory": ".planning/checkpoints",
|
|
575
|
+
"maxCheckpoints": 50,
|
|
576
|
+
"retentionDays": 30,
|
|
577
|
+
"compression": true
|
|
578
|
+
},
|
|
579
|
+
"recovery": {
|
|
580
|
+
"autoPromptOnStart": true,
|
|
581
|
+
"keepInterruptedSessions": 7
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
---
|
|
588
|
+
|
|
589
|
+
## Notas de Implementación
|
|
590
|
+
|
|
591
|
+
1. **Serialización**: Todo el estado debe ser JSON-serializable
|
|
592
|
+
2. **Idempotencia**: Restaurar un checkpoint debe ser idempotente
|
|
593
|
+
3. **Atomicidad**: Writes deben ser atómicos (write-rename pattern)
|
|
594
|
+
4. **Limpieza**: Auto-cleanup de checkpoints antiguos
|
|
595
|
+
5. **Performance**: Lazy loading de checkpoints grandes
|