vgxness 1.12.0 → 1.14.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/dist/agents/canonical-agent-manifest.js +8 -7
- package/dist/cli/cli-flags.js +3 -3
- package/dist/cli/cli-help.js +4 -4
- package/dist/cli/commands/agent-skill-dispatcher.js +10 -1
- package/dist/mcp/control-plane.js +5 -0
- package/dist/mcp/provider-doctor.js +10 -6
- package/dist/mcp/provider-health-types.js +20 -0
- package/dist/mcp/provider-status.js +18 -6
- package/dist/mcp/schema.js +177 -0
- package/dist/mcp/stdio-server.js +20 -5
- package/dist/mcp/validation.js +6 -0
- package/dist/memory/sqlite/migrations/017_intent_signal_skill_targets.sql +42 -0
- package/dist/orchestrator/natural-language-planner.js +53 -8
- package/dist/sdd/cockpit-read-model.js +2 -0
- package/dist/sdd/sdd-continuation-plan.js +149 -0
- package/dist/sdd/sdd-workflow-service.js +127 -4
- package/dist/skills/boot-seed.js +42 -0
- package/dist/skills/skill-resolver.js +6 -0
- package/dist/skills/skill-seed-service.js +39 -16
- package/docs/sdd-flow.es.md +403 -0
- package/docs/sdd-flow.md +403 -0
- package/package.json +1 -1
- package/seeds/skills/skill-seed-v1.json +73 -1
|
@@ -89,6 +89,7 @@ export class SkillResolver {
|
|
|
89
89
|
...(agent.value?.name !== undefined ? { agentName: agent.value.name } : {}),
|
|
90
90
|
...(input.workflow !== undefined ? { workflow: input.workflow } : {}),
|
|
91
91
|
...(input.phase !== undefined ? { phase: input.phase } : {}),
|
|
92
|
+
...(input.intentSignals !== undefined && input.intentSignals.length > 0 ? { intentSignals: normalizedIntentSignals(input.intentSignals) } : {}),
|
|
92
93
|
...(input.providerAdapter !== undefined ? { providerAdapter: input.providerAdapter } : {}),
|
|
93
94
|
...(input.runId !== undefined ? { runId: input.runId } : {}),
|
|
94
95
|
},
|
|
@@ -121,6 +122,8 @@ export class SkillResolver {
|
|
|
121
122
|
}
|
|
122
123
|
for (const phase of phases)
|
|
123
124
|
targets.push({ targetType: 'workflow-phase', targetKey: phase });
|
|
125
|
+
for (const signal of normalizedIntentSignals(input.intentSignals))
|
|
126
|
+
targets.push({ targetType: 'intent-signal', targetKey: signal });
|
|
124
127
|
if (input.providerAdapter !== undefined)
|
|
125
128
|
targets.push({ targetType: 'provider-adapter', targetKey: input.providerAdapter });
|
|
126
129
|
return dedupeTargets(targets);
|
|
@@ -229,6 +232,9 @@ function phaseTargetKeys(workflow, phase) {
|
|
|
229
232
|
function isSddWorkflow(workflow) {
|
|
230
233
|
return workflow?.trim().toLowerCase() === 'sdd';
|
|
231
234
|
}
|
|
235
|
+
function normalizedIntentSignals(signals) {
|
|
236
|
+
return [...new Set((signals ?? []).map((signal) => signal.trim().toLowerCase()).filter(Boolean))];
|
|
237
|
+
}
|
|
232
238
|
function stringMetadata(value) {
|
|
233
239
|
return typeof value === 'string' && value.trim() ? value : undefined;
|
|
234
240
|
}
|
|
@@ -33,9 +33,8 @@ export class SkillSeedService {
|
|
|
33
33
|
if (!details.ok)
|
|
34
34
|
return details;
|
|
35
35
|
existingVersions.set(seed.name, details.value.versions.some((version) => version.version === seed.version));
|
|
36
|
-
for (const attachment of details.value.attachments)
|
|
36
|
+
for (const attachment of details.value.attachments)
|
|
37
37
|
existingAttachments.set(`${seed.name}:${attachment.targetType}:${attachment.targetKey}`, true);
|
|
38
|
-
}
|
|
39
38
|
}
|
|
40
39
|
}
|
|
41
40
|
const transaction = this.database.transaction(() => {
|
|
@@ -74,11 +73,12 @@ export class SkillSeedService {
|
|
|
74
73
|
const skill = this.registry.getSkillByName(manifest.project, manifest.scope, attachment.skill);
|
|
75
74
|
if (!skill.ok)
|
|
76
75
|
throw new SeedLoadError(skill.error);
|
|
77
|
-
const
|
|
78
|
-
const
|
|
76
|
+
const targetType = attachmentTargetType(attachment);
|
|
77
|
+
const targetKey = attachmentTargetKey(attachment);
|
|
78
|
+
const key = `${attachment.skill}:${targetType}:${targetKey}`;
|
|
79
79
|
const attachInput = {
|
|
80
80
|
skillId: skill.value.id,
|
|
81
|
-
targetType
|
|
81
|
+
targetType,
|
|
82
82
|
targetKey,
|
|
83
83
|
metadata: attachmentMetadata(attachment),
|
|
84
84
|
};
|
|
@@ -138,7 +138,7 @@ function validateManifest(manifest) {
|
|
|
138
138
|
const validation = validateAttachmentSeed(attachment, names);
|
|
139
139
|
if (!validation.ok)
|
|
140
140
|
return validation;
|
|
141
|
-
const key = `${attachment
|
|
141
|
+
const key = `${attachmentTargetType(attachment)}:${attachmentTargetKey(attachment)}:${attachment.skill}`;
|
|
142
142
|
if (attachments.has(key))
|
|
143
143
|
return validationFailure(`Duplicate skill seed attachment: ${key}`);
|
|
144
144
|
attachments.add(key);
|
|
@@ -159,10 +159,18 @@ function validateSkillSeed(skill) {
|
|
|
159
159
|
return rejectUnsupportedNativeInputs(skill.name, skill.metadata);
|
|
160
160
|
}
|
|
161
161
|
function validateAttachmentSeed(attachment, names) {
|
|
162
|
-
if (!attachment.
|
|
163
|
-
return validationFailure(
|
|
164
|
-
|
|
165
|
-
|
|
162
|
+
if (attachment.targetType !== undefined && !isSkillAttachmentTargetType(attachment.targetType))
|
|
163
|
+
return validationFailure(`Skill seed attachment targetType is invalid: ${String(attachment.targetType)}`);
|
|
164
|
+
const targetType = attachmentTargetType(attachment);
|
|
165
|
+
if (targetType === 'workflow-phase') {
|
|
166
|
+
if (!attachment.workflow?.trim())
|
|
167
|
+
return validationFailure('Skill seed attachment workflow is required');
|
|
168
|
+
if (!attachment.phase?.trim())
|
|
169
|
+
return validationFailure('Skill seed attachment phase is required');
|
|
170
|
+
}
|
|
171
|
+
else if (!attachment.targetKey?.trim()) {
|
|
172
|
+
return validationFailure(`Skill seed attachment targetKey is required for ${targetType}`);
|
|
173
|
+
}
|
|
166
174
|
if (!attachment.skill?.trim())
|
|
167
175
|
return validationFailure('Skill seed attachment skill is required');
|
|
168
176
|
if (!names.has(attachment.skill))
|
|
@@ -186,20 +194,35 @@ function rejectUnsupportedNativeInputs(name, metadata) {
|
|
|
186
194
|
function compatibilityFor(seed, attachments) {
|
|
187
195
|
const matching = attachments.filter((attachment) => attachment.skill === seed.name);
|
|
188
196
|
return {
|
|
189
|
-
targets: [
|
|
197
|
+
targets: [...new Set(matching.map(attachmentTargetType))],
|
|
190
198
|
adapters: ['opencode'],
|
|
191
|
-
workflows: [...new Set(matching.map((attachment) => attachment.workflow))],
|
|
192
|
-
phases: [...new Set(matching.map((attachment) => attachment.phase))],
|
|
199
|
+
workflows: [...new Set(matching.map((attachment) => attachment.workflow).filter((workflow) => workflow !== undefined))],
|
|
200
|
+
phases: [...new Set(matching.map((attachment) => attachment.phase).filter((phase) => phase !== undefined))],
|
|
193
201
|
};
|
|
194
202
|
}
|
|
195
203
|
function attachmentMetadata(attachment) {
|
|
196
|
-
|
|
204
|
+
const metadata = {
|
|
197
205
|
...(attachment.metadata ?? {}),
|
|
198
206
|
...(attachment.order !== undefined ? { order: attachment.order } : {}),
|
|
199
207
|
seededBy: 'vgxness',
|
|
200
|
-
|
|
201
|
-
|
|
208
|
+
targetType: attachmentTargetType(attachment),
|
|
209
|
+
targetKey: attachmentTargetKey(attachment),
|
|
202
210
|
};
|
|
211
|
+
if (attachment.workflow !== undefined)
|
|
212
|
+
metadata.workflow = attachment.workflow;
|
|
213
|
+
if (attachment.phase !== undefined)
|
|
214
|
+
metadata.phase = attachment.phase;
|
|
215
|
+
return metadata;
|
|
216
|
+
}
|
|
217
|
+
function attachmentTargetType(attachment) {
|
|
218
|
+
return attachment.targetType ?? 'workflow-phase';
|
|
219
|
+
}
|
|
220
|
+
function attachmentTargetKey(attachment) {
|
|
221
|
+
const targetType = attachmentTargetType(attachment);
|
|
222
|
+
return targetType === 'workflow-phase' ? `${attachment.workflow}:${attachment.phase}` : attachment.targetKey ?? '';
|
|
223
|
+
}
|
|
224
|
+
function isSkillAttachmentTargetType(value) {
|
|
225
|
+
return value === 'agent' || value === 'subagent' || value === 'workflow-phase' || value === 'provider-adapter' || value === 'intent-signal';
|
|
203
226
|
}
|
|
204
227
|
function validationFailure(message) {
|
|
205
228
|
return { ok: false, error: { code: 'validation_failed', message } };
|
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
# Flujo SDD
|
|
2
|
+
|
|
3
|
+
> Versión en inglés: [SDD Flow](./sdd-flow.md).
|
|
4
|
+
|
|
5
|
+
> **Alcance:** este documento explica el flujo SDD completo en VGXNESS: desde una intención humana, pasando por artefactos de planeación, progreso de implementación, verificación y archivo. Es una guía práctica para operadores y acompaña a [Architecture](./architecture.md), [Safety](./safety.md), [CLI](./cli.md) y [MCP tools](./mcp.md).
|
|
6
|
+
|
|
7
|
+
VGXNESS trata SDD como estado real del producto, no solo como instrucciones para agentes. Cada fase produce un artefacto guardado localmente en SQLite, y el avance entre fases se controla mediante readiness explícito y, cuando aplica, aceptación humana explícita.
|
|
8
|
+
|
|
9
|
+
Las fases canónicas de SDD son:
|
|
10
|
+
|
|
11
|
+
```text
|
|
12
|
+
explore → proposal → spec → design → tasks → apply-progress → verify → archive
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Modelo mental
|
|
16
|
+
|
|
17
|
+
```text
|
|
18
|
+
Intención humana
|
|
19
|
+
↓
|
|
20
|
+
Conversación en OpenCode / acción del operador por CLI
|
|
21
|
+
↓
|
|
22
|
+
Superficie VGXNESS MCP o CLI
|
|
23
|
+
↓
|
|
24
|
+
Servicios del control plane
|
|
25
|
+
↓
|
|
26
|
+
Artefactos SDD, runs, memoria y checkpoints en SQLite
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
La separación importante es:
|
|
30
|
+
|
|
31
|
+
```text
|
|
32
|
+
Conversación ≠ estado
|
|
33
|
+
Draft ≠ aceptación
|
|
34
|
+
Plan ≠ ejecución
|
|
35
|
+
Preflight ≠ permiso automático
|
|
36
|
+
Provider status ≠ escritura de config del provider
|
|
37
|
+
CLI/MCP ≠ reglas de negocio duplicadas
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## 1. Intención humana
|
|
41
|
+
|
|
42
|
+
El flujo empieza cuando el humano expresa un objetivo, normalmente dentro de OpenCode después de instalar el MCP de VGXNESS.
|
|
43
|
+
|
|
44
|
+
Ejemplo:
|
|
45
|
+
|
|
46
|
+
```text
|
|
47
|
+
Mejorar el flujo de recuperación de runs interrumpidos para que VGXNESS sugiera cómo continuar de forma segura.
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Para cambios sustanciales, VGXNESS no debería saltar directo al código. El camino seguro es inspeccionar el estado SDD actual y elegir la siguiente fase válida.
|
|
51
|
+
|
|
52
|
+
Superficies útiles:
|
|
53
|
+
|
|
54
|
+
```text
|
|
55
|
+
sdd_status
|
|
56
|
+
sdd_next
|
|
57
|
+
sdd_continue
|
|
58
|
+
agent_resolve
|
|
59
|
+
agent_activate
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Equivalentes por CLI para setup, diagnóstico, recuperación y scripting:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
vgxness sdd status --project <project> --change <change>
|
|
66
|
+
vgxness sdd next --project <project> --change <change>
|
|
67
|
+
vgxness sdd continue --project <project> --change <change>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## 2. `explore`: entender antes de elegir solución
|
|
71
|
+
|
|
72
|
+
Objetivo: investigar el problema, los límites actuales del código, decisiones previas, riesgos y posibles enfoques sin comprometerse todavía con una implementación.
|
|
73
|
+
|
|
74
|
+
Preguntas típicas:
|
|
75
|
+
|
|
76
|
+
- ¿Dónde vive la lógica relevante?
|
|
77
|
+
- ¿Qué herramientas CLI y MCP ya existen?
|
|
78
|
+
- ¿Qué servicio es dueño de la regla de dominio?
|
|
79
|
+
- ¿Qué restricciones de safety o storage aplican?
|
|
80
|
+
- ¿Qué riesgos harían difícil revisar el cambio?
|
|
81
|
+
|
|
82
|
+
Para recuperación de runs interrumpidos, la exploración podría revisar:
|
|
83
|
+
|
|
84
|
+
```text
|
|
85
|
+
src/runs/*
|
|
86
|
+
src/sdd/*
|
|
87
|
+
src/mcp/control-plane.ts
|
|
88
|
+
src/cli/commands/*
|
|
89
|
+
docs/*
|
|
90
|
+
test/*
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
El artefacto de fase se guarda con el topic key canónico:
|
|
94
|
+
|
|
95
|
+
```text
|
|
96
|
+
sdd/{change}/explore
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Un agente puede marcar el artefacto como ready, pero readiness no es aceptación.
|
|
100
|
+
|
|
101
|
+
## 3. Aceptación humana de `explore`
|
|
102
|
+
|
|
103
|
+
VGXNESS separa deliberadamente contenido generado y aprobación humana:
|
|
104
|
+
|
|
105
|
+
```text
|
|
106
|
+
draft / ready ≠ accepted
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Solo una decisión humana de aceptación debería avanzar trabajo posterior que esté gobernado por gates. Esto evita que un agente apruebe silenciosamente su propia dirección.
|
|
110
|
+
|
|
111
|
+
Ejemplo CLI:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
vgxness sdd accept-artifact --project <project> --change <change> --phase explore
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## 4. `proposal`: elegir dirección de producto
|
|
118
|
+
|
|
119
|
+
Objetivo: definir qué cambio debe hacerse y por qué.
|
|
120
|
+
|
|
121
|
+
Una buena propuesta responde:
|
|
122
|
+
|
|
123
|
+
- ¿Qué problema estamos resolviendo?
|
|
124
|
+
- ¿Quién se beneficia?
|
|
125
|
+
- ¿Qué está dentro del alcance?
|
|
126
|
+
- ¿Qué queda explícitamente fuera del alcance?
|
|
127
|
+
- ¿Qué riesgos o tradeoffs existen?
|
|
128
|
+
- ¿Cómo sabremos que funcionó?
|
|
129
|
+
|
|
130
|
+
Ejemplo de resumen de propuesta:
|
|
131
|
+
|
|
132
|
+
```text
|
|
133
|
+
Agregar una superficie read-only de continuación para runs interrumpidos que combine runs failed/blocked/needs-human, el último checkpoint, la fase SDD asociada y una siguiente acción recomendada segura.
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Esto sigue siendo definición de dirección, no implementación.
|
|
137
|
+
|
|
138
|
+
## 5. Aceptación humana de `proposal`
|
|
139
|
+
|
|
140
|
+
La propuesta es el contrato principal de alcance. Si es demasiado amplia, la implementación y la revisión se vuelven riesgosas.
|
|
141
|
+
|
|
142
|
+
Pregunta recomendada para revisión:
|
|
143
|
+
|
|
144
|
+
```text
|
|
145
|
+
¿Esto puede revisarse como un slice coherente o deberíamos dividirlo?
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Por ejemplo, un primer slice más seguro puede ser:
|
|
149
|
+
|
|
150
|
+
```text
|
|
151
|
+
Diagnóstico read-only de runs interrumpidos antes de cualquier recuperación automática o ejecución de provider.
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Después de aceptar exactamente la propuesta, se pueden generar borradores downstream de planeación, pero esos artefactos siguen siendo drafts hasta que se revisen y acepten según la gobernanza.
|
|
155
|
+
|
|
156
|
+
## 6. `spec`: definir comportamiento observable
|
|
157
|
+
|
|
158
|
+
Objetivo: especificar qué debe hacer el sistema sin sobreadaptarse a detalles de implementación.
|
|
159
|
+
|
|
160
|
+
Para recuperación de runs interrumpidos, una spec podría requerir:
|
|
161
|
+
|
|
162
|
+
- Runs con estado `failed`, `blocked` o `needs-human` aparecen como candidatos de recuperación.
|
|
163
|
+
- Cada candidato incluye run id, proyecto, workflow, fase, estado, último checkpoint, razón de fallo o bloqueo y siguiente acción recomendada.
|
|
164
|
+
- El estado vacío es explícito cuando no existen runs interrumpidos.
|
|
165
|
+
- La superficie es read-only y no reanuda providers ni muta estado de runs.
|
|
166
|
+
|
|
167
|
+
La spec debe incluir casos límite, por ejemplo:
|
|
168
|
+
|
|
169
|
+
- muchos runs interrumpidos;
|
|
170
|
+
- runs sin checkpoints;
|
|
171
|
+
- runs de otro proyecto;
|
|
172
|
+
- runs ligados a fases SDD ya aceptadas;
|
|
173
|
+
- metadata incompleta o inconsistente.
|
|
174
|
+
|
|
175
|
+
## 7. `design`: decidir cómo construirlo
|
|
176
|
+
|
|
177
|
+
Objetivo: conectar la spec con la arquitectura existente.
|
|
178
|
+
|
|
179
|
+
Un buen diseño identifica:
|
|
180
|
+
|
|
181
|
+
- límites de servicio;
|
|
182
|
+
- cambios de repository/query;
|
|
183
|
+
- superficies CLI y MCP;
|
|
184
|
+
- agregados de schema;
|
|
185
|
+
- comportamiento de renderers;
|
|
186
|
+
- tests;
|
|
187
|
+
- necesidad de migraciones, si aplica;
|
|
188
|
+
- invariantes de safety.
|
|
189
|
+
|
|
190
|
+
Ejemplo de diseño:
|
|
191
|
+
|
|
192
|
+
```text
|
|
193
|
+
Agregar un servicio de candidatos de resume respaldado por el repositorio de runs.
|
|
194
|
+
Exponer herramientas MCP read-only para listar e inspeccionar candidatos.
|
|
195
|
+
Exponer un comando CLI de recuperación/status que use el mismo servicio.
|
|
196
|
+
Mantener la generación de recomendaciones como no-mutante.
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Reglas arquitectónicas que preservar:
|
|
200
|
+
|
|
201
|
+
- CLI y MCP deben compartir servicios de dominio.
|
|
202
|
+
- Los renderers no deben reimplementar reglas de negocio.
|
|
203
|
+
- Las herramientas read-only deben seguir siendo no-mutantes.
|
|
204
|
+
- Las escrituras de configuración de provider requieren consentimiento humano explícito.
|
|
205
|
+
- Los artefactos SDD siguen respaldados por SQLite; no crear `openspec/`.
|
|
206
|
+
|
|
207
|
+
## 8. `tasks`: hacer el diseño revisable
|
|
208
|
+
|
|
209
|
+
Objetivo: dividir el diseño en pasos pequeños de implementación.
|
|
210
|
+
|
|
211
|
+
Ejemplo de desglose:
|
|
212
|
+
|
|
213
|
+
```text
|
|
214
|
+
1. Agregar query de repositorio para runs interrumpidos.
|
|
215
|
+
2. Agregar servicio de candidatos de resume.
|
|
216
|
+
3. Agregar schema MCP y herramientas read-only.
|
|
217
|
+
4. Agregar comando CLI o extender la superficie existente de recovery/status.
|
|
218
|
+
5. Agregar salida de renderer para estados vacío, único candidato y múltiples candidatos.
|
|
219
|
+
6. Agregar tests enfocados de servicio.
|
|
220
|
+
7. Agregar tests de contrato CLI/MCP.
|
|
221
|
+
8. Actualizar docs si cambia comportamiento visible para el usuario.
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
Buenas tasks son pequeñas, testeables y fáciles de revisar.
|
|
225
|
+
|
|
226
|
+
## 9. `apply-progress`: implementar con progreso trazable
|
|
227
|
+
|
|
228
|
+
Objetivo: hacer el cambio de código mientras se registra qué cambió, qué falta y qué evidencia existe.
|
|
229
|
+
|
|
230
|
+
Antes de implementar, revisar tamaño y riesgo:
|
|
231
|
+
|
|
232
|
+
- ¿El cambio toca varios subsistemas?
|
|
233
|
+
- ¿Altera storage o migraciones?
|
|
234
|
+
- ¿Cambia schemas MCP?
|
|
235
|
+
- ¿Cambia comportamiento de safety?
|
|
236
|
+
- ¿El diff es demasiado grande para una sola revisión?
|
|
237
|
+
|
|
238
|
+
Si el cambio es demasiado amplio, hay que dividirlo antes de implementar.
|
|
239
|
+
|
|
240
|
+
Durante la implementación, `apply-progress` debería capturar:
|
|
241
|
+
|
|
242
|
+
- trabajo completado;
|
|
243
|
+
- archivos o módulos modificados;
|
|
244
|
+
- tareas pendientes;
|
|
245
|
+
- resultados de tests;
|
|
246
|
+
- blockers conocidos;
|
|
247
|
+
- desviaciones del diseño aceptado.
|
|
248
|
+
|
|
249
|
+
`apply-progress` es un registro de progreso, no prueba de que la implementación sea correcta.
|
|
250
|
+
|
|
251
|
+
## 10. Preflight para operaciones riesgosas
|
|
252
|
+
|
|
253
|
+
VGXNESS usa preflight checks para mantener explícitas las operaciones riesgosas.
|
|
254
|
+
|
|
255
|
+
Ejemplos de categorías riesgosas:
|
|
256
|
+
|
|
257
|
+
```text
|
|
258
|
+
implementation-edit
|
|
259
|
+
shell
|
|
260
|
+
test-run
|
|
261
|
+
install
|
|
262
|
+
git-write
|
|
263
|
+
provider-tool
|
|
264
|
+
secrets
|
|
265
|
+
external-directory
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
Ejemplo conceptual MCP:
|
|
269
|
+
|
|
270
|
+
```text
|
|
271
|
+
run_preflight({
|
|
272
|
+
category: "test-run",
|
|
273
|
+
operation: "bun run verify:test",
|
|
274
|
+
workflow: "sdd",
|
|
275
|
+
phase: "apply-progress"
|
|
276
|
+
})
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Preflight es control consultivo/de planeación. No significa que la operación esté automáticamente aprobada o ejecutada.
|
|
280
|
+
|
|
281
|
+
## 11. `verify`: comprobar la implementación independientemente
|
|
282
|
+
|
|
283
|
+
Objetivo: verificar la implementación contra la spec y el design aceptados, idealmente con contexto fresco de revisor/agente para cambios no triviales.
|
|
284
|
+
|
|
285
|
+
La verificación debe revisar:
|
|
286
|
+
|
|
287
|
+
- que la spec se cumpla;
|
|
288
|
+
- que los límites del diseño se respeten o las desviaciones estén justificadas;
|
|
289
|
+
- que los tests relevantes pasen;
|
|
290
|
+
- que superficies read-only no se hayan vuelto mutantes;
|
|
291
|
+
- que setup/config de providers sigan requiriendo consentimiento explícito;
|
|
292
|
+
- que storage, CLI y MCP sigan siendo consistentes.
|
|
293
|
+
|
|
294
|
+
Comandos típicos de verificación del repo:
|
|
295
|
+
|
|
296
|
+
```bash
|
|
297
|
+
bun run verify:typecheck
|
|
298
|
+
bun run verify:test
|
|
299
|
+
bun run verify:bun-sqlite
|
|
300
|
+
bun run package:bun:evidence
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
No todo cambio pequeño de docs o copy necesita la suite completa. Cambios de storage, schema CLI/MCP, setup de providers o packaging merecen verificación más estricta.
|
|
304
|
+
|
|
305
|
+
## 12. `archive`: cerrar el cambio con contexto durable
|
|
306
|
+
|
|
307
|
+
Objetivo: preservar qué ocurrió para que trabajo futuro pueda recuperar contexto sin releer todo el hilo o diff.
|
|
308
|
+
|
|
309
|
+
Un artefacto de archive debería incluir:
|
|
310
|
+
|
|
311
|
+
- resultado final;
|
|
312
|
+
- comportamiento visible que cambió;
|
|
313
|
+
- archivos o módulos clave tocados;
|
|
314
|
+
- verificación realizada;
|
|
315
|
+
- riesgos residuales;
|
|
316
|
+
- trabajo de seguimiento;
|
|
317
|
+
- notas de rollback o recuperación, si aplica.
|
|
318
|
+
|
|
319
|
+
Ejemplo de resumen archive:
|
|
320
|
+
|
|
321
|
+
```text
|
|
322
|
+
Change: recover-runs
|
|
323
|
+
Outcome: implemented a read-only interrupted-run recovery surface.
|
|
324
|
+
Verification: typecheck and focused service/CLI tests passed.
|
|
325
|
+
Residual risk: full package evidence was not run locally.
|
|
326
|
+
Follow-up: consider TUI integration after the CLI/MCP flow stabilizes.
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
## Boceto del flujo de herramientas
|
|
330
|
+
|
|
331
|
+
Dentro de OpenCode, el flujo normalmente se ve así conceptualmente:
|
|
332
|
+
|
|
333
|
+
```text
|
|
334
|
+
sdd_status
|
|
335
|
+
↓
|
|
336
|
+
sdd_continue
|
|
337
|
+
↓
|
|
338
|
+
agent_activate(explore)
|
|
339
|
+
↓
|
|
340
|
+
sdd_save_artifact(explore)
|
|
341
|
+
↓
|
|
342
|
+
sdd_ready(explore)
|
|
343
|
+
↓
|
|
344
|
+
humano acepta explore
|
|
345
|
+
↓
|
|
346
|
+
agent_activate(proposal)
|
|
347
|
+
↓
|
|
348
|
+
sdd_save_artifact(proposal)
|
|
349
|
+
↓
|
|
350
|
+
sdd_ready(proposal)
|
|
351
|
+
↓
|
|
352
|
+
humano acepta proposal
|
|
353
|
+
↓
|
|
354
|
+
agent_activate(spec)
|
|
355
|
+
↓
|
|
356
|
+
agent_activate(design)
|
|
357
|
+
↓
|
|
358
|
+
agent_activate(tasks)
|
|
359
|
+
↓
|
|
360
|
+
humano revisa/acepta artefactos con gate
|
|
361
|
+
↓
|
|
362
|
+
agent_activate(apply)
|
|
363
|
+
↓
|
|
364
|
+
run_preflight(...)
|
|
365
|
+
↓
|
|
366
|
+
sdd_save_artifact(apply-progress)
|
|
367
|
+
↓
|
|
368
|
+
agent_activate(verify)
|
|
369
|
+
↓
|
|
370
|
+
sdd_save_artifact(verify)
|
|
371
|
+
↓
|
|
372
|
+
archive
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
## Por qué existe este flujo
|
|
376
|
+
|
|
377
|
+
Un flujo agentic ingenuo sería:
|
|
378
|
+
|
|
379
|
+
```text
|
|
380
|
+
leer código → editar código → correr tests → decir terminado
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
VGXNESS usa SDD para hacerlo más seguro:
|
|
384
|
+
|
|
385
|
+
```text
|
|
386
|
+
entender objetivo
|
|
387
|
+
↓
|
|
388
|
+
elegir alcance
|
|
389
|
+
↓
|
|
390
|
+
especificar comportamiento
|
|
391
|
+
↓
|
|
392
|
+
diseñar el cambio
|
|
393
|
+
↓
|
|
394
|
+
dividir en tareas
|
|
395
|
+
↓
|
|
396
|
+
implementar con preflight y tracking de progreso
|
|
397
|
+
↓
|
|
398
|
+
verificar independientemente
|
|
399
|
+
↓
|
|
400
|
+
archivar contexto durable
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
La estructura inicial cuesta un poco de tiempo, pero reduce scope creep oculto, diffs imposibles de revisar, automatización insegura y pérdida de contexto.
|