pumuki 6.3.337 → 6.3.339

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.
@@ -76,25 +76,56 @@ const normalizeRuleCode = (ruleId: string): string =>
76
76
  .replace(/[.-]/gu, '_')
77
77
  .toUpperCase();
78
78
 
79
+ const extractMessageField = (message: string, field: string): string | undefined => {
80
+ const escapedField = field.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
81
+ const match = message.match(new RegExp(`\\b${escapedField}=([^\\n]+?)(?=\\s(?:severity|code|rule|file|lines?|message|remediation|snippet|node|primary_node|missing)=|\\s\\|\\|\\s\\d+\\)|$)`, 'i'));
82
+ const value = match?.[1]?.trim();
83
+ return value && value.length > 0 ? value : undefined;
84
+ };
85
+
86
+ const extractFirstNestedSkillSegment = (message: string): string =>
87
+ message
88
+ .replace(/^.*?\bBlocking causes:\s*1\)\s*/isu, '')
89
+ .replace(/\s+\|\|\s+\d+\)\s+[\s\S]*$/u, '')
90
+ .trim();
91
+
92
+ const normalizeNestedSkillMessage = (params: {
93
+ ruleId: string;
94
+ segment: string;
95
+ }): string => {
96
+ if (/\bmessage=/i.test(params.segment)) {
97
+ return params.segment;
98
+ }
99
+ const withoutRule = params.segment.replace(params.ruleId, '').trim();
100
+ return `message=${withoutRule || 'Skill violada.'}`;
101
+ };
102
+
79
103
  const extractNestedSkillCauseFromWrapper = (cause: NotificationBlockingCause): NotificationBlockingCause => {
80
104
  if (cause.ruleId?.startsWith('skills.') || cause.code.startsWith('SKILLS_')) {
81
105
  return cause;
82
106
  }
83
- const nested = cause.message.match(/\bBlocking causes:\s*1\)\s*(skills\.[a-z0-9_.-]+)\s+(.+?)$/iu);
107
+ const nested = cause.message.match(/\bBlocking causes:\s*1\)\s*(skills\.[a-z0-9_.-]+)\s+(.+?)$/isu);
84
108
  if (!nested?.[1]) {
85
109
  return cause;
86
110
  }
87
111
  const ruleId = nested[1];
88
- const nestedMessage = nested[2]?.trim() || 'Skill violada.';
112
+ const nestedMessage = extractFirstNestedSkillSegment(cause.message) || nested[2]?.trim() || 'Skill violada.';
113
+ const normalizedNestedMessage = normalizeNestedSkillMessage({
114
+ ruleId,
115
+ segment: nestedMessage,
116
+ });
117
+ const nestedFile = extractMessageField(normalizedNestedMessage, 'file');
118
+ const nestedRemediation = extractMessageField(normalizedNestedMessage, 'remediation');
89
119
  return {
90
120
  ...cause,
91
121
  code: normalizeRuleCode(ruleId),
92
122
  ruleId,
93
- message: `rule=${ruleId} message=${nestedMessage}`,
123
+ file: nestedFile ?? cause.file,
124
+ message: `rule=${ruleId} ${normalizedNestedMessage}`,
94
125
  remediation:
95
- cause.remediation && !/corrige la violaci[oó]n indicada/i.test(cause.remediation)
126
+ cause.remediation && !/corrige la violaci[oó]n indicada|corrige la causa bloqueante/i.test(cause.remediation)
96
127
  ? cause.remediation
97
- : 'Corrige la violación de la skill indicada en el fichero afectado y vuelve a intentar el commit.',
128
+ : nestedRemediation ?? 'Corrige la violación de la skill indicada en el fichero afectado y vuelve a intentar el commit.',
98
129
  };
99
130
  };
100
131
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pumuki",
3
- "version": "6.3.337",
3
+ "version": "6.3.339",
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": {
@@ -8,6 +8,7 @@ struct DialogConfig {
8
8
  let disableButton: String
9
9
  let muteButton: String
10
10
  let keepButton: String
11
+ let timeoutSeconds: Double
11
12
  }
12
13
 
13
14
  func parseArguments() -> DialogConfig {
@@ -18,13 +19,20 @@ func parseArguments() -> DialogConfig {
18
19
  }
19
20
  return args[index + 1]
20
21
  }
22
+ func readDouble(_ key: String, fallback: Double) -> Double {
23
+ guard let value = Double(read(key, fallback: String(fallback))), value > 0 else {
24
+ return fallback
25
+ }
26
+ return value
27
+ }
21
28
  return DialogConfig(
22
29
  title: read("--title", fallback: "Pumuki bloqueado"),
23
30
  cause: read("--cause", fallback: "Bloqueo detectado."),
24
31
  remediation: read("--remediation", fallback: "Corrige el bloqueo y vuelve a ejecutar."),
25
32
  disableButton: read("--disable-button", fallback: "Desactivar"),
26
33
  muteButton: read("--mute-button", fallback: "Silenciar 30 min"),
27
- keepButton: read("--keep-button", fallback: "Mantener activas")
34
+ keepButton: read("--keep-button", fallback: "Mantener activas"),
35
+ timeoutSeconds: readDouble("--timeout-seconds", fallback: 15)
28
36
  )
29
37
  }
30
38
 
@@ -69,6 +77,13 @@ final class DialogAppDelegate: NSObject, NSApplicationDelegate {
69
77
  alert.addButton(withTitle: config.muteButton)
70
78
  alert.addButton(withTitle: config.disableButton)
71
79
 
80
+ DispatchQueue.main.asyncAfter(deadline: .now() + config.timeoutSeconds) {
81
+ if alert.window.isVisible {
82
+ alert.window.orderOut(nil)
83
+ NSApp.stopModal(withCode: .alertFirstButtonReturn)
84
+ }
85
+ }
86
+
72
87
  let response = alert.runModal()
73
88
  let choice: String
74
89
  switch response {
@@ -168,7 +168,7 @@ const formatVisibleRule = (cause: BlockedCause): string => {
168
168
 
169
169
  const extractMessageField = (message: string, field: string): string | null => {
170
170
  const escapedField = field.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
171
- const match = message.match(new RegExp(`\\b${escapedField}=([^\\n]+?)(?=\\s(?:severity|code|rule|file|lines?|message|remediation|snippet|node|primary_node|missing)=|$)`, 'i'));
171
+ const match = message.match(new RegExp(`\\b${escapedField}=([^\\n]+?)(?=\\s(?:severity|code|rule|file|lines?|message|remediation|snippet|node|primary_node|missing)=|\\s\\|\\|\\s\\d+\\)|$)`, 'i'));
172
172
  const value = match?.[1]?.trim();
173
173
  return value && value.length > 0 ? normalizeNotificationText(value) : null;
174
174
  };
@@ -208,11 +208,18 @@ const normalizeRuleCode = (ruleId: string): string =>
208
208
  const isGenericCauseFix = (value?: string): boolean =>
209
209
  !value ||
210
210
  /corrige la violaci[oó]n indicada/i.test(value) ||
211
- /corrige las violaciones listadas/i.test(value);
211
+ /corrige las violaciones listadas/i.test(value) ||
212
+ /corrige la causa bloqueante/i.test(value);
212
213
 
213
214
  const extractNestedSkillRuleId = (message: string): string | null =>
214
215
  message.match(/\b(skills\.[a-z0-9_.-]+)\b/iu)?.[1] ?? null;
215
216
 
217
+ const extractFirstNestedSkillSegment = (message: string): string =>
218
+ message
219
+ .replace(/^.*?\bBlocking causes:\s*1\)\s*/isu, '')
220
+ .replace(/\s+\|\|\s+\d+\)\s+[\s\S]*$/u, '')
221
+ .trim();
222
+
216
223
  const normalizeDisplayCause = (cause: BlockedCause): BlockedCause => {
217
224
  if (isSkillCause(cause) || isSkillsContractCause(cause)) {
218
225
  return cause;
@@ -221,15 +228,17 @@ const normalizeDisplayCause = (cause: BlockedCause): BlockedCause => {
221
228
  if (!nestedSkillRuleId) {
222
229
  return cause;
223
230
  }
224
- const nestedFile = extractMessageField(cause.message, 'file');
225
- const nestedRemediation = extractMessageField(cause.message, 'remediation');
231
+ const nestedSegment = extractFirstNestedSkillSegment(cause.message);
232
+ const nestedFile = extractMessageField(nestedSegment, 'file');
233
+ const nestedRemediation = extractMessageField(nestedSegment, 'remediation');
226
234
  return {
227
235
  ...cause,
228
236
  code: normalizeRuleCode(nestedSkillRuleId),
229
237
  ruleId: nestedSkillRuleId,
230
238
  file: nestedFile ?? cause.file,
239
+ message: nestedSegment,
231
240
  remediation: isGenericCauseFix(cause.remediation)
232
- ? nestedRemediation ?? cause.remediation
241
+ ? nestedRemediation ?? 'Corrige la violación de la skill indicada en el fichero afectado y vuelve a intentar el commit.'
233
242
  : cause.remediation,
234
243
  };
235
244
  };