pumuki 6.3.140 → 6.3.142
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 +13 -0
- package/core/facts/detectors/typescript/index.test.ts +28 -0
- package/core/facts/detectors/typescript/index.ts +4 -0
- package/core/rules/presets/iosEnterpriseRuleSet.test.ts +5 -0
- package/core/rules/presets/iosEnterpriseRuleSet.ts +5 -5
- package/docs/operations/RELEASE_NOTES.md +12 -0
- package/integrations/config/skillsDetectorRegistry.ts +15 -0
- package/integrations/config/skillsMarkdownRules.ts +21 -0
- package/integrations/config/skillsRuleSet.ts +4 -1
- package/integrations/git/gitAtomicity.ts +86 -21
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,19 @@ This project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [6.3.142] - 2026-05-05
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- **PUMUKI-INC-059 iOS SOLID en PRE_WRITE:** la skill iOS `Verificar que NO viole SOLID (SRP, OCP, LSP, ISP, DIP)` se normaliza al id canónico `skills.ios.no-solid-violations` y al alias real del lock legacy, activa los nodos AST OCP/SRP/DIP/ISP/LSP y bloquea desde `PRE_WRITE` sin depender de `PUMUKI_ENABLE_AST_HEURISTICS`.
|
|
14
|
+
- **Skills hard-blocking multi-stage:** `no-solid-violations` se promueve a bloqueo desde `PRE_WRITE`, `PRE_COMMIT`, `PRE_PUSH` y `CI`, evitando que una violación iOS OCP/SRP llegue a disco o al commit.
|
|
15
|
+
|
|
16
|
+
## [6.3.141] - 2026-05-05
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- **PRE_PUSH en ramas actualizadas desde base:** el guard de atomicidad ignora commits heredados de `main`/`develop` y commits merge al validar trazabilidad y límites por commit, evitando bloqueos falsos en rollouts que solo resolvieron conflictos con la rama base.
|
|
21
|
+
|
|
9
22
|
## [6.3.140] - 2026-05-05
|
|
10
23
|
|
|
11
24
|
### Fixed
|
|
@@ -4248,6 +4248,34 @@ test('hasHardcodedValuePattern detecta literals de configuracion y omite valores
|
|
|
4248
4248
|
assert.equal(hasHardcodedValuePattern(neutralLiteralAst), false);
|
|
4249
4249
|
});
|
|
4250
4250
|
|
|
4251
|
+
test('hasHardcodedValuePattern no bloquea tokens internos de metadata AST', () => {
|
|
4252
|
+
const astNodeTokenAst = {
|
|
4253
|
+
type: 'VariableDeclarator',
|
|
4254
|
+
id: { type: 'Identifier', name: 'astNodeToken' },
|
|
4255
|
+
init: {
|
|
4256
|
+
type: 'StringLiteral',
|
|
4257
|
+
value: 'none',
|
|
4258
|
+
loc: { start: { line: 4 }, end: { line: 4 } },
|
|
4259
|
+
},
|
|
4260
|
+
loc: { start: { line: 4 }, end: { line: 4 } },
|
|
4261
|
+
};
|
|
4262
|
+
const astNodesTokenAst = {
|
|
4263
|
+
type: 'VariableDeclarator',
|
|
4264
|
+
id: { type: 'Identifier', name: 'astNodesToken' },
|
|
4265
|
+
init: {
|
|
4266
|
+
type: 'StringLiteral',
|
|
4267
|
+
value: 'none',
|
|
4268
|
+
loc: { start: { line: 8 }, end: { line: 8 } },
|
|
4269
|
+
},
|
|
4270
|
+
loc: { start: { line: 8 }, end: { line: 8 } },
|
|
4271
|
+
};
|
|
4272
|
+
|
|
4273
|
+
assert.equal(hasHardcodedValuePattern(astNodeTokenAst), false);
|
|
4274
|
+
assert.equal(findHardcodedValuePatternMatch(astNodeTokenAst), undefined);
|
|
4275
|
+
assert.equal(hasHardcodedValuePattern(astNodesTokenAst), false);
|
|
4276
|
+
assert.equal(findHardcodedValuePatternMatch(astNodesTokenAst), undefined);
|
|
4277
|
+
});
|
|
4278
|
+
|
|
4251
4279
|
test('hasHardcodedValuePattern usa tokens exactos y no subcadenas accidentales', () => {
|
|
4252
4280
|
const reportFunctionAst = {
|
|
4253
4281
|
type: 'FunctionDeclaration',
|
|
@@ -4908,6 +4908,10 @@ const isBenignConfigMetadataName = (value: string): boolean => {
|
|
|
4908
4908
|
if (normalized.length === 0) {
|
|
4909
4909
|
return true;
|
|
4910
4910
|
}
|
|
4911
|
+
const tokenSet = new Set(identifierNameTokens(normalized));
|
|
4912
|
+
if (tokenSet.has('ast') && (tokenSet.has('node') || tokenSet.has('nodes')) && tokenSet.has('token')) {
|
|
4913
|
+
return true;
|
|
4914
|
+
}
|
|
4911
4915
|
if (
|
|
4912
4916
|
normalized.startsWith('skills.') ||
|
|
4913
4917
|
normalized.startsWith('heuristics.') ||
|
|
@@ -33,6 +33,11 @@ test('iosEnterpriseRuleSet define reglas locked para plataforma ios', () => {
|
|
|
33
33
|
assert.equal(byId.get('ios.solid.isp.fat-protocol-dependency')?.when.kind, 'Heuristic');
|
|
34
34
|
assert.equal(byId.get('ios.solid.lsp.narrowed-precondition-substitution')?.when.kind, 'Heuristic');
|
|
35
35
|
assert.equal(byId.get('ios.solid.srp.presentation-mixed-responsibilities')?.when.kind, 'Heuristic');
|
|
36
|
+
assert.equal(byId.get('ios.solid.ocp.discriminator-switch-branching')?.stage, 'PRE_WRITE');
|
|
37
|
+
assert.equal(byId.get('ios.solid.dip.concrete-framework-dependency')?.stage, 'PRE_WRITE');
|
|
38
|
+
assert.equal(byId.get('ios.solid.isp.fat-protocol-dependency')?.stage, 'PRE_WRITE');
|
|
39
|
+
assert.equal(byId.get('ios.solid.lsp.narrowed-precondition-substitution')?.stage, 'PRE_WRITE');
|
|
40
|
+
assert.equal(byId.get('ios.solid.srp.presentation-mixed-responsibilities')?.stage, 'PRE_WRITE');
|
|
36
41
|
assert.equal(byId.get('ios.canary-001.presentation-mixed-responsibilities')?.when.kind, 'Heuristic');
|
|
37
42
|
assert.equal(byId.get('ios.tdd.domain-changes-require-tests')?.when.kind, 'All');
|
|
38
43
|
assert.equal(byId.get('ios.no-completion-handlers-outside-bridges')?.when.kind, 'Heuristic');
|
|
@@ -44,7 +44,7 @@ export const iosEnterpriseRuleSet: RuleSet = [
|
|
|
44
44
|
'Blocks iOS application or presentation types that must be modified to support new discriminator cases instead of extending behavior through abstractions.',
|
|
45
45
|
severity: 'CRITICAL',
|
|
46
46
|
platform: 'ios',
|
|
47
|
-
stage: '
|
|
47
|
+
stage: 'PRE_WRITE',
|
|
48
48
|
locked: true,
|
|
49
49
|
scope: {
|
|
50
50
|
include: ['**/*.swift'],
|
|
@@ -70,7 +70,7 @@ export const iosEnterpriseRuleSet: RuleSet = [
|
|
|
70
70
|
'Blocks iOS application or presentation types that depend directly on concrete framework services instead of abstractions.',
|
|
71
71
|
severity: 'CRITICAL',
|
|
72
72
|
platform: 'ios',
|
|
73
|
-
stage: '
|
|
73
|
+
stage: 'PRE_WRITE',
|
|
74
74
|
locked: true,
|
|
75
75
|
scope: {
|
|
76
76
|
include: ['**/*.swift'],
|
|
@@ -96,7 +96,7 @@ export const iosEnterpriseRuleSet: RuleSet = [
|
|
|
96
96
|
'Blocks iOS application or presentation types that depend on fat protocols instead of a minimal port tailored to the members they actually use.',
|
|
97
97
|
severity: 'CRITICAL',
|
|
98
98
|
platform: 'ios',
|
|
99
|
-
stage: '
|
|
99
|
+
stage: 'PRE_WRITE',
|
|
100
100
|
locked: true,
|
|
101
101
|
scope: {
|
|
102
102
|
include: ['**/*.swift'],
|
|
@@ -122,7 +122,7 @@ export const iosEnterpriseRuleSet: RuleSet = [
|
|
|
122
122
|
'Blocks iOS application or presentation types whose subtype narrows the contract preconditions and becomes unsafe to substitute for the base protocol or abstraction.',
|
|
123
123
|
severity: 'CRITICAL',
|
|
124
124
|
platform: 'ios',
|
|
125
|
-
stage: '
|
|
125
|
+
stage: 'PRE_WRITE',
|
|
126
126
|
locked: true,
|
|
127
127
|
scope: {
|
|
128
128
|
include: ['**/*.swift'],
|
|
@@ -148,7 +148,7 @@ export const iosEnterpriseRuleSet: RuleSet = [
|
|
|
148
148
|
'Blocks iOS presentation types that mix session, networking, persistence and navigation responsibilities in the same semantic node.',
|
|
149
149
|
severity: 'CRITICAL',
|
|
150
150
|
platform: 'ios',
|
|
151
|
-
stage: '
|
|
151
|
+
stage: 'PRE_WRITE',
|
|
152
152
|
locked: true,
|
|
153
153
|
scope: {
|
|
154
154
|
include: ['**/*.swift'],
|
|
@@ -4,6 +4,18 @@ This file tracks the active deterministic framework line used in this repository
|
|
|
4
4
|
Canonical release chronology lives in `CHANGELOG.md`.
|
|
5
5
|
This file keeps only the operational highlights and rollout notes that matter while running the framework.
|
|
6
6
|
|
|
7
|
+
### 2026-05-05 (v6.3.142)
|
|
8
|
+
|
|
9
|
+
- **RuralGo PUMUKI-INC-059:** PRE_WRITE vuelve a pedir hechos AST para iOS SOLID aunque el flag experimental de heurísticas esté apagado.
|
|
10
|
+
- **OCP/SRP iOS bloqueante temprano:** `skills.ios.no-solid-violations` y el id real legacy del lock se vinculan a OCP/SRP/DIP/ISP/LSP; los findings se promueven a `ERROR` desde PRE_WRITE.
|
|
11
|
+
- **Rollout:** publicar `pumuki@6.3.142`, repinear primero RuralGo y revalidar `status`, `doctor` y un canary OCP iOS en PRE_WRITE/PRE_COMMIT.
|
|
12
|
+
|
|
13
|
+
### 2026-05-05 (v6.3.141)
|
|
14
|
+
|
|
15
|
+
- **PRE_PUSH sin falso bloqueo por historial base:** ramas de rollout que integran `main`/`develop` dejan de fallar por commits merge heredados como `Merge pull request ...`.
|
|
16
|
+
- **Flux/SAAS follow-up:** esta patch desbloquea el push de las resoluciones de conflicto de los PRs de repin abiertos tras `6.3.140`.
|
|
17
|
+
- **Rollout:** publicar `pumuki@6.3.141`, repinear primero RuralGo y repetir Flux/SAAS sin bypass.
|
|
18
|
+
|
|
7
19
|
### 2026-05-05 (v6.3.140)
|
|
8
20
|
|
|
9
21
|
- **PRE_PUSH compatible con ramas largas:** la atomicidad se valida por commit individual, no por diff agregado de rama.
|
|
@@ -160,6 +160,21 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
|
|
|
160
160
|
'ios.core-data.nsmanagedobject-state-leak',
|
|
161
161
|
['heuristics.ios.core-data.nsmanagedobject-state-leak.ast']
|
|
162
162
|
),
|
|
163
|
+
'skills.ios.no-solid-violations': heuristicDetector('ios.solid', [
|
|
164
|
+
'heuristics.ios.solid.srp.presentation-mixed-responsibilities.ast',
|
|
165
|
+
'heuristics.ios.solid.dip.concrete-framework-dependency.ast',
|
|
166
|
+
'heuristics.ios.solid.ocp.discriminator-switch.ast',
|
|
167
|
+
'heuristics.ios.solid.isp.fat-protocol-dependency.ast',
|
|
168
|
+
'heuristics.ios.solid.lsp.narrowed-precondition.ast',
|
|
169
|
+
]),
|
|
170
|
+
'skills.ios.guideline.ios.verificar-que-no-viole-solid-srp-ocp-lsp-isp-dip':
|
|
171
|
+
heuristicDetector('ios.solid', [
|
|
172
|
+
'heuristics.ios.solid.srp.presentation-mixed-responsibilities.ast',
|
|
173
|
+
'heuristics.ios.solid.dip.concrete-framework-dependency.ast',
|
|
174
|
+
'heuristics.ios.solid.ocp.discriminator-switch.ast',
|
|
175
|
+
'heuristics.ios.solid.isp.fat-protocol-dependency.ast',
|
|
176
|
+
'heuristics.ios.solid.lsp.narrowed-precondition.ast',
|
|
177
|
+
]),
|
|
163
178
|
'skills.android.no-solid-violations': heuristicDetector('android.solid', [
|
|
164
179
|
'heuristics.android.solid.srp.presentation-mixed-responsibilities.ast',
|
|
165
180
|
'heuristics.android.solid.dip.concrete-framework-dependency.ast',
|
|
@@ -90,6 +90,8 @@ const inferRuleStage = (raw: string): SkillsStage | undefined => {
|
|
|
90
90
|
};
|
|
91
91
|
|
|
92
92
|
const KNOWN_RULE_DEFAULT_STAGE: Readonly<Record<string, SkillsStage>> = {
|
|
93
|
+
'skills.ios.no-solid-violations': 'PRE_WRITE',
|
|
94
|
+
'skills.ios.guideline.ios.verificar-que-no-viole-solid-srp-ocp-lsp-isp-dip': 'PRE_WRITE',
|
|
93
95
|
'skills.backend.no-solid-violations': 'PRE_PUSH',
|
|
94
96
|
'skills.frontend.no-solid-violations': 'PRE_PUSH',
|
|
95
97
|
'skills.backend.enforce-clean-architecture': 'PRE_PUSH',
|
|
@@ -275,8 +277,27 @@ const normalizeKnownRuleTarget = (
|
|
|
275
277
|
normalizedDescription: string
|
|
276
278
|
): string | null => {
|
|
277
279
|
const includes = (needle: string): boolean => normalizedDescription.includes(needle);
|
|
280
|
+
const hasWord = (needle: string): boolean =>
|
|
281
|
+
new RegExp(`(^|\\s)${needle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}(\\s|$)`).test(
|
|
282
|
+
normalizedDescription
|
|
283
|
+
);
|
|
278
284
|
|
|
279
285
|
if (platform === 'ios') {
|
|
286
|
+
if (
|
|
287
|
+
includes('solid') ||
|
|
288
|
+
includes('single responsibility') ||
|
|
289
|
+
hasWord('srp') ||
|
|
290
|
+
hasWord('ocp') ||
|
|
291
|
+
hasWord('lsp') ||
|
|
292
|
+
hasWord('isp') ||
|
|
293
|
+
hasWord('dip') ||
|
|
294
|
+
includes('open closed') ||
|
|
295
|
+
includes('open-closed') ||
|
|
296
|
+
includes('verificar que no viole solid') ||
|
|
297
|
+
includes('no viole solid')
|
|
298
|
+
) {
|
|
299
|
+
return 'skills.ios.no-solid-violations';
|
|
300
|
+
}
|
|
280
301
|
if (
|
|
281
302
|
includes('force unwrap') ||
|
|
282
303
|
includes('force unwrapping') ||
|
|
@@ -369,7 +369,10 @@ const resolveRuleSeverity = (params: {
|
|
|
369
369
|
const promotedRuleIds = params.bundlePolicy?.promoteToErrorRuleIds ?? [];
|
|
370
370
|
const shouldPromoteBySolidContract =
|
|
371
371
|
params.rule.id.endsWith('.no-solid-violations') &&
|
|
372
|
-
(params.stage === '
|
|
372
|
+
(params.stage === 'PRE_WRITE' ||
|
|
373
|
+
params.stage === 'PRE_COMMIT' ||
|
|
374
|
+
params.stage === 'PRE_PUSH' ||
|
|
375
|
+
params.stage === 'CI');
|
|
373
376
|
const shouldPromote =
|
|
374
377
|
shouldPromoteBySolidContract || promotedRuleIds.includes(params.rule.id);
|
|
375
378
|
|
|
@@ -32,6 +32,14 @@ const ATOMICITY_CONFIG_FILE = '.pumuki/git-atomicity.json';
|
|
|
32
32
|
const DEFAULT_COMMIT_PATTERN =
|
|
33
33
|
'^(feat|fix|chore|refactor|docs|test|perf|build|ci|revert)(\\([^)]+\\))?:\\s.+$';
|
|
34
34
|
const MANAGED_EVIDENCE_PATHS = new Set(['.ai_evidence.json', '.AI_EVIDENCE.json']);
|
|
35
|
+
const BASELINE_BRANCH_REFS = [
|
|
36
|
+
'origin/main',
|
|
37
|
+
'origin/develop',
|
|
38
|
+
'upstream/main',
|
|
39
|
+
'upstream/develop',
|
|
40
|
+
'main',
|
|
41
|
+
'develop',
|
|
42
|
+
];
|
|
35
43
|
|
|
36
44
|
const defaultConfig: GitAtomicityConfig = {
|
|
37
45
|
enabled: true,
|
|
@@ -252,33 +260,90 @@ const collectCommitSubjects = (params: {
|
|
|
252
260
|
fromRef?: string;
|
|
253
261
|
toRef?: string;
|
|
254
262
|
}): ReadonlyArray<string> => {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
263
|
+
return collectCommitRecords(params)
|
|
264
|
+
.filter((record) => shouldEvaluateCommitRecord({ git: params.git, repoRoot: params.repoRoot, record }))
|
|
265
|
+
.map((record) => record.subject);
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
type CommitRecord = {
|
|
269
|
+
hash: string;
|
|
270
|
+
parents: ReadonlyArray<string>;
|
|
271
|
+
subject: string;
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
const parseCommitRecords = (value: string): ReadonlyArray<CommitRecord> =>
|
|
275
|
+
value
|
|
276
|
+
.split('\n')
|
|
277
|
+
.map((line) => line.trim())
|
|
278
|
+
.filter((line) => line.length > 0)
|
|
279
|
+
.map((line) => {
|
|
280
|
+
const [hash = '', parents = '', subject = ''] = line.split('\u0001');
|
|
281
|
+
return {
|
|
282
|
+
hash: hash.trim(),
|
|
283
|
+
parents: parents.split(' ').map((parent) => parent.trim()).filter((parent) => parent.length > 0),
|
|
284
|
+
subject: subject.trim(),
|
|
285
|
+
};
|
|
286
|
+
})
|
|
287
|
+
.filter((record) => record.hash.length > 0);
|
|
288
|
+
|
|
289
|
+
const isCommitReachableFromRef = (params: {
|
|
290
|
+
git: IGitService;
|
|
291
|
+
repoRoot: string;
|
|
292
|
+
commitHash: string;
|
|
293
|
+
ref: string;
|
|
294
|
+
}): boolean => {
|
|
258
295
|
try {
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
if (isUnresolvableRevisionError(error)) {
|
|
264
|
-
return [];
|
|
265
|
-
}
|
|
266
|
-
throw error;
|
|
296
|
+
params.git.runGit(['merge-base', '--is-ancestor', params.commitHash, params.ref], params.repoRoot);
|
|
297
|
+
return true;
|
|
298
|
+
} catch {
|
|
299
|
+
return false;
|
|
267
300
|
}
|
|
268
301
|
};
|
|
269
302
|
|
|
270
|
-
const
|
|
303
|
+
const isInheritedBaselineCommit = (params: {
|
|
304
|
+
git: IGitService;
|
|
305
|
+
repoRoot: string;
|
|
306
|
+
commitHash: string;
|
|
307
|
+
}): boolean =>
|
|
308
|
+
BASELINE_BRANCH_REFS.some((ref) =>
|
|
309
|
+
isCommitReachableFromRef({
|
|
310
|
+
git: params.git,
|
|
311
|
+
repoRoot: params.repoRoot,
|
|
312
|
+
commitHash: params.commitHash,
|
|
313
|
+
ref,
|
|
314
|
+
})
|
|
315
|
+
);
|
|
316
|
+
|
|
317
|
+
const shouldEvaluateCommitRecord = (params: {
|
|
318
|
+
git: IGitService;
|
|
319
|
+
repoRoot: string;
|
|
320
|
+
record: CommitRecord;
|
|
321
|
+
}): boolean => {
|
|
322
|
+
if (params.record.parents.length > 1) {
|
|
323
|
+
return false;
|
|
324
|
+
}
|
|
325
|
+
return !isInheritedBaselineCommit({
|
|
326
|
+
git: params.git,
|
|
327
|
+
repoRoot: params.repoRoot,
|
|
328
|
+
commitHash: params.record.hash,
|
|
329
|
+
});
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
const collectCommitRecords = (params: {
|
|
271
333
|
git: IGitService;
|
|
272
334
|
repoRoot: string;
|
|
273
335
|
fromRef?: string;
|
|
274
336
|
toRef?: string;
|
|
275
|
-
}): ReadonlyArray<
|
|
337
|
+
}): ReadonlyArray<CommitRecord> => {
|
|
276
338
|
if (!params.fromRef || !params.toRef) {
|
|
277
339
|
return [];
|
|
278
340
|
}
|
|
279
341
|
try {
|
|
280
|
-
return
|
|
281
|
-
params.git.runGit(
|
|
342
|
+
return parseCommitRecords(
|
|
343
|
+
params.git.runGit(
|
|
344
|
+
['log', '--format=%H%x01%P%x01%s', '--reverse', `${params.fromRef}..${params.toRef}`],
|
|
345
|
+
params.repoRoot
|
|
346
|
+
)
|
|
282
347
|
);
|
|
283
348
|
} catch (error) {
|
|
284
349
|
if (isUnresolvableRevisionError(error)) {
|
|
@@ -367,29 +432,29 @@ const buildPrePushCommitPathLimitViolations = (params: {
|
|
|
367
432
|
fromRef?: string;
|
|
368
433
|
toRef?: string;
|
|
369
434
|
}): GitAtomicityViolation[] | undefined => {
|
|
370
|
-
const
|
|
435
|
+
const commitRecords = collectCommitRecords({
|
|
371
436
|
git: params.git,
|
|
372
437
|
repoRoot: params.repoRoot,
|
|
373
438
|
fromRef: params.fromRef,
|
|
374
439
|
toRef: params.toRef,
|
|
375
|
-
});
|
|
376
|
-
if (
|
|
440
|
+
}).filter((record) => shouldEvaluateCommitRecord({ git: params.git, repoRoot: params.repoRoot, record }));
|
|
441
|
+
if (commitRecords.length === 0) {
|
|
377
442
|
return undefined;
|
|
378
443
|
}
|
|
379
444
|
|
|
380
445
|
const violations: GitAtomicityViolation[] = [];
|
|
381
|
-
for (const
|
|
446
|
+
for (const commitRecord of commitRecords) {
|
|
382
447
|
const changedPaths = collectCommitChangedPaths({
|
|
383
448
|
git: params.git,
|
|
384
449
|
repoRoot: params.repoRoot,
|
|
385
|
-
commitHash,
|
|
450
|
+
commitHash: commitRecord.hash,
|
|
386
451
|
}).filter((path) => !isManagedEvidencePath(path));
|
|
387
452
|
violations.push(
|
|
388
453
|
...buildPathLimitViolations({
|
|
389
454
|
changedPaths,
|
|
390
455
|
config: params.config,
|
|
391
456
|
stage: 'PRE_PUSH',
|
|
392
|
-
label: `commit=${
|
|
457
|
+
label: `commit=${commitRecord.hash.slice(0, 12)}`,
|
|
393
458
|
})
|
|
394
459
|
);
|
|
395
460
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pumuki",
|
|
3
|
-
"version": "6.3.
|
|
3
|
+
"version": "6.3.142",
|
|
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": {
|