refacil-sdd-ai 4.2.3 → 4.3.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.
Files changed (47) hide show
  1. package/README.md +239 -214
  2. package/agents/auditor.md +182 -184
  3. package/agents/debugger.md +201 -204
  4. package/agents/implementer.md +150 -149
  5. package/agents/investigator.md +80 -89
  6. package/agents/proposer.md +219 -124
  7. package/agents/tester.md +140 -144
  8. package/agents/validator.md +153 -145
  9. package/bin/cli.js +158 -116
  10. package/lib/bus/askFulfillment.js +17 -17
  11. package/lib/bus/broker.js +599 -599
  12. package/lib/bus/ui/app.js +318 -318
  13. package/lib/commands/sdd.js +433 -0
  14. package/lib/hooks.js +236 -236
  15. package/lib/installer.js +55 -1
  16. package/lib/methodology-migration-pending.js +101 -136
  17. package/package.json +4 -6
  18. package/skills/apply/SKILL.md +122 -120
  19. package/skills/archive/SKILL.md +101 -107
  20. package/skills/ask/SKILL.md +78 -78
  21. package/skills/attend/SKILL.md +70 -70
  22. package/skills/bug/SKILL.md +121 -117
  23. package/skills/explore/SKILL.md +61 -63
  24. package/skills/guide/SKILL.md +79 -79
  25. package/skills/inbox/SKILL.md +43 -43
  26. package/skills/join/SKILL.md +82 -82
  27. package/skills/prereqs/BUS-CROSS-REPO.md +55 -55
  28. package/skills/prereqs/METHODOLOGY-CONTRACT.md +122 -115
  29. package/skills/prereqs/SKILL.md +30 -37
  30. package/skills/propose/SKILL.md +91 -102
  31. package/skills/reply/SKILL.md +44 -44
  32. package/skills/review/SKILL.md +135 -126
  33. package/skills/review/checklist-back.md +92 -92
  34. package/skills/review/checklist-front.md +72 -72
  35. package/skills/review/checklist.md +114 -114
  36. package/skills/say/SKILL.md +38 -38
  37. package/skills/setup/SKILL.md +85 -141
  38. package/skills/setup/troubleshooting.md +38 -35
  39. package/skills/test/SKILL.md +86 -94
  40. package/skills/test/testing-patterns.md +63 -63
  41. package/skills/up-code/SKILL.md +108 -108
  42. package/skills/update/SKILL.md +109 -132
  43. package/skills/verify/SKILL.md +128 -132
  44. package/templates/compact-guidance.md +45 -45
  45. package/templates/methodology-guide.md +46 -42
  46. package/config/openspec-config.yaml +0 -8
  47. package/skills/prereqs/OPENSPEC-DELTAS.md +0 -51
package/bin/cli.js CHANGED
@@ -13,6 +13,7 @@ const {
13
13
  installSkills,
14
14
  installAgents,
15
15
  removeSkills,
16
+ removeOpenspecLegacyAssets,
16
17
  createClaudeMd,
17
18
  createCursorRules,
18
19
  readRepoVersion,
@@ -24,6 +25,7 @@ const {
24
25
  const { installHooks, uninstallHooks, cleanLegacySettingsHooks } = require('../lib/hooks');
25
26
  const { handleCompact } = require('../lib/commands/compact');
26
27
  const { handleBus } = require('../lib/commands/bus');
28
+ const { handleSdd, autoMigrateOpenspec } = require('../lib/commands/sdd');
27
29
  const { syncIgnoreFiles } = require('../lib/ignore-files');
28
30
  const { methodologyMigrationPending } = require('../lib/methodology-migration-pending');
29
31
 
@@ -46,7 +48,7 @@ function writePendingUpdateFlag(root, fromVersion, toVersion) {
46
48
  } catch (_) {}
47
49
  }
48
50
 
49
- /** Borra `.refacil-pending-update` si ya no hay migracion (flags viejos o sync de skills sin migracion). */
51
+ /** Clears `.refacil-pending-update` if there is no longer a pending migration (stale flags or skill sync without migration). */
50
52
  function clearStalePendingUpdateFlag(root) {
51
53
  const flagPath = path.join(root, '.refacil-pending-update');
52
54
  if (!fs.existsSync(flagPath)) return;
@@ -78,9 +80,9 @@ function notifyUpdate() {
78
80
  return;
79
81
  }
80
82
 
81
- const fromLabel = info.from ? `v${info.from}` : 'version anterior';
83
+ const fromLabel = info.from ? `v${info.from}` : 'previous version';
82
84
 
83
- // Si el usuario ya está ejecutando /refacil:update, dejar pasar y borrar el flag
85
+ // If the user is already running /refacil:update, let it through and clear the flag
84
86
  const prompt = readStdinPrompt();
85
87
  if (prompt.includes('refacil:update') || prompt.includes('refacil/update')) {
86
88
  try { fs.unlinkSync(flagPath); } catch (_) {}
@@ -88,13 +90,13 @@ function notifyUpdate() {
88
90
  }
89
91
 
90
92
  if (!info.shown) {
91
- // Primera vez: bloquear para que el usuario lo vea claramente
93
+ // First time: block so the user sees it clearly
92
94
  try { fs.writeFileSync(flagPath, JSON.stringify({ ...info, shown: true })); } catch (_) {}
93
95
  const userMsg =
94
- `[refacil-sdd-ai] Actualizacion de metodologia detectada (${fromLabel} → v${info.to}).\n` +
95
- `Tu mensaje fue pausado. ¿Deseas aplicar las migraciones pendientes antes de continuar?\n` +
96
- ` • Si: ejecuta /refacil:update\n` +
97
- ` • No: reenvía tu mensaje anterior para continuar sin actualizar.`;
96
+ `[refacil-sdd-ai] Methodology update detected (${fromLabel} → v${info.to}).\n` +
97
+ `Your message was paused. Do you want to apply the pending migrations before continuing?\n` +
98
+ ` • Yes: run /refacil:update\n` +
99
+ ` • No: resend your previous message to continue without updating.`;
98
100
  if (isCursor) {
99
101
  process.stdout.write(JSON.stringify({ continue: false, user_message: userMsg }) + '\n');
100
102
  } else {
@@ -103,12 +105,12 @@ function notifyUpdate() {
103
105
  }
104
106
  process.exit(2);
105
107
  } else {
106
- // Segunda vez: dejar pasar y avisar al LLM (solo Claude Code soporta inyectar contexto)
108
+ // Second time: let through and notify the LLM (only Claude Code supports context injection)
107
109
  try { fs.unlinkSync(flagPath); } catch (_) {}
108
110
  if (!isCursor) {
109
111
  console.log(
110
- `[refacil-sdd-ai] IMPORTANTE: hay una actualizacion de la metodologia SDD-AI pendiente (${fromLabel} → v${info.to}). ` +
111
- `Antes de responder al usuario, preguntale si desea ejecutar /refacil:update ahora.`,
112
+ `[refacil-sdd-ai] IMPORTANT: there is a pending SDD-AI methodology update (${fromLabel} → v${info.to}). ` +
113
+ `Before responding to the user, ask them if they want to run /refacil:update now.`,
112
114
  );
113
115
  }
114
116
  }
@@ -137,11 +139,11 @@ function syncRepoSkillsIfStale(globalVersion) {
137
139
  const repoVersion = readRepoVersion(projectRoot);
138
140
  if (repoVersion === globalVersion) return null;
139
141
 
140
- // El repo tiene skills más nuevas que el paquete instalado no degradar
142
+ // Repo has newer skills than the installed package do not downgrade
141
143
  if (semverGt(repoVersion, globalVersion)) {
142
144
  process.stderr.write(
143
- `[refacil-sdd-ai] El repo usa la metodologia v${repoVersion} pero el paquete global es v${globalVersion}. ` +
144
- `Ejecuta: npm update -g refacil-sdd-ai\n`,
145
+ `[refacil-sdd-ai] Repo uses methodology v${repoVersion} but the global package is v${globalVersion}. ` +
146
+ `Run: npm update -g refacil-sdd-ai\n`,
145
147
  );
146
148
  return null;
147
149
  }
@@ -167,10 +169,10 @@ function migrationPendingCmd() {
167
169
  if (wantJson) {
168
170
  process.stdout.write(`${JSON.stringify({ pending, reasons })}\n`);
169
171
  } else if (pending) {
170
- console.log(' Migraciones de metodologia pendientes:');
172
+ console.log(' Pending methodology migrations:');
171
173
  for (const r of reasons) console.log(` - ${r}`);
172
174
  } else {
173
- console.log(' Sin migraciones de metodologia pendientes (criterio alineado con hooks y /refacil:update).');
175
+ console.log(' No pending methodology migrations (criteria aligned with hooks and /refacil:update).');
174
176
  }
175
177
  clearStalePendingUpdateFlag(projectRoot);
176
178
  process.exit(pending ? 1 : 0);
@@ -179,18 +181,33 @@ function migrationPendingCmd() {
179
181
  function checkUpdate() {
180
182
  clearStalePendingUpdateFlag(projectRoot);
181
183
 
184
+ try {
185
+ autoMigrateOpenspec(projectRoot);
186
+ } catch (err) {
187
+ process.stderr.write(`[refacil-sdd-ai] Could not migrate openspec/ to refacil-sdd/: ${err.message}\n`);
188
+ }
189
+
190
+ try {
191
+ const legacyRemoved = removeOpenspecLegacyAssets(projectRoot);
192
+ if (legacyRemoved > 0) {
193
+ process.stderr.write(`[refacil-sdd-ai] Removed ${legacyRemoved} legacy OpenSpec assets (openspec-* skills, opsx-* commands)\n`);
194
+ }
195
+ } catch (err) {
196
+ process.stderr.write(`[refacil-sdd-ai] Could not remove legacy OpenSpec assets: ${err.message}\n`);
197
+ }
198
+
182
199
  const { execSync } = require('child_process');
183
200
  let localVersion = getPackageVersion(packageRoot);
184
201
 
185
202
  try {
186
203
  syncCompactGuidance(projectRoot, packageRoot);
187
204
  } catch (err) {
188
- process.stderr.write(`[refacil-sdd-ai] No se pudo sincronizar compact-guidance: ${err.message}\n`);
205
+ process.stderr.write(`[refacil-sdd-ai] Could not sync compact-guidance: ${err.message}\n`);
189
206
  }
190
207
 
191
208
  cleanLegacySettingsHooks(projectRoot);
192
209
 
193
- // Paso 1: actualizar el paquete global si hay version nueva en npm
210
+ // Step 1: update the global package if a newer version is available on npm
194
211
  try {
195
212
  const latest = execSync('npm view refacil-sdd-ai version', {
196
213
  encoding: 'utf8',
@@ -204,8 +221,8 @@ function checkUpdate() {
204
221
  localVersion = latest;
205
222
  } catch (_) {
206
223
  console.log(
207
- `[refacil-sdd-ai] Hay una nueva version disponible (v${localVersion} -> v${latest}) pero la actualizacion automatica fallo. ` +
208
- `Ejecuta manualmente: npm update -g refacil-sdd-ai && refacil-sdd-ai update`,
224
+ `[refacil-sdd-ai] A new version is available (v${localVersion} -> v${latest}) but the automatic update failed. ` +
225
+ `Run manually: npm update -g refacil-sdd-ai && refacil-sdd-ai update`,
209
226
  );
210
227
  }
211
228
  }
@@ -213,21 +230,21 @@ function checkUpdate() {
213
230
  // Silent: sin internet o registry no disponible
214
231
  }
215
232
 
216
- // Paso 2: sincronizar skills del repo con el paquete (ya actualizado)
233
+ // Step 2: sync repo skills with the (now updated) package
217
234
  const syncResult = syncRepoSkillsIfStale(localVersion);
218
235
  if (syncResult && !syncResult.failed) {
219
- const fromLabel = syncResult.from ? `v${syncResult.from}` : 'version desconocida';
236
+ const fromLabel = syncResult.from ? `v${syncResult.from}` : 'unknown version';
220
237
  console.log(
221
- `[refacil-sdd-ai] Skills de este repo sincronizadas (${fromLabel} -> v${syncResult.to}). ` +
222
- 'Reinicia la sesion de Claude Code o Cursor para detectar los cambios.',
238
+ `[refacil-sdd-ai] Repo skills synced (${fromLabel} -> v${syncResult.to}). ` +
239
+ 'Restart the Claude Code or Cursor session to pick up the changes.',
223
240
  );
224
241
  if (methodologyMigrationPending(projectRoot).pending) {
225
242
  writePendingUpdateFlag(projectRoot, syncResult.from, syncResult.to);
226
243
  }
227
244
  } else if (syncResult && syncResult.failed) {
228
245
  console.log(
229
- `[refacil-sdd-ai] Skills de este repo estan desactualizadas respecto al paquete global (v${syncResult.to}) ` +
230
- 'pero la sincronizacion automatica fallo. Ejecuta manualmente: refacil-sdd-ai update',
246
+ `[refacil-sdd-ai] Repo skills are out of date with the global package (v${syncResult.to}) ` +
247
+ 'but automatic sync failed. Run manually: refacil-sdd-ai update',
231
248
  );
232
249
  }
233
250
  }
@@ -246,7 +263,9 @@ function checkReview() {
246
263
  const command = (input.tool_input && input.tool_input.command) || '';
247
264
  if (!command.match(/git\s+push/)) return;
248
265
 
249
- const changesDir = path.join(projectRoot, 'openspec', 'changes');
266
+ const sddChangesDir = path.join(projectRoot, 'refacil-sdd', 'changes');
267
+ const legacyChangesDir = path.join(projectRoot, 'openspec', 'changes');
268
+ const changesDir = fs.existsSync(sddChangesDir) ? sddChangesDir : legacyChangesDir;
250
269
  if (!fs.existsSync(changesDir)) return;
251
270
 
252
271
  const entries = fs.readdirSync(changesDir, { withFileTypes: true });
@@ -264,14 +283,14 @@ function checkReview() {
264
283
  const names = missing.map((e) => e.name).join(', ');
265
284
  const reason =
266
285
  missing.length === 1
267
- ? `[refacil-sdd-ai] Review pendiente para: ${names}. ` +
268
- 'Deten el push y ejecuta /refacil:review sobre ese cambio antes de subir codigo. ' +
269
- 'Si el review aprueba, reintenta el git push. ' +
270
- 'Si el review requiere correcciones, informa los hallazgos al usuario y NO reintentar el push.'
271
- : `[refacil-sdd-ai] Hay multiples cambios sin review aprobado: ${names}. ` +
272
- 'Deten el push y pide al usuario seleccionar explicitamente que cambio quiere subir. ' +
273
- 'Luego ejecuta /refacil:review <nombre-cambio> para ese cambio especifico y reintenta el push. ' +
274
- 'No ejecutes review automatico sin seleccion cuando hay mas de un cambio pendiente.';
286
+ ? `[refacil-sdd-ai] Review pending for: ${names}. ` +
287
+ 'Stop the push and run /refacil:review on that change before pushing code. ' +
288
+ 'If the review passes, retry the git push. ' +
289
+ 'If the review requires corrections, report the findings to the user and DO NOT retry the push.'
290
+ : `[refacil-sdd-ai] Multiple changes without approved review: ${names}. ` +
291
+ 'Stop the push and ask the user to explicitly select which change they want to push. ' +
292
+ 'Then run /refacil:review <change-name> for that specific change and retry the push. ' +
293
+ 'Do not run automatic review without explicit selection when there is more than one pending change.';
275
294
  console.log(JSON.stringify({ decision: 'block', reason }));
276
295
  }
277
296
  }
@@ -279,7 +298,7 @@ function checkReview() {
279
298
  // --- High-level commands ---
280
299
 
281
300
  function init() {
282
- console.log('\n refacil-sdd-ai: Inicializando metodologia SDD-AI...\n');
301
+ console.log('\n refacil-sdd-ai: Initializing SDD-AI methodology...\n');
283
302
 
284
303
  const nodeOk = checkNodeVersion();
285
304
  if (nodeOk) console.log(` Node.js ${process.version} OK`);
@@ -288,18 +307,18 @@ function init() {
288
307
  if (claudeCheck.ok === true) {
289
308
  console.log(` Claude Code ${claudeCheck.version} OK`);
290
309
  } else if (claudeCheck.ok === false) {
291
- console.log(`\n ADVERTENCIA: Claude Code ${claudeCheck.version} detectado.`);
292
- console.log(' El hook compact-bash requiere Claude Code >= 2.1.89 para rewrite silencioso.');
293
- console.log(' Con version inferior se instala igual pero el rewrite no tendra efecto.');
294
- console.log(' Actualiza con: npm install -g @anthropic-ai/claude-code\n');
310
+ console.log(`\n WARNING: Claude Code ${claudeCheck.version} detected.`);
311
+ console.log(' The compact-bash hook requires Claude Code >= 2.1.89 for silent rewrite.');
312
+ console.log(' It will still install on older versions but the rewrite will have no effect.');
313
+ console.log(' Update with: npm install -g @anthropic-ai/claude-code\n');
295
314
  }
296
315
 
297
316
  const count = installSkills(packageRoot, projectRoot);
298
- console.log(` ${count} skills instaladas en .claude/skills/ y .cursor/skills/`);
317
+ console.log(` ${count} skills installed in .claude/skills/ and .cursor/skills/`);
299
318
 
300
319
  const agentsCount = installAgents(packageRoot, projectRoot);
301
320
  if (agentsCount > 0) {
302
- console.log(` ${agentsCount} sub-agentes instalados en .claude/agents/ y .cursor/agents/`);
321
+ console.log(` ${agentsCount} sub-agents installed in .claude/agents/ and .cursor/agents/`);
303
322
  }
304
323
 
305
324
  writeRepoVersion(projectRoot, getPackageVersion(packageRoot));
@@ -308,56 +327,62 @@ function init() {
308
327
  if (createCursorRules(packageRoot, projectRoot)) console.log(' .cursorrules OK');
309
328
 
310
329
  if (installHooks('.claude', projectRoot)) {
311
- console.log(' Hook check-update agregado a .claude/settings.json');
330
+ console.log(' Hook check-update added to .claude/settings.json');
312
331
  }
313
332
  if (installHooks('.cursor', projectRoot)) {
314
- console.log(' Hook check-update agregado a .cursor/settings.json');
333
+ console.log(' Hook check-update added to .cursor/settings.json');
315
334
  }
316
335
 
317
336
  try {
318
337
  const ignoreResult = syncIgnoreFiles(projectRoot);
319
338
  const s = ignoreResult.claude;
320
339
  if (s.status === 'created') {
321
- console.log(' .claudeignore y .cursorignore creados');
340
+ console.log(' .claudeignore and .cursorignore created');
322
341
  } else if (s.status === 'updated') {
323
- console.log(` .claudeignore y .cursorignore actualizados (${s.added} entradas agregadas)`);
342
+ console.log(` .claudeignore and .cursorignore updated (${s.added} entries added)`);
324
343
  } else {
325
- console.log(' .claudeignore y .cursorignore ya están al día');
344
+ console.log(' .claudeignore and .cursorignore are up to date');
326
345
  }
327
346
  } catch (err) {
328
- console.error(` Advertencia: no se pudo sincronizar ignore files: ${err.message}`);
347
+ console.error(` Warning: could not sync ignore files: ${err.message}`);
329
348
  }
330
349
 
331
350
  try {
332
351
  const result = syncCompactGuidance(projectRoot, packageRoot);
333
352
  if (result.status === 'appended') {
334
- console.log(' Bloque compact-guidance agregado a AGENTS.md');
353
+ console.log(' compact-guidance block added to AGENTS.md');
335
354
  } else if (result.status === 'replaced') {
336
- console.log(' Bloque compact-guidance actualizado en AGENTS.md');
355
+ console.log(' compact-guidance block updated in AGENTS.md');
337
356
  }
338
357
  } catch (err) {
339
- console.error(` Advertencia: no se pudo sincronizar compact-guidance: ${err.message}`);
358
+ console.error(` Warning: could not sync compact-guidance: ${err.message}`);
340
359
  }
341
360
 
342
- console.log('\n Siguientes pasos:\n');
343
- console.log(' 1. REINICIA tu sesion de Claude Code o Cursor');
344
- console.log(' (las skills nuevas no se detectan hasta reiniciar)\n');
345
- console.log(' 2. Ejecuta: /refacil:setup');
346
- console.log(' (instala OpenSpec y genera AGENTS.md para tu proyecto)\n');
347
- console.log(' Nota: /refacil:setup tambien instalara los comandos de OpenSpec (opsx:*).');
348
- console.log(' Los comandos refacil:* y opsx:* coexisten sin conflicto.');
349
- console.log(' El equipo debe usar los refacil:* como interfaz principal.\n');
361
+ console.log('\n Next steps:\n');
362
+ console.log(' 1. RESTART your Claude Code or Cursor session');
363
+ console.log(' (new skills are not detected until the session is restarted)\n');
364
+ console.log(' 2. Run: /refacil:setup');
365
+ console.log(' (generates AGENTS.md for your project)\n');
350
366
  }
351
367
 
352
368
  function update() {
353
- console.log('\n refacil-sdd-ai: Actualizando skills...\n');
369
+ console.log('\n refacil-sdd-ai: Updating skills...\n');
354
370
 
355
371
  const count = installSkills(packageRoot, projectRoot);
356
- console.log(` ${count} skills actualizadas en .claude/skills/ y .cursor/skills/`);
372
+ console.log(` ${count} skills updated in .claude/skills/ and .cursor/skills/`);
357
373
 
358
374
  const agentsCount = installAgents(packageRoot, projectRoot);
359
375
  if (agentsCount > 0) {
360
- console.log(` ${agentsCount} sub-agentes actualizados en .claude/agents/ y .cursor/agents/`);
376
+ console.log(` ${agentsCount} sub-agents updated in .claude/agents/ and .cursor/agents/`);
377
+ }
378
+
379
+ try {
380
+ const legacyRemoved = removeOpenspecLegacyAssets(projectRoot);
381
+ if (legacyRemoved > 0) {
382
+ console.log(` ${legacyRemoved} legacy OpenSpec assets removed (openspec-* skills, opsx-* commands)`);
383
+ }
384
+ } catch (err) {
385
+ process.stderr.write(`[refacil-sdd-ai] Could not remove legacy OpenSpec assets: ${err.message}\n`);
361
386
  }
362
387
 
363
388
  writeRepoVersion(projectRoot, getPackageVersion(packageRoot));
@@ -366,92 +391,93 @@ function update() {
366
391
  createCursorRules(packageRoot, projectRoot);
367
392
 
368
393
  if (installHooks('.claude', projectRoot)) {
369
- console.log(' Hook check-update agregado a .claude/settings.json');
394
+ console.log(' Hook check-update added to .claude/settings.json');
370
395
  }
371
396
  if (installHooks('.cursor', projectRoot)) {
372
- console.log(' Hook check-update agregado a .cursor/settings.json');
397
+ console.log(' Hook check-update added to .cursor/settings.json');
373
398
  }
374
399
 
375
400
  try {
376
401
  const ignoreResult = syncIgnoreFiles(projectRoot);
377
402
  const s = ignoreResult.claude;
378
403
  if (s.status === 'created') {
379
- console.log(' .claudeignore y .cursorignore creados');
404
+ console.log(' .claudeignore and .cursorignore created');
380
405
  } else if (s.status === 'updated') {
381
- console.log(` .claudeignore y .cursorignore actualizados (${s.added} entradas agregadas)`);
406
+ console.log(` .claudeignore and .cursorignore updated (${s.added} entries added)`);
382
407
  } else {
383
- console.log(' .claudeignore y .cursorignore ya están al día');
408
+ console.log(' .claudeignore and .cursorignore are up to date');
384
409
  }
385
410
  } catch (err) {
386
- console.error(` Advertencia: no se pudo sincronizar ignore files: ${err.message}`);
411
+ console.error(` Warning: could not sync ignore files: ${err.message}`);
387
412
  }
388
413
 
389
414
  try {
390
415
  const result = syncCompactGuidance(projectRoot, packageRoot);
391
416
  if (result.status === 'appended') {
392
- console.log(' Bloque compact-guidance agregado a AGENTS.md');
417
+ console.log(' compact-guidance block added to AGENTS.md');
393
418
  } else if (result.status === 'replaced') {
394
- console.log(' Bloque compact-guidance actualizado en AGENTS.md');
419
+ console.log(' compact-guidance block updated in AGENTS.md');
395
420
  }
396
421
  } catch (err) {
397
- console.error(` Advertencia: no se pudo sincronizar compact-guidance: ${err.message}`);
422
+ console.error(` Warning: could not sync compact-guidance: ${err.message}`);
398
423
  }
399
424
 
400
- console.log('\n REINICIA tu sesion de Claude Code o Cursor para aplicar los cambios.\n');
425
+ console.log('\n RESTART your Claude Code or Cursor session to apply the changes.\n');
401
426
  }
402
427
 
403
428
  function clean() {
404
- console.log('\n refacil-sdd-ai: Eliminando skills...\n');
429
+ console.log('\n refacil-sdd-ai: Removing skills...\n');
405
430
 
406
431
  const count = removeSkills(projectRoot);
407
- console.log(` ${count} skills eliminadas de .claude/skills/ y .cursor/skills/`);
432
+ console.log(` ${count} skills removed from .claude/skills/ and .cursor/skills/`);
408
433
 
409
434
  if (uninstallHooks('.claude', projectRoot)) {
410
- console.log(' Hooks SDD-AI removidos de .claude/settings.json');
435
+ console.log(' SDD-AI hooks removed from .claude/settings.json');
411
436
  } else {
412
- console.log(' No se encontraron hooks SDD-AI para remover en .claude/settings.json.');
437
+ console.log(' No SDD-AI hooks found to remove in .claude/settings.json.');
413
438
  }
414
439
  if (uninstallHooks('.cursor', projectRoot)) {
415
- console.log(' Hooks SDD-AI removidos de .cursor/settings.json');
440
+ console.log(' SDD-AI hooks removed from .cursor/settings.json');
416
441
  }
417
442
 
418
443
  try {
419
444
  const result = removeCompactGuidance(projectRoot);
420
445
  if (result.status === 'removed') {
421
- console.log(' Bloque compact-guidance removido de AGENTS.md');
446
+ console.log(' compact-guidance block removed from AGENTS.md');
422
447
  }
423
448
  } catch (err) {
424
- console.error(` Advertencia: no se pudo limpiar compact-guidance: ${err.message}`);
449
+ console.error(` Warning: could not clean compact-guidance: ${err.message}`);
425
450
  }
426
451
 
427
- console.log(' AGENTS.md, CLAUDE.md y .cursorrules no fueron eliminados.');
428
- console.log('\n Nota: Los comandos opsx:* de OpenSpec no se eliminan.');
429
- console.log(' Para eliminar OpenSpec: rm -rf openspec/ .claude/commands/opsx .cursor/commands/opsx\n');
452
+ console.log(' AGENTS.md, CLAUDE.md and .cursorrules were not removed.');
453
+ console.log('\n Note: if you have openspec/ in the repo, migrate first with: refacil-sdd-ai sdd status');
454
+ console.log(' (the openspec/ refacil-sdd/ migration is automatic on any sdd subcommand)');
455
+ console.log(' To remove the openspec/ directory after migrating: rm -rf openspec/\n');
430
456
  }
431
457
 
432
458
  function help() {
433
459
  console.log(`
434
- refacil-sdd-ai — Metodologia SDD-AI con OpenSpec
435
-
436
- Comandos:
437
- init Instala skills en .claude/ y .cursor/, crea CLAUDE.md y .cursorrules
438
- update Re-copia skills (para actualizar a nueva version del paquete)
439
- migration-pending Misma validacion que hooks/notify-update: lista migraciones (exit 1 si hay; --json)
440
- check-update Sincroniza skills y compact-guidance al inicio de sesion (hook SessionStart)
441
- notify-update Notifica migracion de metodologia solo si aplica (hook UserPromptSubmit)
442
- check-review Verifica que el review se haya completado (usado por hook PreToolUse)
443
- compact-bash Reescribe comandos Bash bare para reducir tokens (usado por hook PreToolUse)
444
- compact Subcomandos del hook compact-bash:
445
- compact stats - Estadisticas completas (hook + ya-compacto) y ahorro estimado
446
- compact disable - Desactiva el rewrite temporalmente
447
- compact enable - Re-activa el rewrite
448
- compact clear-log - Borra el log historico
449
- bus Subcomandos del chat room entre agentes (refacil-bus):
450
- bus start - Arranca el broker local (auto-spawn detached)
451
- bus stop - Detiene el broker
452
- bus status - Muestra puerto, pid, uptime del broker
453
- bus serve - (interno) Ejecuta el broker en foreground
454
- bus join --room <sala> [--session <s>] [--intro "..."]
460
+ refacil-sdd-ai — SDD-AI Methodology
461
+
462
+ Commands:
463
+ init Install skills in .claude/ and .cursor/, create CLAUDE.md and .cursorrules
464
+ update Re-copy skills (to update to a new package version)
465
+ migration-pending Same validation as hooks/notify-update: list migrations (exit 1 if any; --json)
466
+ check-update Sync skills and compact-guidance at session start (SessionStart hook)
467
+ notify-update Notify methodology migration only if applicable (UserPromptSubmit hook)
468
+ check-review Verify that review has been completed (used by PreToolUse hook)
469
+ compact-bash Rewrite bare Bash commands to reduce tokens (used by PreToolUse hook)
470
+ compact Subcommands for the compact-bash hook:
471
+ compact stats - Full stats (hook + already-compact) and estimated savings
472
+ compact disable - Temporarily disable rewrite
473
+ compact enable - Re-enable rewrite
474
+ compact clear-log - Clear the history log
475
+ bus Subcommands for the inter-agent chat room (refacil-bus):
476
+ bus start - Start the local broker (auto-spawn detached)
477
+ bus stop - Stop the broker
478
+ bus status - Show port, pid, uptime of the broker
479
+ bus serve - (internal) Run the broker in foreground
480
+ bus join --room <room> [--session <s>] [--intro "..."]
455
481
  bus leave [--session <s>]
456
482
  bus say --text "..." [--session <s>]
457
483
  bus ask --to <name|all|*|everyone> --text "..." [--wait N] [--session <s>]
@@ -459,21 +485,29 @@ function help() {
459
485
  bus history [--n N] [--session <s>]
460
486
  bus inbox [--session <s>]
461
487
  bus rooms
462
- bus watch <session> [--room <sala>] (panel en vivo, sin tokens)
463
- bus attend [--timeout N] (escucha preguntas dirigidas)
464
- bus view (abre la UI web en el navegador)
465
- clean Elimina skills y remueve hooks SDD-AI de .claude/settings.json y .cursor/settings.json
466
- help Muestra esta ayuda
467
-
468
- Flujo completo:
488
+ bus watch <session> [--room <room>] (live panel, no tokens)
489
+ bus attend [--timeout N] (listen for directed questions)
490
+ bus view (open the web UI in the browser)
491
+ sdd Subcommands for managing SDD-AI artifacts in refacil-sdd/:
492
+ sdd new-change <name> Create a change with proposal/design/tasks/specs scaffold
493
+ sdd archive <name> Archive a change to refacil-sdd/changes/archive/
494
+ sdd list [--json] List active changes with review status
495
+ sdd status <name> [--json] Artifact and task status of a change
496
+ sdd mark-reviewed <name> Write .review-passed (requires --verdict and --summary)
497
+ sdd tasks-update <name> Mark task N as completed (--task N --done)
498
+ sdd validate-name <name> Validate change name format
499
+ clean Remove skills and SDD-AI hooks from .claude/settings.json and .cursor/settings.json
500
+ help Show this help
501
+
502
+ Full flow:
469
503
  1. npm install -g refacil-sdd-ai
470
504
  2. refacil-sdd-ai init
471
- 3. REINICIAR sesion de Claude Code o Cursor
472
- 4. Ejecutar: /refacil:setup (instala OpenSpec + genera AGENTS.md)
505
+ 3. RESTART the Claude Code or Cursor session
506
+ 4. Run: /refacil:setup (generates AGENTS.md for your project)
473
507
 
474
- Requisitos:
475
- - Node.js >= 20.19.0 (requerido por OpenSpec)
476
- - Claude Code >= 2.1.89 (requerido por compact-bash para rewrite silencioso) o Cursor
508
+ Requirements:
509
+ - Node.js >= 20.19.0
510
+ - Claude Code >= 2.1.89 (required by compact-bash for silent rewrite) or Cursor
477
511
  `);
478
512
  }
479
513
 
@@ -481,6 +515,11 @@ function help() {
481
515
 
482
516
  const command = process.argv[2] || 'help';
483
517
 
518
+ if (command === '--version' || command === '-v') {
519
+ console.log(getPackageVersion(packageRoot));
520
+ process.exit(0);
521
+ }
522
+
484
523
  switch (command) {
485
524
  case 'init':
486
525
  init();
@@ -509,6 +548,9 @@ switch (command) {
509
548
  case 'bus':
510
549
  handleBus(process.argv[3], process.argv.slice(4), packageRoot);
511
550
  break;
551
+ case 'sdd':
552
+ handleSdd(process.argv[3], process.argv.slice(4));
553
+ break;
512
554
  case 'clean':
513
555
  clean();
514
556
  break;
@@ -518,7 +560,7 @@ switch (command) {
518
560
  help();
519
561
  break;
520
562
  default:
521
- console.error(` Comando desconocido: ${command}`);
563
+ console.error(` Unknown command: ${command}`);
522
564
  help();
523
565
  process.exit(1);
524
566
  }
@@ -1,17 +1,17 @@
1
- 'use strict';
2
-
3
- /**
4
- * Indica si el `ask` ya tiene una respuesta que lo cierra para este hilo.
5
- * Para el mismo correlationId con varios destinatarios (@all), solo cuenta
6
- * la respuesta emitida por la sesión que recibió ese ask (ask.to).
7
- */
8
- function askHasMatchingReply(messages, ask) {
9
- if (!ask || ask.kind !== 'ask' || !ask.correlationId) return true;
10
- return messages.some((m) => {
11
- if (m.kind !== 'reply' || m.correlationId !== ask.correlationId) return false;
12
- if (ask.to) return m.from === ask.to;
13
- return m.to === ask.from;
14
- });
15
- }
16
-
17
- module.exports = { askHasMatchingReply };
1
+ 'use strict';
2
+
3
+ /**
4
+ * Indica si el `ask` ya tiene una respuesta que lo cierra para este hilo.
5
+ * Para el mismo correlationId con varios destinatarios (@all), solo cuenta
6
+ * la respuesta emitida por la sesión que recibió ese ask (ask.to).
7
+ */
8
+ function askHasMatchingReply(messages, ask) {
9
+ if (!ask || ask.kind !== 'ask' || !ask.correlationId) return true;
10
+ return messages.some((m) => {
11
+ if (m.kind !== 'reply' || m.correlationId !== ask.correlationId) return false;
12
+ if (ask.to) return m.from === ask.to;
13
+ return m.to === ask.from;
14
+ });
15
+ }
16
+
17
+ module.exports = { askHasMatchingReply };