pumuki 6.3.358 → 6.3.359

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.358",
3
+ "version": "6.3.359",
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": {
@@ -7,6 +7,7 @@ import {
7
7
  buildNotificationTrackingCauseSummary,
8
8
  extractNotificationTrackingContext,
9
9
  } from './framework-menu-system-notifications-tracking';
10
+ import { buildLegacySkillCauseSummary } from './framework-menu-system-notifications-legacy-skill-cause';
10
11
 
11
12
  const BLOCKED_CAUSE_SUMMARY_BY_CODE: Readonly<Record<string, string>> = {
12
13
  EVIDENCE_GATE_BLOCKED: 'El gate de evidencia/gobernanza está bloqueado.',
@@ -170,6 +171,10 @@ export const resolveBlockedCauseSummary = (
170
171
  if (blockedCausesSummary) {
171
172
  return truncateNotificationText(blockedCausesSummary, 72);
172
173
  }
174
+ const legacySkillCauseSummary = buildLegacySkillCauseSummary(event.causeMessage);
175
+ if (legacySkillCauseSummary) {
176
+ return legacySkillCauseSummary;
177
+ }
173
178
  const trackingContext = extractNotificationTrackingContext(event.causeMessage);
174
179
  const priorityCode = resolvePriorityCauseFromMessage(event.causeMessage);
175
180
  if (priorityCode) {
@@ -0,0 +1,107 @@
1
+ import path from 'node:path';
2
+
3
+ import { normalizeNotificationText } from './framework-menu-system-notifications-text';
4
+
5
+ type LegacySkillCause = {
6
+ readonly ruleId: string;
7
+ readonly file?: string;
8
+ readonly line?: string;
9
+ readonly message?: string;
10
+ readonly remediation?: string;
11
+ };
12
+
13
+ const FIELD_NAMES = ['severity', 'file', 'line', 'lines', 'message', 'remediation'] as const;
14
+
15
+ const RULE_LABELS: Readonly<Record<string, string>> = {
16
+ 'skills.ios.prefer-swift-testing': 'Swift Testing',
17
+ 'skills.ios.no-wait-for-expectations': 'Swift Testing async',
18
+ 'skills.ios.no-xctassert': 'Swift Testing',
19
+ 'skills.ios.no-xctunwrap': 'Swift Testing',
20
+ 'skills.backend.no-empty-catch': 'Backend: no empty catch',
21
+ };
22
+
23
+ const extractLegacySkillSegment = (message?: string): string | null => {
24
+ if (!message) {
25
+ return null;
26
+ }
27
+ const markerIndex = message.indexOf('Blocking causes:');
28
+ if (markerIndex < 0) {
29
+ return null;
30
+ }
31
+ const afterMarker = message.slice(markerIndex);
32
+ const firstCause = afterMarker.replace(/^Blocking causes:\s*1\)\s*/i, '');
33
+ const nextCauseIndex = firstCause.search(/\s+\d+\)\s+skills\./);
34
+ return nextCauseIndex >= 0 ? firstCause.slice(0, nextCauseIndex) : firstCause;
35
+ };
36
+
37
+ const extractField = (segment: string, fieldName: string): string | undefined => {
38
+ const nextFields = FIELD_NAMES.filter((name) => name !== fieldName).join('|');
39
+ const pattern = new RegExp(`(?:^|\\s)${fieldName}=([\\s\\S]*?)(?=\\s(?:${nextFields})=|$)`);
40
+ const match = segment.match(pattern);
41
+ const value = match?.[1]?.trim();
42
+ return value && value.length > 0 ? value : undefined;
43
+ };
44
+
45
+ const humanizeRuleId = (ruleId: string): string =>
46
+ RULE_LABELS[ruleId] ??
47
+ ruleId
48
+ .replace(/^skills\./, '')
49
+ .split(/[._-]+/)
50
+ .filter(Boolean)
51
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
52
+ .join(' ');
53
+
54
+ const formatLocation = (cause: LegacySkillCause): string | null => {
55
+ if (!cause.file) {
56
+ return null;
57
+ }
58
+ const basename = path.basename(cause.file);
59
+ return cause.line ? `${basename}:${cause.line}` : basename;
60
+ };
61
+
62
+ export const extractLegacySkillCauseFromMessage = (
63
+ message?: string
64
+ ): LegacySkillCause | null => {
65
+ const segment = extractLegacySkillSegment(message);
66
+ if (!segment) {
67
+ return null;
68
+ }
69
+ const ruleId = segment.match(/\bskills\.[a-z0-9_.-]+\b/i)?.[0];
70
+ if (!ruleId) {
71
+ return null;
72
+ }
73
+ return {
74
+ ruleId,
75
+ file: extractField(segment, 'file'),
76
+ line: extractField(segment, 'lines') ?? extractField(segment, 'line'),
77
+ message: extractField(segment, 'message'),
78
+ remediation: extractField(segment, 'remediation'),
79
+ };
80
+ };
81
+
82
+ export const buildLegacySkillCauseSummary = (message?: string): string | null => {
83
+ const cause = extractLegacySkillCauseFromMessage(message);
84
+ if (!cause) {
85
+ return null;
86
+ }
87
+ const rule = humanizeRuleId(cause.ruleId);
88
+ const location = formatLocation(cause);
89
+ return location ? `Skill violada: ${location} · ${rule}` : `Skill violada: ${rule}`;
90
+ };
91
+
92
+ export const buildLegacySkillCauseRemediation = (message?: string): string | null => {
93
+ const cause = extractLegacySkillCauseFromMessage(message);
94
+ if (!cause) {
95
+ return null;
96
+ }
97
+ const rule = humanizeRuleId(cause.ruleId);
98
+ const location = formatLocation(cause);
99
+ const failure = cause.message
100
+ ? ` Falla: ${normalizeNotificationText(cause.message)}.`
101
+ : '';
102
+ const remediation = cause.remediation
103
+ ? normalizeNotificationText(cause.remediation)
104
+ : 'Corrige esa regla en el fichero afectado y vuelve a intentar el commit.';
105
+ const file = location ? ` Fichero: ${location}.` : '';
106
+ return `Regla: ${rule}.${file}${failure} Solución: ${remediation}`;
107
+ };
@@ -8,6 +8,7 @@ import {
8
8
  extractNotificationTrackingContext,
9
9
  TRACKING_BLOCKED_REMEDIATION,
10
10
  } from './framework-menu-system-notifications-tracking';
11
+ import { buildLegacySkillCauseRemediation } from './framework-menu-system-notifications-legacy-skill-cause';
11
12
 
12
13
  type BlockedRemediationVariant = 'banner' | 'dialog';
13
14
 
@@ -224,6 +225,10 @@ export const resolveBlockedRemediation = (
224
225
  if (trackingContext) {
225
226
  return truncateNotificationText(buildNotificationTrackingRemediation(trackingContext), maxLength);
226
227
  }
228
+ const legacySkillCauseRemediation = buildLegacySkillCauseRemediation(event.causeMessage);
229
+ if (legacySkillCauseRemediation) {
230
+ return truncateNotificationText(legacySkillCauseRemediation, maxLength);
231
+ }
227
232
  if (fromEvent.length > 0) {
228
233
  if (
229
234
  causeCode === 'EVIDENCE_GATE_BLOCKED' &&