pumuki 6.3.357 → 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 +1 -1
- package/scripts/framework-menu-system-notifications-cause.ts +5 -0
- package/scripts/framework-menu-system-notifications-legacy-skill-cause.ts +107 -0
- package/scripts/framework-menu-system-notifications-macos-dialog-payload.ts +13 -8
- package/scripts/framework-menu-system-notifications-payloads-blocked.ts +22 -2
- package/scripts/framework-menu-system-notifications-payloads.ts +1 -0
- package/scripts/framework-menu-system-notifications-remediation.ts +5 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pumuki",
|
|
3
|
-
"version": "6.3.
|
|
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
|
+
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { PumukiCriticalNotificationEvent } from './framework-menu-system-notifications-types';
|
|
2
2
|
import {
|
|
3
|
+
resolveDisplayBlockingCausesForEvent,
|
|
3
4
|
resolvePrioritizedBlockingCauses,
|
|
4
5
|
resolveBlockedCauseSummary,
|
|
5
6
|
resolveBlockedRemediation,
|
|
@@ -332,7 +333,10 @@ const formatBlockingCauseForDialog = (
|
|
|
332
333
|
): readonly string[] => {
|
|
333
334
|
const rule = cause.ruleId ?? cause.code;
|
|
334
335
|
const visibleRule = formatVisibleRule(cause);
|
|
335
|
-
const problem = localizeDeveloperText(
|
|
336
|
+
const problem = localizeDeveloperText(
|
|
337
|
+
extractFieldFromCauseMessage(cause.message, 'message') ??
|
|
338
|
+
(stripTechnicalFieldsFromMessage(cause.message) || cause.code)
|
|
339
|
+
);
|
|
336
340
|
const remediation = isGoldenFlowCause(cause)
|
|
337
341
|
? GOLDEN_FLOW_REMEDIATION
|
|
338
342
|
: isWorktreeHygieneCause(cause)
|
|
@@ -418,17 +422,18 @@ export const buildBlockedDialogPayload = (params: {
|
|
|
418
422
|
env: NodeJS.ProcessEnv;
|
|
419
423
|
}): BlockedDialogPayload => {
|
|
420
424
|
const causeCode = params.event.causeCode ?? 'GATE_BLOCKED';
|
|
421
|
-
const
|
|
425
|
+
const displayBlockingCauses = resolveDisplayBlockingCausesForEvent(params.event);
|
|
426
|
+
const cause = buildBlockingCausesDetails(displayBlockingCauses)
|
|
422
427
|
?? resolveBlockedCauseSummary(params.event, causeCode);
|
|
423
|
-
const remediation = hasOnlyWorktreeHygieneCauses(
|
|
428
|
+
const remediation = hasOnlyWorktreeHygieneCauses(displayBlockingCauses)
|
|
424
429
|
? WORKTREE_HYGIENE_REMEDIATION
|
|
425
|
-
: hasOnlyGoldenFlowCauses(
|
|
426
|
-
? resolveGoldenFlowDialogRemediation(
|
|
427
|
-
: hasOnlyBddScenarioMissingCauses(
|
|
430
|
+
: hasOnlyGoldenFlowCauses(displayBlockingCauses)
|
|
431
|
+
? resolveGoldenFlowDialogRemediation(displayBlockingCauses)
|
|
432
|
+
: hasOnlyBddScenarioMissingCauses(displayBlockingCauses)
|
|
428
433
|
? 'Crea el fichero .feature esperado para la slice activa o corrige la referencia de tarea. Después vuelve a intentar el commit.'
|
|
429
|
-
: hasOnlySkillsContractCauses(
|
|
434
|
+
: hasOnlySkillsContractCauses(displayBlockingCauses)
|
|
430
435
|
? SKILLS_CONTRACT_DIALOG_REMEDIATION
|
|
431
|
-
:
|
|
436
|
+
: displayBlockingCauses.length > 0
|
|
432
437
|
? 'Corrige las violaciones listadas y vuelve a intentar el commit.'
|
|
433
438
|
: resolveBlockedRemediation(params.event, causeCode);
|
|
434
439
|
const projectLabel = resolveProjectLabel({
|
|
@@ -275,6 +275,25 @@ const normalizeDisplayCause = (cause: BlockedCause): BlockedCause => {
|
|
|
275
275
|
};
|
|
276
276
|
};
|
|
277
277
|
|
|
278
|
+
export const resolveDisplayBlockingCausesForEvent = (
|
|
279
|
+
event: Extract<PumukiCriticalNotificationEvent, { kind: 'gate.blocked' }>
|
|
280
|
+
): ReadonlyArray<BlockedCause> => {
|
|
281
|
+
if (event.blockingCauses && event.blockingCauses.length > 0) {
|
|
282
|
+
return event.blockingCauses;
|
|
283
|
+
}
|
|
284
|
+
if (!event.causeMessage || !/\bBlocking causes:\s*1\)\s*skills\./iu.test(event.causeMessage)) {
|
|
285
|
+
return [];
|
|
286
|
+
}
|
|
287
|
+
return [
|
|
288
|
+
{
|
|
289
|
+
code: event.causeCode ?? 'EVIDENCE_GATE_BLOCKED',
|
|
290
|
+
ruleId: 'ai_gate.repo_policy',
|
|
291
|
+
message: event.causeMessage,
|
|
292
|
+
remediation: event.remediation,
|
|
293
|
+
},
|
|
294
|
+
];
|
|
295
|
+
};
|
|
296
|
+
|
|
278
297
|
export const resolvePrioritizedBlockingCauses = (
|
|
279
298
|
causes: Extract<PumukiCriticalNotificationEvent, { kind: 'gate.blocked' }>['blockingCauses']
|
|
280
299
|
): ReadonlyArray<BlockedCause> => {
|
|
@@ -376,12 +395,13 @@ export const buildGateBlockedPayload = (
|
|
|
376
395
|
projectPrefix: string
|
|
377
396
|
): SystemNotificationPayload => {
|
|
378
397
|
const causeCode = event.causeCode ?? 'GATE_BLOCKED';
|
|
398
|
+
const displayBlockingCauses = resolveDisplayBlockingCausesForEvent(event);
|
|
379
399
|
const causeSummary = truncateNotificationText(
|
|
380
|
-
buildBlockingCausesSummary(
|
|
400
|
+
buildBlockingCausesSummary(displayBlockingCauses) ?? resolveBlockedCauseSummary(event, causeCode),
|
|
381
401
|
96
|
|
382
402
|
);
|
|
383
403
|
const remediation =
|
|
384
|
-
buildBlockingCausesRemediation(
|
|
404
|
+
buildBlockingCausesRemediation(displayBlockingCauses) ?? resolveBlockedRemediation(event, causeCode);
|
|
385
405
|
return {
|
|
386
406
|
title: '🔴 Pumuki bloqueado',
|
|
387
407
|
subtitle: `${projectPrefix}${event.stage} · ${causeSummary}`,
|
|
@@ -27,6 +27,7 @@ export {
|
|
|
27
27
|
} from './framework-menu-system-notifications-payloads-audit';
|
|
28
28
|
export {
|
|
29
29
|
buildGateBlockedPayload,
|
|
30
|
+
resolveDisplayBlockingCausesForEvent,
|
|
30
31
|
resolvePrioritizedBlockingCauses,
|
|
31
32
|
} from './framework-menu-system-notifications-payloads-blocked';
|
|
32
33
|
export {
|
|
@@ -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' &&
|