pumuki 6.3.102 → 6.3.103
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/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,14 @@ This project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [6.3.103] - 2026-04-22
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- **Diagnóstico accionable del tracking canónico en consumers:** `status`, `doctor` y el gate repo-policy ya incluyen `TRACKING_CANONICAL_IN_PROGRESS_INVALID` junto con referencias a entradas activas y al board canónico del repo consumidor cuando existe.
|
|
14
|
+
- **Separación explícita entre blocker y warning secundario:** la salida de `PRE_WRITE` conserva un `block-summary` primario y añade `warning-summary` para warnings de higiene (`EVIDENCE_PREWRITE_WORKTREE_WARN`) cuando conviven con un bloqueo duro de tracking.
|
|
15
|
+
- **Cobertura de regresión del hotfix:** nuevas pruebas fijan el parsing de boards tabulares `🚧 reported activo` y la impresión del resumen jerárquico con warning secundario.
|
|
16
|
+
|
|
9
17
|
## [6.3.102] - 2026-04-22
|
|
10
18
|
|
|
11
19
|
### Fixed
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
v6.3.
|
|
1
|
+
v6.3.103
|
|
@@ -6,6 +6,12 @@ This file keeps only the operational highlights and rollout notes that matter wh
|
|
|
6
6
|
|
|
7
7
|
## 2026-04 (CLI stability and macOS notifications)
|
|
8
8
|
|
|
9
|
+
### 2026-04-22 (v6.3.103)
|
|
10
|
+
|
|
11
|
+
- **Tracking canónico accionable:** `status`, `doctor` y el gate repo-policy enriquecen `TRACKING_CANONICAL_IN_PROGRESS_INVALID` con referencias a las entradas activas detectadas en el board del consumer.
|
|
12
|
+
- **PRE_WRITE menos ambiguo:** cuando un warning de higiene de worktree convive con un bloqueo duro, el runtime imprime `warning-summary` separado del `block-summary`.
|
|
13
|
+
- **Rollout recomendado:** publicar `pumuki@6.3.103`, repin inmediato en `RuralGo` y revalidar `status` / `doctor` / `git commit` sobre un board con varias filas `🚧 reported activo`.
|
|
14
|
+
|
|
9
15
|
### 2026-04-22 (v6.3.102)
|
|
10
16
|
|
|
11
17
|
- **Convergencia de policy efectiva:** `strict` deja de depender solo de `PUMUKI_POLICY_STRICT` cuando el contrato firmado ya lo declara por stage; `status`, `doctor` y runtime vuelven a hablar el mismo idioma.
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
1
3
|
import type { Finding } from '../../core/gate/Finding';
|
|
2
4
|
import type { GateStage } from '../../core/gate/GateStage';
|
|
3
5
|
import { evaluateAiGate, type AiGateStage } from '../gate/evaluateAiGate';
|
|
@@ -6,10 +8,82 @@ const AI_GATE_STAGES = new Set<AiGateStage>(['PRE_WRITE', 'PRE_COMMIT', 'PRE_PUS
|
|
|
6
8
|
|
|
7
9
|
const REPO_POLICY_CODES = new Set<string>([
|
|
8
10
|
'GITFLOW_PROTECTED_BRANCH',
|
|
11
|
+
'TRACKING_CANONICAL_IN_PROGRESS_INVALID',
|
|
9
12
|
'EVIDENCE_PREWRITE_WORKTREE_OVER_LIMIT',
|
|
10
13
|
'EVIDENCE_PREWRITE_WORKTREE_WARN',
|
|
11
14
|
]);
|
|
12
15
|
|
|
16
|
+
const TRACKING_CANDIDATE_FILES = [
|
|
17
|
+
'docs/technical/08-validation/refactor/pumuki-integration-feedback.md',
|
|
18
|
+
'docs/pumuki/PUMUKI_BUGS_MEJORAS.md',
|
|
19
|
+
'docs/BUGS_Y_MEJORAS_PUMUKI.md',
|
|
20
|
+
'PUMUKI-RESET-MASTER-PLAN.md',
|
|
21
|
+
'RURALGO_SEGUIMIENTO.md',
|
|
22
|
+
] as const;
|
|
23
|
+
|
|
24
|
+
type TrackingActiveEntry = {
|
|
25
|
+
taskId: string | null;
|
|
26
|
+
lineNumber: number;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export const collectTrackingActiveEntriesFromMarkdown = (
|
|
30
|
+
markdown: string
|
|
31
|
+
): ReadonlyArray<TrackingActiveEntry> => {
|
|
32
|
+
const entries: TrackingActiveEntry[] = [];
|
|
33
|
+
const lines = markdown.split(/\r?\n/u);
|
|
34
|
+
for (const [index, line] of lines.entries()) {
|
|
35
|
+
const tableMatch = line.match(
|
|
36
|
+
/^\|\s*\d+\s*\|\s*`([^`]+)`\s*\|.*\|\s*🚧(?:\s+reported\s+activo|\s+En construcción|\s+En construccion)?\s*\|/u
|
|
37
|
+
);
|
|
38
|
+
if (tableMatch) {
|
|
39
|
+
entries.push({
|
|
40
|
+
taskId: tableMatch[1]!.trim(),
|
|
41
|
+
lineNumber: index + 1,
|
|
42
|
+
});
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
const bulletMatch = line.match(/^- 🚧 (`?P[0-9A-Za-z.-]+`?)/u);
|
|
46
|
+
if (bulletMatch) {
|
|
47
|
+
entries.push({
|
|
48
|
+
taskId: bulletMatch[1]!.replaceAll('`', '').trim(),
|
|
49
|
+
lineNumber: index + 1,
|
|
50
|
+
});
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (/^- Estado:\s*🚧/u.test(line)) {
|
|
54
|
+
entries.push({
|
|
55
|
+
taskId: null,
|
|
56
|
+
lineNumber: index + 1,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return entries;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const formatTrackingEntry = (entry: TrackingActiveEntry): string =>
|
|
64
|
+
entry.taskId ? `${entry.taskId}@L${entry.lineNumber}` : `line_${entry.lineNumber}`;
|
|
65
|
+
|
|
66
|
+
export const appendTrackingActionableContext = (params: {
|
|
67
|
+
repoRoot: string;
|
|
68
|
+
message: string;
|
|
69
|
+
}): string => {
|
|
70
|
+
for (const candidate of TRACKING_CANDIDATE_FILES) {
|
|
71
|
+
const candidatePath = resolve(params.repoRoot, candidate);
|
|
72
|
+
if (!existsSync(candidatePath)) {
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
const source = readFileSync(candidatePath, 'utf8');
|
|
76
|
+
const entries = collectTrackingActiveEntriesFromMarkdown(source);
|
|
77
|
+
if (entries.length === 0) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
const preview = entries.slice(0, 3).map(formatTrackingEntry).join(', ');
|
|
81
|
+
const overflow = entries.length > 3 ? ` (+${entries.length - 3} more)` : '';
|
|
82
|
+
return `${params.message} active_entries=${preview}${overflow} tracking_source=${candidate}`;
|
|
83
|
+
}
|
|
84
|
+
return params.message;
|
|
85
|
+
};
|
|
86
|
+
|
|
13
87
|
const toRepoPolicyFinding = (params: {
|
|
14
88
|
code: string;
|
|
15
89
|
message: string;
|
|
@@ -39,7 +113,13 @@ export const collectAiGateRepoPolicyFindings = (params: {
|
|
|
39
113
|
.map((v) =>
|
|
40
114
|
toRepoPolicyFinding({
|
|
41
115
|
code: v.code,
|
|
42
|
-
message:
|
|
116
|
+
message:
|
|
117
|
+
v.code === 'TRACKING_CANONICAL_IN_PROGRESS_INVALID'
|
|
118
|
+
? appendTrackingActionableContext({
|
|
119
|
+
repoRoot: params.repoRoot,
|
|
120
|
+
message: v.message,
|
|
121
|
+
})
|
|
122
|
+
: v.message,
|
|
43
123
|
severity: v.severity === 'ERROR' ? 'ERROR' : 'WARN',
|
|
44
124
|
})
|
|
45
125
|
);
|
|
@@ -52,6 +52,15 @@ const resolvePrimaryFinding = (findings: ReadonlyArray<Finding>): Finding => {
|
|
|
52
52
|
return primary ?? findings[0]!;
|
|
53
53
|
};
|
|
54
54
|
|
|
55
|
+
const sortFindingsBySeverity = (findings: ReadonlyArray<Finding>): ReadonlyArray<Finding> =>
|
|
56
|
+
[...findings].sort((left, right) => {
|
|
57
|
+
const severityDelta = severityWeight(right.severity) - severityWeight(left.severity);
|
|
58
|
+
if (severityDelta !== 0) {
|
|
59
|
+
return severityDelta;
|
|
60
|
+
}
|
|
61
|
+
return left.ruleId.localeCompare(right.ruleId);
|
|
62
|
+
});
|
|
63
|
+
|
|
55
64
|
const normalizeAnchorLine = (lines: Finding['lines']): number => {
|
|
56
65
|
if (Array.isArray(lines)) {
|
|
57
66
|
const candidates = lines
|
|
@@ -98,7 +107,8 @@ export const printGateFindings = (findings: ReadonlyArray<Finding>): void => {
|
|
|
98
107
|
if (findings.length === 0) {
|
|
99
108
|
return;
|
|
100
109
|
}
|
|
101
|
-
const
|
|
110
|
+
const orderedFindings = sortFindingsBySeverity(findings);
|
|
111
|
+
const primary = resolvePrimaryFinding(orderedFindings);
|
|
102
112
|
const nextAction =
|
|
103
113
|
BLOCK_NEXT_ACTION_BY_CODE[primary.code]
|
|
104
114
|
?? 'Corrige el bloqueante primario y vuelve a ejecutar el mismo comando.';
|
|
@@ -106,7 +116,17 @@ export const printGateFindings = (findings: ReadonlyArray<Finding>): void => {
|
|
|
106
116
|
`[pumuki][block-summary] primary=${primary.code} severity=${primary.severity.toUpperCase()} rule=${primary.ruleId}\n`
|
|
107
117
|
);
|
|
108
118
|
process.stdout.write(`[pumuki][block-summary] next_action=${nextAction}\n`);
|
|
109
|
-
|
|
119
|
+
const secondaryWarnings = orderedFindings.filter(
|
|
120
|
+
(finding) =>
|
|
121
|
+
finding !== primary &&
|
|
122
|
+
severityWeight(finding.severity) < severityWeight(primary.severity)
|
|
123
|
+
);
|
|
124
|
+
for (const finding of secondaryWarnings) {
|
|
125
|
+
process.stdout.write(
|
|
126
|
+
`[pumuki][warning-summary] secondary=${finding.code} severity=${finding.severity.toUpperCase()} rule=${finding.ruleId}\n`
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
for (const finding of orderedFindings) {
|
|
110
130
|
process.stdout.write(`${formatFinding(finding)}\n`);
|
|
111
131
|
}
|
|
112
132
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pumuki",
|
|
3
|
-
"version": "6.3.
|
|
3
|
+
"version": "6.3.103",
|
|
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": {
|