zugzbot-sdd 1.5.34 → 1.5.36
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.
|
@@ -44,7 +44,8 @@ export default tool({
|
|
|
44
44
|
category: tool.schema.string().optional().describe("Categoría del aprendizaje para el cerebro"),
|
|
45
45
|
tag: tool.schema.string().optional().describe("Tag corto del aprendizaje para el cerebro"),
|
|
46
46
|
problem: tool.schema.string().optional().describe("Problema resuelto (máx 120 caracteres)"),
|
|
47
|
-
solution: tool.schema.string().optional().describe("Solución aplicada (máx 300 caracteres)")
|
|
47
|
+
solution: tool.schema.string().optional().describe("Solución aplicada (máx 300 caracteres)"),
|
|
48
|
+
bypassPendingTasks: tool.schema.boolean().optional().default(false).describe("Ignorar/Bypassear la verificación de tareas pendientes en el lockfile si el usuario aprobó manualmente o es un flujo QA Manual")
|
|
48
49
|
},
|
|
49
50
|
async execute(args, context) {
|
|
50
51
|
const projectRoot = context.worktree || context.directory;
|
|
@@ -57,11 +58,23 @@ export default tool({
|
|
|
57
58
|
if (fs.existsSync(lockfilePath)) {
|
|
58
59
|
try {
|
|
59
60
|
const lockfile = JSON.parse(fs.readFileSync(lockfilePath, "utf-8"));
|
|
61
|
+
const isManualQa = lockfile.qa_manual === true || lockfile.manual_qa === true;
|
|
62
|
+
const shouldBypass = args.bypassPendingTasks === true || isManualQa;
|
|
60
63
|
if (lockfile.tasks && Array.isArray(lockfile.tasks) && lockfile.tasks.length > 0) {
|
|
61
64
|
const pendingTasks = lockfile.tasks.filter((t) => t.status === "pending");
|
|
62
65
|
if (pendingTasks.length > 0) {
|
|
63
|
-
|
|
64
|
-
|
|
66
|
+
if (shouldBypass) {
|
|
67
|
+
// Auto-completar tareas en caliente para dejar el lockfile limpio
|
|
68
|
+
lockfile.tasks.forEach((t) => {
|
|
69
|
+
if (t.status === "pending")
|
|
70
|
+
t.status = "completed";
|
|
71
|
+
});
|
|
72
|
+
fs.writeFileSync(lockfilePath, JSON.stringify(lockfile, null, 2), "utf-8");
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
const pendingList = pendingTasks.map((t) => ` ⚠️ [${t.id}] ${t.desc}`).join("\n");
|
|
76
|
+
return `[SDD Archive Blocked] No se puede cerrar el ciclo. Hay ${pendingTasks.length} tarea(s) pendiente(s):\n${pendingList}\n\nPor favor, completa todas las tareas o fuerza el cierre con aprobación explícita del usuario.`;
|
|
77
|
+
}
|
|
65
78
|
}
|
|
66
79
|
}
|
|
67
80
|
}
|
|
@@ -161,15 +174,7 @@ export default tool({
|
|
|
161
174
|
catch (e) {
|
|
162
175
|
report.push(`⚠️ Sincronización automática de habilidades fallida o no disponible: ${e.message || e}`);
|
|
163
176
|
}
|
|
164
|
-
// 4.
|
|
165
|
-
const tempCommitMsgPath = path.join(projectRoot, ".openspec", `commit_msg_${args.changeName}.txt`);
|
|
166
|
-
try {
|
|
167
|
-
fs.writeFileSync(tempCommitMsgPath, args.commitMessage + "\n", "utf-8");
|
|
168
|
-
report.push(`✓ Archivo commit_message.txt generado en location temporal`);
|
|
169
|
-
}
|
|
170
|
-
catch (e) {
|
|
171
|
-
report.push(`⚠️ Error escribiendo commit_message.txt: ${e.message}`);
|
|
172
|
-
}
|
|
177
|
+
// 4. No temporary file is needed on disk, we feed it directly to git commit stdin in step 7.
|
|
173
178
|
// 5. Resetear el lockfile a idle (ANTES del commit para incluirlo en el cierre)
|
|
174
179
|
if (fs.existsSync(lockfilePath)) {
|
|
175
180
|
try {
|
|
@@ -264,20 +269,13 @@ Este reporte detalla la telemetría de tokens y coste financiero en USD acumulad
|
|
|
264
269
|
if (fs.existsSync(path.join(projectRoot, ".git"))) {
|
|
265
270
|
try {
|
|
266
271
|
execSync("git add .", { cwd: projectRoot, stdio: "ignore" });
|
|
267
|
-
execSync(
|
|
272
|
+
execSync("git commit -F -", { cwd: projectRoot, input: args.commitMessage + "\n", stdio: ["pipe", "ignore", "ignore"] });
|
|
268
273
|
report.push(`✓ Commit de Git ejecutado usando el mensaje semántico (incluye archivos archivados)`);
|
|
269
274
|
}
|
|
270
275
|
catch (e) {
|
|
271
276
|
report.push(`⚠️ Git Commit falló o no había cambios pendientes de código: ${e.message}`);
|
|
272
277
|
}
|
|
273
278
|
}
|
|
274
|
-
// 8. Limpiar archivo temporal de commit message
|
|
275
|
-
try {
|
|
276
|
-
if (fs.existsSync(tempCommitMsgPath)) {
|
|
277
|
-
fs.unlinkSync(tempCommitMsgPath);
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
catch (e) { }
|
|
281
279
|
report.push("━━━ finalizado con éxito absoluto ━━━");
|
|
282
280
|
return report.join("\n");
|
|
283
281
|
}
|
package/package.json
CHANGED
|
@@ -43,7 +43,8 @@ export default tool({
|
|
|
43
43
|
category: tool.schema.string().optional().describe("Categoría del aprendizaje para el cerebro"),
|
|
44
44
|
tag: tool.schema.string().optional().describe("Tag corto del aprendizaje para el cerebro"),
|
|
45
45
|
problem: tool.schema.string().optional().describe("Problema resuelto (máx 120 caracteres)"),
|
|
46
|
-
solution: tool.schema.string().optional().describe("Solución aplicada (máx 300 caracteres)")
|
|
46
|
+
solution: tool.schema.string().optional().describe("Solución aplicada (máx 300 caracteres)"),
|
|
47
|
+
bypassPendingTasks: tool.schema.boolean().optional().default(false).describe("Ignorar/Bypassear la verificación de tareas pendientes en el lockfile si el usuario aprobó manualmente o es un flujo QA Manual")
|
|
47
48
|
},
|
|
48
49
|
async execute(args, context) {
|
|
49
50
|
const projectRoot = context.worktree || context.directory
|
|
@@ -58,11 +59,22 @@ export default tool({
|
|
|
58
59
|
if (fs.existsSync(lockfilePath)) {
|
|
59
60
|
try {
|
|
60
61
|
const lockfile = JSON.parse(fs.readFileSync(lockfilePath, "utf-8"))
|
|
62
|
+
const isManualQa = lockfile.qa_manual === true || lockfile.manual_qa === true
|
|
63
|
+
const shouldBypass = args.bypassPendingTasks === true || isManualQa
|
|
64
|
+
|
|
61
65
|
if (lockfile.tasks && Array.isArray(lockfile.tasks) && lockfile.tasks.length > 0) {
|
|
62
66
|
const pendingTasks = lockfile.tasks.filter((t: any) => t.status === "pending")
|
|
63
67
|
if (pendingTasks.length > 0) {
|
|
64
|
-
|
|
65
|
-
|
|
68
|
+
if (shouldBypass) {
|
|
69
|
+
// Auto-completar tareas en caliente para dejar el lockfile limpio
|
|
70
|
+
lockfile.tasks.forEach((t: any) => {
|
|
71
|
+
if (t.status === "pending") t.status = "completed"
|
|
72
|
+
})
|
|
73
|
+
fs.writeFileSync(lockfilePath, JSON.stringify(lockfile, null, 2), "utf-8")
|
|
74
|
+
} else {
|
|
75
|
+
const pendingList = pendingTasks.map((t: any) => ` ⚠️ [${t.id}] ${t.desc}`).join("\n")
|
|
76
|
+
return `[SDD Archive Blocked] No se puede cerrar el ciclo. Hay ${pendingTasks.length} tarea(s) pendiente(s):\n${pendingList}\n\nPor favor, completa todas las tareas o fuerza el cierre con aprobación explícita del usuario.`
|
|
77
|
+
}
|
|
66
78
|
}
|
|
67
79
|
}
|
|
68
80
|
} catch (e: any) {}
|
|
@@ -160,14 +172,7 @@ export default tool({
|
|
|
160
172
|
report.push(`⚠️ Sincronización automática de habilidades fallida o no disponible: ${e.message || e}`)
|
|
161
173
|
}
|
|
162
174
|
|
|
163
|
-
// 4.
|
|
164
|
-
const tempCommitMsgPath = path.join(projectRoot, ".openspec", `commit_msg_${args.changeName}.txt`)
|
|
165
|
-
try {
|
|
166
|
-
fs.writeFileSync(tempCommitMsgPath, args.commitMessage + "\n", "utf-8")
|
|
167
|
-
report.push(`✓ Archivo commit_message.txt generado en location temporal`)
|
|
168
|
-
} catch (e: any) {
|
|
169
|
-
report.push(`⚠️ Error escribiendo commit_message.txt: ${e.message}`)
|
|
170
|
-
}
|
|
175
|
+
// 4. No temporary file is needed on disk, we feed it directly to git commit stdin in step 7.
|
|
171
176
|
|
|
172
177
|
// 5. Resetear el lockfile a idle (ANTES del commit para incluirlo en el cierre)
|
|
173
178
|
if (fs.existsSync(lockfilePath)) {
|
|
@@ -265,20 +270,13 @@ Este reporte detalla la telemetría de tokens y coste financiero en USD acumulad
|
|
|
265
270
|
if (fs.existsSync(path.join(projectRoot, ".git"))) {
|
|
266
271
|
try {
|
|
267
272
|
execSync("git add .", { cwd: projectRoot, stdio: "ignore" })
|
|
268
|
-
execSync(
|
|
273
|
+
execSync("git commit -F -", { cwd: projectRoot, input: args.commitMessage + "\n", stdio: ["pipe", "ignore", "ignore"] })
|
|
269
274
|
report.push(`✓ Commit de Git ejecutado usando el mensaje semántico (incluye archivos archivados)`)
|
|
270
275
|
} catch (e: any) {
|
|
271
276
|
report.push(`⚠️ Git Commit falló o no había cambios pendientes de código: ${e.message}`)
|
|
272
277
|
}
|
|
273
278
|
}
|
|
274
279
|
|
|
275
|
-
// 8. Limpiar archivo temporal de commit message
|
|
276
|
-
try {
|
|
277
|
-
if (fs.existsSync(tempCommitMsgPath)) {
|
|
278
|
-
fs.unlinkSync(tempCommitMsgPath)
|
|
279
|
-
}
|
|
280
|
-
} catch (e: any) {}
|
|
281
|
-
|
|
282
280
|
report.push("━━━ finalizado con éxito absoluto ━━━")
|
|
283
281
|
return report.join("\n")
|
|
284
282
|
}
|