pumuki 6.3.352 → 6.3.354

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.
@@ -30,6 +30,8 @@ type NotificationBlockingCause = {
30
30
  message: string;
31
31
  ruleId?: string;
32
32
  file?: string;
33
+ line?: number;
34
+ lines?: ReadonlyArray<number>;
33
35
  remediation?: string;
34
36
  };
35
37
 
@@ -83,6 +85,48 @@ const extractMessageField = (message: string, field: string): string | undefined
83
85
  return value && value.length > 0 ? value : undefined;
84
86
  };
85
87
 
88
+ const normalizeEvidenceLinesForNotification = (
89
+ lines: unknown
90
+ ): Pick<NotificationBlockingCause, 'line' | 'lines'> => {
91
+ if (typeof lines === 'number' && Number.isFinite(lines) && lines > 0) {
92
+ return {
93
+ line: Math.floor(lines),
94
+ };
95
+ }
96
+ if (Array.isArray(lines)) {
97
+ const normalized = Array.from(
98
+ new Set(
99
+ lines
100
+ .filter((line): line is number => typeof line === 'number' && Number.isFinite(line) && line > 0)
101
+ .map((line) => Math.floor(line))
102
+ )
103
+ ).sort((left, right) => left - right);
104
+ return normalized.length > 0 ? { lines: normalized } : {};
105
+ }
106
+ if (typeof lines === 'string') {
107
+ const normalized = Array.from(
108
+ new Set(
109
+ lines
110
+ .split(',')
111
+ .map((line) => Number.parseInt(line.trim(), 10))
112
+ .filter((line) => Number.isFinite(line) && line > 0)
113
+ )
114
+ ).sort((left, right) => left - right);
115
+ return normalized.length > 0 ? { lines: normalized } : {};
116
+ }
117
+ return {};
118
+ };
119
+
120
+ const extractStructuredLinesFromMessage = (
121
+ message: string
122
+ ): Pick<NotificationBlockingCause, 'line' | 'lines'> => {
123
+ const raw = message.match(/\blines?=([0-9][0-9,\-\s]*)\b/i)?.[1];
124
+ if (!raw) {
125
+ return {};
126
+ }
127
+ return normalizeEvidenceLinesForNotification(raw);
128
+ };
129
+
86
130
  const extractFirstNestedSkillSegment = (message: string): string =>
87
131
  message
88
132
  .replace(/^.*?\bBlocking causes:\s*1\)\s*/isu, '')
@@ -121,6 +165,11 @@ const extractNestedSkillCauseFromWrapper = (cause: NotificationBlockingCause): N
121
165
  code: normalizeRuleCode(ruleId),
122
166
  ruleId,
123
167
  file: nestedFile ?? cause.file,
168
+ ...(
169
+ cause.line || cause.lines
170
+ ? {}
171
+ : extractStructuredLinesFromMessage(normalizedNestedMessage)
172
+ ),
124
173
  message: `rule=${ruleId} ${normalizedNestedMessage}`,
125
174
  remediation:
126
175
  cause.remediation && !/corrige la violaci[oó]n indicada|corrige la causa bloqueante/i.test(cause.remediation)
@@ -163,6 +212,7 @@ export const toAuditSummaryEventFromEvidence = (
163
212
  code: cause.code,
164
213
  ruleId: cause.ruleId,
165
214
  file: cause.file,
215
+ ...normalizeEvidenceLinesForNotification(cause.lines),
166
216
  message: formatEvidenceBlockingCause(cause),
167
217
  remediation: cause.remediation,
168
218
  })
@@ -204,6 +254,7 @@ export const toAuditSummaryEventFromAiGate = (params: {
204
254
  ruleId: violation.code.startsWith('skills.') ? violation.code : undefined,
205
255
  message: violation.message,
206
256
  remediation: 'Corrige la violación indicada y vuelve a intentar el commit.',
257
+ ...extractStructuredLinesFromMessage(violation.message),
207
258
  })
208
259
  ),
209
260
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pumuki",
3
- "version": "6.3.352",
3
+ "version": "6.3.354",
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": {
@@ -137,6 +137,17 @@ const formatLocation = (cause: NonNullable<Extract<PumukiCriticalNotificationEve
137
137
  if (!cause.file) {
138
138
  return 'sin fichero';
139
139
  }
140
+ if (typeof cause.line === 'number' && Number.isFinite(cause.line) && cause.line > 0) {
141
+ return `${cause.file}:${Math.floor(cause.line)}`;
142
+ }
143
+ if (Array.isArray(cause.lines)) {
144
+ const lines = cause.lines
145
+ .filter((line) => Number.isFinite(line) && line > 0)
146
+ .map((line) => Math.floor(line));
147
+ if (lines.length > 0) {
148
+ return `${cause.file}:${lines.join(',')}`;
149
+ }
150
+ }
140
151
  const line = extractLineFromCauseMessage(cause.message);
141
152
  return line ? `${cause.file}:${line}` : cause.file;
142
153
  };
@@ -118,6 +118,17 @@ const formatCauseLocation = (cause: BlockedCause): string => {
118
118
  return 'sin fichero';
119
119
  }
120
120
  const baseFile = cause.file.split('/').filter(Boolean).pop() ?? cause.file;
121
+ if (typeof cause.line === 'number' && Number.isFinite(cause.line) && cause.line > 0) {
122
+ return `${baseFile}:${Math.floor(cause.line)}`;
123
+ }
124
+ if (Array.isArray(cause.lines)) {
125
+ const lines = cause.lines
126
+ .filter((line) => Number.isFinite(line) && line > 0)
127
+ .map((line) => Math.floor(line));
128
+ if (lines.length > 0) {
129
+ return `${baseFile}:${lines.join(',')}`;
130
+ }
131
+ }
121
132
  const lineMatch = cause.message.match(/\blines?=([0-9][0-9,\-\s]*)\b/i);
122
133
  if (!lineMatch?.[1]) {
123
134
  return baseFile;