pumuki-ast-hooks 5.5.36 → 5.5.37
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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pumuki-ast-hooks",
|
|
3
|
-
"version": "5.5.
|
|
3
|
+
"version": "5.5.37",
|
|
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": {
|
package/scripts/hooks-system/infrastructure/orchestration/__tests__/intelligent-audit.spec.js
CHANGED
|
@@ -23,7 +23,15 @@ describe('AI_EVIDENCE.json structure validation', () => {
|
|
|
23
23
|
question_3_clean_architecture: 'Verify that the code follows Clean Architecture and SOLID principles',
|
|
24
24
|
last_answered: new Date().toISOString()
|
|
25
25
|
},
|
|
26
|
-
rules_read:
|
|
26
|
+
rules_read: [
|
|
27
|
+
{
|
|
28
|
+
file: 'rulesgold.mdc',
|
|
29
|
+
verified: true,
|
|
30
|
+
summary: 'loaded (example)',
|
|
31
|
+
path: '/tmp/rulesgold.mdc'
|
|
32
|
+
}
|
|
33
|
+
],
|
|
34
|
+
rules_read_flags: {
|
|
27
35
|
backend: true,
|
|
28
36
|
frontend: false,
|
|
29
37
|
ios: false,
|
|
@@ -79,15 +87,25 @@ describe('AI_EVIDENCE.json structure validation', () => {
|
|
|
79
87
|
expect(evidence.protocol_3_questions.last_answered).toBeDefined();
|
|
80
88
|
});
|
|
81
89
|
|
|
82
|
-
it('should have rules_read field
|
|
90
|
+
it('should have rules_read field with rule load evidence entries', () => {
|
|
83
91
|
const evidence = createMockEvidence();
|
|
84
92
|
expect(evidence.rules_read).toBeDefined();
|
|
85
|
-
expect(evidence.rules_read
|
|
86
|
-
expect(evidence.rules_read.
|
|
87
|
-
expect(evidence.rules_read
|
|
88
|
-
expect(evidence.rules_read
|
|
89
|
-
expect(evidence.rules_read
|
|
90
|
-
|
|
93
|
+
expect(Array.isArray(evidence.rules_read)).toBe(true);
|
|
94
|
+
expect(evidence.rules_read.length).toBeGreaterThan(0);
|
|
95
|
+
expect(evidence.rules_read[0]).toHaveProperty('file');
|
|
96
|
+
expect(evidence.rules_read[0]).toHaveProperty('verified');
|
|
97
|
+
expect(evidence.rules_read[0]).toHaveProperty('summary');
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('should have rules_read_flags legacy field tracking platform flags', () => {
|
|
101
|
+
const evidence = createMockEvidence();
|
|
102
|
+
expect(evidence.rules_read_flags).toBeDefined();
|
|
103
|
+
expect(evidence.rules_read_flags.backend).toBe(true);
|
|
104
|
+
expect(evidence.rules_read_flags.frontend).toBe(false);
|
|
105
|
+
expect(evidence.rules_read_flags.ios).toBe(false);
|
|
106
|
+
expect(evidence.rules_read_flags.android).toBe(false);
|
|
107
|
+
expect(evidence.rules_read_flags.gold).toBe(true);
|
|
108
|
+
expect(evidence.rules_read_flags.last_checked).toBeDefined();
|
|
91
109
|
});
|
|
92
110
|
|
|
93
111
|
it('should have current_context field with branch and file info', () => {
|
|
@@ -9,6 +9,7 @@ const { TokenManager } = require('../utils/token-manager');
|
|
|
9
9
|
const { toErrorMessage } = require('../utils/error-utils');
|
|
10
10
|
const fs = require('fs');
|
|
11
11
|
const path = require('path');
|
|
12
|
+
const DynamicRulesLoader = require('../../application/services/DynamicRulesLoader');
|
|
12
13
|
|
|
13
14
|
function deriveCategoryFromRuleId(ruleId) {
|
|
14
15
|
if (!ruleId || typeof ruleId !== 'string') return 'unknown';
|
|
@@ -24,6 +25,121 @@ function deriveCategoryFromRuleId(ruleId) {
|
|
|
24
25
|
return parts[0] || 'unknown';
|
|
25
26
|
}
|
|
26
27
|
|
|
28
|
+
function detectPlatformsFromStagedFiles(stagedFiles) {
|
|
29
|
+
const platforms = new Set();
|
|
30
|
+
const files = Array.isArray(stagedFiles) ? stagedFiles : [];
|
|
31
|
+
|
|
32
|
+
files.forEach(filePath => {
|
|
33
|
+
const lowerPath = String(filePath || '').toLowerCase();
|
|
34
|
+
|
|
35
|
+
if (lowerPath.includes('apps/backend/') || lowerPath.includes('/services/') || lowerPath.includes('services/') || lowerPath.includes('/functions/') || lowerPath.includes('functions/')) {
|
|
36
|
+
platforms.add('backend');
|
|
37
|
+
}
|
|
38
|
+
if (lowerPath.includes('apps/web-app/') || lowerPath.includes('apps/admin') || lowerPath.includes('apps/frontend/') || lowerPath.includes('frontend/')) {
|
|
39
|
+
platforms.add('frontend');
|
|
40
|
+
}
|
|
41
|
+
if (lowerPath.includes('apps/ios/') || lowerPath.endsWith('.swift')) {
|
|
42
|
+
platforms.add('ios');
|
|
43
|
+
}
|
|
44
|
+
if (lowerPath.includes('apps/android/') || lowerPath.endsWith('.kt') || lowerPath.endsWith('.kts') || lowerPath.endsWith('.java')) {
|
|
45
|
+
platforms.add('android');
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
return platforms;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function countViolationsByPlatform(violations) {
|
|
53
|
+
const counts = { backend: 0, frontend: 0, ios: 0, android: 0 };
|
|
54
|
+
const list = Array.isArray(violations) ? violations : [];
|
|
55
|
+
|
|
56
|
+
list.forEach(v => {
|
|
57
|
+
const ruleId = v.ruleId || v.rule || 'unknown';
|
|
58
|
+
const category = String(v.category || deriveCategoryFromRuleId(ruleId) || '').toLowerCase();
|
|
59
|
+
const platform = category.split('.')[0];
|
|
60
|
+
if (counts[platform] !== undefined) {
|
|
61
|
+
counts[platform] += 1;
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
return counts;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function buildPlatformsEvidence(stagedFiles, violations) {
|
|
69
|
+
const stagedDetected = detectPlatformsFromStagedFiles(stagedFiles);
|
|
70
|
+
const violationCounts = countViolationsByPlatform(violations);
|
|
71
|
+
|
|
72
|
+
const platforms = ['backend', 'frontend', 'ios', 'android'];
|
|
73
|
+
const result = {};
|
|
74
|
+
|
|
75
|
+
platforms.forEach(p => {
|
|
76
|
+
const violationsCount = violationCounts[p] || 0;
|
|
77
|
+
result[p] = {
|
|
78
|
+
detected: stagedDetected.has(p) || violationsCount > 0,
|
|
79
|
+
violations: violationsCount
|
|
80
|
+
};
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
return result;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function summarizeRulesContent(content) {
|
|
87
|
+
if (!content || typeof content !== 'string') {
|
|
88
|
+
return 'not found';
|
|
89
|
+
}
|
|
90
|
+
const firstNonEmpty = content
|
|
91
|
+
.split('\n')
|
|
92
|
+
.map(l => l.trim())
|
|
93
|
+
.find(l => l.length > 0);
|
|
94
|
+
const firstLine = firstNonEmpty ? firstNonEmpty.slice(0, 140) : '';
|
|
95
|
+
return firstLine.length > 0 ? firstLine : `loaded (${content.length} chars)`;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async function buildRulesReadEvidence(platformsEvidence) {
|
|
99
|
+
const loader = new DynamicRulesLoader();
|
|
100
|
+
const entries = [];
|
|
101
|
+
|
|
102
|
+
const detectedPlatforms = ['backend', 'frontend', 'ios', 'android']
|
|
103
|
+
.filter(p => platformsEvidence && platformsEvidence[p] && platformsEvidence[p].detected);
|
|
104
|
+
|
|
105
|
+
const uniqueFiles = ['rulesgold.mdc', ...detectedPlatforms.map(p => loader.rulesMap[p]).filter(Boolean)];
|
|
106
|
+
|
|
107
|
+
for (const file of uniqueFiles) {
|
|
108
|
+
let verified = false;
|
|
109
|
+
let summary = 'not found';
|
|
110
|
+
let resolvedPath = null;
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
const content = await loader.loadRule(file);
|
|
114
|
+
verified = Boolean(content);
|
|
115
|
+
summary = summarizeRulesContent(content);
|
|
116
|
+
const cached = loader.cache && loader.cache.rules ? loader.cache.rules.get(file) : null;
|
|
117
|
+
resolvedPath = cached && cached.fullPath ? cached.fullPath : null;
|
|
118
|
+
} catch (error) {
|
|
119
|
+
summary = `error: ${toErrorMessage(error)}`;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
entries.push({
|
|
123
|
+
file,
|
|
124
|
+
verified,
|
|
125
|
+
summary,
|
|
126
|
+
path: resolvedPath
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return {
|
|
131
|
+
entries,
|
|
132
|
+
legacyFlags: {
|
|
133
|
+
backend: detectedPlatforms.includes('backend'),
|
|
134
|
+
frontend: detectedPlatforms.includes('frontend'),
|
|
135
|
+
ios: detectedPlatforms.includes('ios'),
|
|
136
|
+
android: detectedPlatforms.includes('android'),
|
|
137
|
+
gold: true,
|
|
138
|
+
last_checked: formatLocalTimestamp()
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
27
143
|
function formatLocalTimestamp(date = new Date()) {
|
|
28
144
|
const year = date.getFullYear();
|
|
29
145
|
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
@@ -90,7 +206,7 @@ async function runIntelligentAudit() {
|
|
|
90
206
|
const gateResult = { passed: true, exitCode: 0, blockedBy: null };
|
|
91
207
|
const tokenManager = new TokenManager();
|
|
92
208
|
const tokenUsage = tokenManager.estimate(enhancedAll, {});
|
|
93
|
-
updateAIEvidence(enhancedAll, gateResult, tokenUsage);
|
|
209
|
+
await updateAIEvidence(enhancedAll, gateResult, tokenUsage);
|
|
94
210
|
process.exit(0);
|
|
95
211
|
}
|
|
96
212
|
|
|
@@ -136,7 +252,7 @@ async function runIntelligentAudit() {
|
|
|
136
252
|
|
|
137
253
|
tokenManager.record(tokenUsage);
|
|
138
254
|
|
|
139
|
-
updateAIEvidence(enhancedViolations, gateResult, tokenUsage);
|
|
255
|
+
await updateAIEvidence(enhancedViolations, gateResult, tokenUsage);
|
|
140
256
|
|
|
141
257
|
saveEnhancedViolations(enhancedViolations);
|
|
142
258
|
|
|
@@ -201,7 +317,7 @@ function saveEnhancedViolations(violations) {
|
|
|
201
317
|
fs.writeFileSync(outputPath, JSON.stringify(enhanced, null, 2));
|
|
202
318
|
}
|
|
203
319
|
|
|
204
|
-
function updateAIEvidence(violations, gateResult, tokenUsage) {
|
|
320
|
+
async function updateAIEvidence(violations, gateResult, tokenUsage) {
|
|
205
321
|
const evidencePath = '.AI_EVIDENCE.json';
|
|
206
322
|
|
|
207
323
|
if (!fs.existsSync(evidencePath)) {
|
|
@@ -320,14 +436,12 @@ function updateAIEvidence(violations, gateResult, tokenUsage) {
|
|
|
320
436
|
last_answered: formatLocalTimestamp()
|
|
321
437
|
};
|
|
322
438
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
last_checked: formatLocalTimestamp()
|
|
330
|
-
};
|
|
439
|
+
const stagedFiles = getStagedFiles();
|
|
440
|
+
const platformsEvidence = buildPlatformsEvidence(stagedFiles, violations);
|
|
441
|
+
const rulesRead = await buildRulesReadEvidence(platformsEvidence);
|
|
442
|
+
|
|
443
|
+
evidence.rules_read = rulesRead.entries;
|
|
444
|
+
evidence.rules_read_flags = rulesRead.legacyFlags;
|
|
331
445
|
|
|
332
446
|
evidence.current_context = {
|
|
333
447
|
working_on: env.get('AUTO_EVIDENCE_SUMMARY', 'AST Intelligence Analysis'),
|
|
@@ -337,12 +451,7 @@ function updateAIEvidence(violations, gateResult, tokenUsage) {
|
|
|
337
451
|
timestamp: formatLocalTimestamp()
|
|
338
452
|
};
|
|
339
453
|
|
|
340
|
-
evidence.platforms =
|
|
341
|
-
backend: { detected: true, violations: violations.filter(v => v.category && v.category.includes('backend')).length },
|
|
342
|
-
frontend: { detected: false, violations: 0 },
|
|
343
|
-
ios: { detected: false, violations: 0 },
|
|
344
|
-
android: { detected: false, violations: 0 }
|
|
345
|
-
};
|
|
454
|
+
evidence.platforms = platformsEvidence;
|
|
346
455
|
|
|
347
456
|
evidence.session_id = `session-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
348
457
|
|