pumuki 6.3.318 → 6.3.320

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pumuki",
3
- "version": "6.3.318",
3
+ "version": "6.3.320",
4
4
  "description": "Enterprise-grade AST Intelligence System with multi-platform support (iOS, Android, Backend, Frontend) and Feature-First + DDD + Clean Architecture enforcement. Includes dynamic violations API for intelligent querying.",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -216,6 +216,37 @@ const isSkillCause = (
216
216
  (cause.ruleId ?? '').startsWith('skills.') ||
217
217
  cause.code.startsWith('SKILLS_');
218
218
 
219
+ const isSkillsContractCause = (
220
+ cause: NonNullable<Extract<PumukiCriticalNotificationEvent, { kind: 'gate.blocked' }>['blockingCauses']>[number]
221
+ ): boolean => {
222
+ const searchable = `${cause.code} ${cause.ruleId ?? ''} ${cause.message}`.toUpperCase();
223
+ return (
224
+ searchable.includes('EVIDENCE_PLATFORM_CRITICAL_SKILLS_RULES_MISSING') ||
225
+ searchable.includes('EVIDENCE_SKILLS_CONTRACT_INCOMPLETE')
226
+ );
227
+ };
228
+
229
+ const formatPlatformName = (platform: string | null): string =>
230
+ platform
231
+ ? platform
232
+ .replace(/\bios\b/giu, 'iOS')
233
+ .replace(/\bandroid\b/giu, 'Android')
234
+ .replace(/\bfrontend\b/giu, 'Frontend')
235
+ .replace(/\bbackend\b/giu, 'Backend')
236
+ : 'plataforma detectada';
237
+
238
+ const extractSkillsContractPlatform = (message: string): string | null =>
239
+ message.match(/\bplatforms?=([a-z0-9_,.-]+)/i)?.[1]?.split(',')[0]?.trim() ?? null;
240
+
241
+ const extractSkillsContractRules = (message: string): string | null => {
242
+ const rulesMatch = message.match(/\brules?=\{([^}]+)\}/i)?.[1];
243
+ const missingMatch = message.match(/\bmissing=\[([^\]]+)\]/i)?.[1];
244
+ return normalizeNotificationText(rulesMatch ?? missingMatch ?? '');
245
+ };
246
+
247
+ const SKILLS_CONTRACT_REMEDIATION =
248
+ 'Actualiza o reconcilia el contrato de skills de Pumuki y vuelve a intentar el commit. Si estás en un repo consumidor, repinea Pumuki a una versión que incluya esa regla crítica.';
249
+
219
250
  const WORKTREE_HYGIENE_REMEDIATION =
220
251
  'Reduce el worktree pendiente a un slice atómico: stagea solo la tarea activa o guarda el resto en stash nombrado, y reejecuta PRE_WRITE.';
221
252
 
@@ -301,6 +332,16 @@ const formatBlockingCauseForDialog = (
301
332
  ' Solución: Crea ese .feature con el escenario de aceptación de la slice, o corrige la referencia si el id de tarea no es correcto.',
302
333
  ];
303
334
  }
335
+ if (isSkillsContractCause(cause)) {
336
+ const platform = formatPlatformName(extractSkillsContractPlatform(cause.message));
337
+ const rules = extractSkillsContractRules(cause.message);
338
+ return [
339
+ `${index + 1}. Causa bloqueante: contrato de skills incompleto`,
340
+ ` Plataforma: ${platform}`,
341
+ ` Falla: Pumuki detecta ${platform}, pero falta activar enforcement de skills críticas${rules ? `: ${rules}` : ''}.`,
342
+ ` Solución: ${SKILLS_CONTRACT_REMEDIATION}`,
343
+ ];
344
+ }
304
345
 
305
346
  const causeLabel = isSkillCause(cause) ? 'Regla' : 'Causa bloqueante';
306
347
  return [
@@ -327,6 +368,11 @@ const hasOnlyBddScenarioMissingCauses = (
327
368
  ): boolean =>
328
369
  Boolean(causes?.length) && causes!.every(isBddScenarioMissingCause);
329
370
 
371
+ const hasOnlySkillsContractCauses = (
372
+ causes: Extract<PumukiCriticalNotificationEvent, { kind: 'gate.blocked' }>['blockingCauses']
373
+ ): boolean =>
374
+ Boolean(causes?.length) && causes!.every(isSkillsContractCause);
375
+
330
376
  const resolveGoldenFlowDialogRemediation = (
331
377
  causes: Extract<PumukiCriticalNotificationEvent, { kind: 'gate.blocked' }>['blockingCauses']
332
378
  ): string => {
@@ -348,6 +394,8 @@ export const buildBlockedDialogPayload = (params: {
348
394
  ? resolveGoldenFlowDialogRemediation(params.event.blockingCauses)
349
395
  : hasOnlyBddScenarioMissingCauses(params.event.blockingCauses)
350
396
  ? 'Crea el fichero .feature esperado para la slice activa o corrige la referencia de tarea. Después vuelve a intentar el commit.'
397
+ : hasOnlySkillsContractCauses(params.event.blockingCauses)
398
+ ? SKILLS_CONTRACT_REMEDIATION
351
399
  : params.event.blockingCauses && params.event.blockingCauses.length > 0
352
400
  ? 'Corrige las violaciones listadas y vuelve a intentar el commit.'
353
401
  : resolveBlockedRemediation(params.event, causeCode);
@@ -47,6 +47,35 @@ const isBddScenarioMissingCause = (cause: BlockedCause): boolean => {
47
47
  );
48
48
  };
49
49
 
50
+ const isSkillsContractCause = (cause: BlockedCause): boolean => {
51
+ const searchable = `${cause.code} ${cause.ruleId ?? ''} ${cause.message}`.toUpperCase();
52
+ return (
53
+ searchable.includes('EVIDENCE_PLATFORM_CRITICAL_SKILLS_RULES_MISSING') ||
54
+ searchable.includes('EVIDENCE_SKILLS_CONTRACT_INCOMPLETE')
55
+ );
56
+ };
57
+
58
+ const formatPlatformName = (platform: string | null): string =>
59
+ platform
60
+ ? platform
61
+ .replace(/\bios\b/giu, 'iOS')
62
+ .replace(/\bandroid\b/giu, 'Android')
63
+ .replace(/\bfrontend\b/giu, 'Frontend')
64
+ .replace(/\bbackend\b/giu, 'Backend')
65
+ : 'plataforma detectada';
66
+
67
+ const extractSkillsContractPlatform = (message: string): string | null =>
68
+ message.match(/\bplatforms?=([a-z0-9_,.-]+)/i)?.[1]?.split(',')[0]?.trim() ?? null;
69
+
70
+ const extractSkillsContractRules = (message: string): string | null => {
71
+ const rulesMatch = message.match(/\brules?=\{([^}]+)\}/i)?.[1];
72
+ const missingMatch = message.match(/\bmissing=\[([^\]]+)\]/i)?.[1];
73
+ return normalizeNotificationText(rulesMatch ?? missingMatch ?? '');
74
+ };
75
+
76
+ const SKILLS_CONTRACT_REMEDIATION =
77
+ 'Actualiza o reconcilia el contrato de skills de Pumuki y vuelve a intentar el commit. Si estás en un repo consumidor, repinea Pumuki a una versión que incluya esa regla crítica.';
78
+
50
79
  const extractExpectedBddFeatureFile = (cause: BlockedCause): string => {
51
80
  const directFile = cause.file?.endsWith('.feature') ? cause.file : null;
52
81
  const fieldMatch = cause.message.match(/\bfile=([^\s]+\.feature)\b/i)?.[1];
@@ -187,6 +216,11 @@ export const resolvePrioritizedBlockingCauses = (
187
216
  if (leftBddScenarioMissing !== rightBddScenarioMissing) {
188
217
  return leftBddScenarioMissing ? -1 : 1;
189
218
  }
219
+ const leftSkillsContract = isSkillsContractCause(left);
220
+ const rightSkillsContract = isSkillsContractCause(right);
221
+ if (leftSkillsContract !== rightSkillsContract) {
222
+ return leftSkillsContract ? -1 : 1;
223
+ }
190
224
  return 0;
191
225
  });
192
226
  };
@@ -213,6 +247,10 @@ const buildBlockingCausesSummary = (
213
247
  if (isBddScenarioMissingCause(first)) {
214
248
  return `BDD sin fichero .feature: ${extractExpectedBddFeatureFile(first)}${overflow}`;
215
249
  }
250
+ if (isSkillsContractCause(first)) {
251
+ const platform = formatPlatformName(extractSkillsContractPlatform(first.message));
252
+ return `Contrato de skills incompleto: ${platform}${overflow}`;
253
+ }
216
254
  return `${prefix}: ${formatCauseRule(first)} · ${formatCauseLocation(first)}${overflow}`;
217
255
  };
218
256
 
@@ -244,6 +282,11 @@ const buildBlockingCausesRemediation = (
244
282
  if (isBddScenarioMissingCause(first)) {
245
283
  return `Falta el fichero ${extractExpectedBddFeatureFile(first)}. Crea ese .feature con el escenario de aceptación de la slice, o corrige la referencia de tarea si no corresponde.`;
246
284
  }
285
+ if (isSkillsContractCause(first)) {
286
+ const platform = formatPlatformName(extractSkillsContractPlatform(first.message));
287
+ const rules = extractSkillsContractRules(first.message);
288
+ return `Pumuki detecta ${platform}, pero falta activar enforcement de skills críticas${rules ? `: ${rules}` : ''}. ${SKILLS_CONTRACT_REMEDIATION}`;
289
+ }
247
290
  return `${formatCauseFix(first)} Revisa el reporte completo para el resto de causas bloqueantes.`;
248
291
  };
249
292
 
@@ -22,7 +22,7 @@ const BLOCKED_REMEDIATION_BY_CODE: Readonly<Record<string, string>> = {
22
22
  EVIDENCE_REPO_ROOT_MISMATCH: 'Regenera la evidencia desde este repositorio y vuelve a validar.',
23
23
  PRE_PUSH_UPSTREAM_MISSING: 'Configura upstream con `git push --set-upstream origin <branch>` y repite PRE_PUSH.',
24
24
  SDD_SESSION_MISSING:
25
- 'Abre la sesión SDD del cambio activo: `pumuki sdd session --open --change=<id>`. Sustituye <id> por la carpeta en openspec/changes. Después vuelve a intentar el commit; Pumuki ejecutará PRE_WRITE automáticamente.',
25
+ 'Abre `openspec/changes/` y copia la carpeta de tu tarea, por ejemplo `rgo-1900-35`. Ejecuta `pumuki sdd session --open --change=<id>` usando ese nombre. Después vuelve a intentar el commit; PRE_WRITE automáticamente.',
26
26
  SDD_SESSION_INVALID:
27
27
  'Refresca la sesión SDD activa: `pumuki sdd session --refresh --ttl-minutes=90`. Después vuelve a intentar el commit; Pumuki ejecutará PRE_WRITE automáticamente.',
28
28
  OPENSPEC_MISSING: 'Instala OpenSpec en este repositorio y vuelve a validar el gate.',