pumuki 6.3.319 → 6.3.321

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.
@@ -1501,9 +1501,6 @@ const appendWorktreeHygieneViolations = (
1501
1501
  };
1502
1502
 
1503
1503
  const toPolicyStage = (stage: AiGateStage): SkillsStage => {
1504
- if (stage === 'PRE_WRITE') {
1505
- return 'PRE_COMMIT';
1506
- }
1507
1504
  return stage;
1508
1505
  };
1509
1506
 
@@ -84,9 +84,6 @@ const defaultDependencies: PlatformGateEvaluationDependencies = {
84
84
  const normalizeStageForSkills = (
85
85
  stage: GateStage
86
86
  ): Exclude<GateStage, 'STAGED'> => {
87
- if (stage === 'PRE_WRITE') {
88
- return 'CI';
89
- }
90
87
  return stage === 'STAGED' ? 'PRE_COMMIT' : stage;
91
88
  };
92
89
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pumuki",
3
- "version": "6.3.319",
3
+ "version": "6.3.321",
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