pumuki-ast-hooks 5.3.18 → 5.3.19
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/docs/VIOLATIONS_RESOLUTION_PLAN.md +23 -25
- package/package.json +2 -2
- package/scripts/hooks-system/application/CompositionRoot.js +24 -73
- package/scripts/hooks-system/application/services/DynamicRulesLoader.js +1 -2
- package/scripts/hooks-system/application/services/GitTreeState.js +139 -13
- package/scripts/hooks-system/application/services/HookSystemScheduler.js +43 -0
- package/scripts/hooks-system/application/services/PlaybookRunner.js +1 -1
- package/scripts/hooks-system/application/services/RealtimeGuardService.js +15 -85
- package/scripts/hooks-system/application/services/guard/GuardAutoManagerService.js +2 -31
- package/scripts/hooks-system/application/services/guard/GuardConfig.js +9 -17
- package/scripts/hooks-system/application/services/guard/GuardHeartbeatMonitor.js +9 -6
- package/scripts/hooks-system/application/services/guard/GuardProcessManager.js +0 -29
- package/scripts/hooks-system/application/services/installation/GitEnvironmentService.js +1 -4
- package/scripts/hooks-system/application/services/installation/McpConfigurator.js +1 -2
- package/scripts/hooks-system/application/services/logging/AuditLogger.js +86 -1
- package/scripts/hooks-system/application/services/logging/UnifiedLogger.js +4 -13
- package/scripts/hooks-system/application/services/monitoring/EvidenceMonitor.js +1 -0
- package/scripts/hooks-system/application/services/monitoring/EvidenceMonitorService.js +3 -7
- package/scripts/hooks-system/application/services/token/TokenMetricsService.js +1 -14
- package/scripts/hooks-system/bin/__tests__/evidence-update.spec.js +49 -0
- package/scripts/hooks-system/bin/cli.js +1 -15
- package/scripts/hooks-system/domain/events/index.js +6 -32
- package/scripts/hooks-system/infrastructure/ast/android/analyzers/AndroidAnalysisOrchestrator.js +2 -3
- package/scripts/hooks-system/infrastructure/ast/ast-core.js +20 -12
- package/scripts/hooks-system/infrastructure/ast/ast-intelligence.js +18 -8
- package/scripts/hooks-system/infrastructure/ast/backend/analyzers/BackendPatternDetector.js +1 -2
- package/scripts/hooks-system/infrastructure/ast/backend/ast-backend.js +8 -10
- package/scripts/hooks-system/infrastructure/ast/frontend/ast-frontend.js +196 -196
- package/scripts/hooks-system/infrastructure/ast/ios/analyzers/__tests__/iOSASTIntelligentAnalyzer.spec.js +66 -0
- package/scripts/hooks-system/infrastructure/ast/ios/analyzers/iOSASTIntelligentAnalyzer.js +2 -3
- package/scripts/hooks-system/infrastructure/ast/ios/analyzers/iOSArchitectureRules.js +24 -86
- package/scripts/hooks-system/infrastructure/hooks/skill-activation-prompt.js +2 -3
- package/scripts/hooks-system/infrastructure/logging/UnifiedLoggerFactory.js +5 -35
- package/scripts/hooks-system/infrastructure/orchestration/intelligent-audit.js +16 -86
- package/scripts/hooks-system/infrastructure/telemetry/metrics-server.js +2 -51
- package/scripts/hooks-system/infrastructure/validators/enforce-english-literals.js +8 -6
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
## 📊 Resumen Ejecutivo
|
|
13
|
-
- **Estado actual:** ⚠️ Acción requerida (
|
|
13
|
+
- **Estado actual:** ⚠️ Acción requerida (91 críticas, 0 altas, 30 medias, 14 bajas)
|
|
14
14
|
- **Branch:** `fix/audit-staged-severity-case-insensitive`
|
|
15
15
|
- **Fecha de inicio:** 30/12/2025 — **ETA general:** 15/01/2026
|
|
16
16
|
- **Objetivo:** Reducir a 0 las CRÍTICAS/HIGH y bajar el total < 20 antes de permitir commits sin bypass.
|
|
@@ -35,7 +35,7 @@ gantt
|
|
|
35
35
|
Auditoría de seguridad : crit3, after crit2, 3d
|
|
36
36
|
Métricas Prometheus : crit4, after crit3, 2d
|
|
37
37
|
Patrones de confiabilidad : crit5, after crit4, 2d
|
|
38
|
-
|
|
38
|
+
|
|
39
39
|
section Fase 2: HIGH + MEDIUM
|
|
40
40
|
Corrección HIGH : high1, after crit5, 1d
|
|
41
41
|
Refactorización MEDIUM : med1, after high1, 5d
|
|
@@ -46,50 +46,48 @@ gantt
|
|
|
46
46
|
|
|
47
47
|
---
|
|
48
48
|
|
|
49
|
-
## 🔴 Fase 1: Violaciones CRÍTICAS (
|
|
49
|
+
## 🔴 Fase 1: Violaciones CRÍTICAS (91)
|
|
50
50
|
| Estado | Violación | Cant. | Responsable | DOD (Definition of Done) | Doc |
|
|
51
51
|
|--------|-----------|-------|-------------|--------------------------|-----|
|
|
52
|
-
|
|
|
53
|
-
|
|
|
54
|
-
|
|
|
55
|
-
|
|
|
56
|
-
|
|
|
52
|
+
| 🚧 | backend.observability.missing_prometheus | 45 | BE | Añadir métricas Prometheus a todos los servicios críticos; endpoints /metrics funcionando | [Prometheus](../docs/metrics-monitoring.md) |
|
|
53
|
+
| ⏳ | backend.config.missing_env_separation | 27 | BE | Config por entorno (dev/stg/prod), sin secretos hardcode | [Config entornos](../docs/env-configuration.md) |
|
|
54
|
+
| ⏳ | backend.security.missing_audit_logging | 23 | BE | Audit trail en operaciones sensibles + logs estructurados | [Audit logging](../docs/security-auditing.md) |
|
|
55
|
+
| ⏳ | backend.error.custom_exceptions | 16 | BE | CustomError base + reemplazo de `Error` genérico en BE; tests pasando | [Guía de excepciones](../docs/error-handling.md) |
|
|
56
|
+
| ⏳ | backend.reliability.missing_bulkhead | 10 | BE | Limitadores/aislamiento en puntos críticos + pruebas de carga | [Reliability](../docs/reliability-patterns.md) |
|
|
57
|
+
| ⏳ | backend.event.emitter | 4 | BE | try/catch en manejadores de eventos; manejo de errores robusto | [Eventos](../docs/event-handling.md) |
|
|
58
|
+
| ⏳ | backend.observability.missing_alerting | 3 | SRE | Alertas en métricas críticas; umbrales definidos | [Alerting](../docs/alerting-system.md) |
|
|
59
|
+
| ⏳ | backend.config.missing_validation | 1 | BE | Validación de configuración al inicio | [Config validation](../docs/config-validation.md) |
|
|
60
|
+
| ⏳ | backend.config.missing_env_validation | 1 | BE | Validación de variables de entorno requeridas | [Env validation](../docs/env-validation.md) |
|
|
61
|
+
| ⏳ | backend.database.raw_sql | 1 | BE | Uso de ORM en lugar de raw SQL | [Database](../docs/database-layer.md) |
|
|
57
62
|
|
|
58
63
|
---
|
|
59
64
|
|
|
60
|
-
## 🟠 Fase 2: Violaciones HIGH + MEDIUM (
|
|
65
|
+
## 🟠 Fase 2: Violaciones HIGH + MEDIUM (30)
|
|
61
66
|
| Estado | Violación | Cant. | Responsable | DOD | Doc |
|
|
62
67
|
|--------|-----------|-------|-------------|-----|-----|
|
|
63
|
-
| ✅ | HIGH
|
|
64
|
-
|
|
|
65
|
-
| ✅ | backend.event.handler | 26 | BE | Handlers idempotentes + tests de eventos | [Eventos](../docs/event-handling.md) |
|
|
66
|
-
| ⏳ | backend.observability.missing_prometheus | 24 | BE | Métricas por handler; dashboards mínimos | [Observabilidad](../docs/observability.md) |
|
|
67
|
-
| ✅ | backend.auth.missing_cors | 17 | BE | No aplica al hook-system (no expone servidor HTTP); la detección queda en proyectos auditados | [CORS](../docs/cors-configuration.md) |
|
|
68
|
-
| ✅ | backend.observability.missing_alerting | 10 | SRE | Alertas en métricas críticas; umbrales definidos | [Alerting](../docs/alerting-system.md) |
|
|
68
|
+
| ✅ | HIGH | 0 | BE | No aplica (repo JS puro sin TS); se documenta enfoque de seguridad de tipos | [Type safety](../docs/type-safety.md) |
|
|
69
|
+
| ⏳ | MEDIUM | 30 | BE | Resolver violaciones de complejidad media restantes | [Medium violations](../docs/medium-violations.md) |
|
|
69
70
|
|
|
70
71
|
---
|
|
71
72
|
|
|
72
|
-
## 🔵 Fase 3: Violaciones LOW (
|
|
73
|
+
## 🔵 Fase 3: Violaciones LOW (14)
|
|
73
74
|
| Estado | Violación | Cant. | Responsable | DOD | Doc |
|
|
74
75
|
|--------|-----------|-------|-------------|-----|-----|
|
|
75
|
-
| ⏳ |
|
|
76
|
-
| ⏳ | frontend.code_quality.magic_number | 4 | FE | Constantes declaradas; tests ajustados | [Constantes](../docs/constants-vs-magic-numbers.md) |
|
|
77
|
-
| ⏳ | frontend.devops.hardcoded_feature_flag | 2 | FE/DevOps | Flags externalizados por entorno | [Feature flags](../docs/feature-flags.md) |
|
|
78
|
-
| ⏳ | frontend.performance.code_splitting | 2 | FE | Split aplicado en rutas pesadas; bundle size reducido | [Perf FE](../docs/frontend-performance.md) |
|
|
79
|
-
| ⏳ | frontend.performance.missing_code_splitting | 2 | FE | Lazy loading habilitado en vistas grandes | [Code splitting](../docs/code-splitting.md) |
|
|
76
|
+
| ⏳ | LOW | 14 | BE/FE | Resolver violaciones de baja prioridad restantes | [Low violations](../docs/low-violations.md) |
|
|
80
77
|
|
|
81
78
|
---
|
|
82
79
|
|
|
83
80
|
## 📈 Métricas de Progreso
|
|
84
81
|
| Fase | Total | Completado | % |
|
|
85
82
|
|------|-------|------------|---|
|
|
86
|
-
| CRÍTICAS |
|
|
87
|
-
| HIGH + MEDIUM |
|
|
88
|
-
| LOW |
|
|
89
|
-
| **TOTAL** | **
|
|
83
|
+
| CRÍTICAS | 91 | 0 | 0% |
|
|
84
|
+
| HIGH + MEDIUM | 30 | 0 | 0% |
|
|
85
|
+
| LOW | 14 | 0 | 0% |
|
|
86
|
+
| **TOTAL** | **135** | **0** | **0%** |
|
|
90
87
|
|
|
91
88
|
**Riesgos actualizados:**
|
|
92
89
|
1) Implementación de Prometheus podría requerir cambios de infra; 2) Revisión de seguridad depende de disponibilidad de equipo; 3) Refactorizaciones pueden impactar tiempos.
|
|
93
90
|
|
|
94
91
|
**Comentarios/Notas colaborativas:**
|
|
95
92
|
- Añade comentarios bajo cada tabla al cerrar tareas (usa la leyenda para actualizar estados).
|
|
93
|
+
- Progreso en métricas Prometheus: añadidas a 27 servicios, pero 45 violaciones restantes indican necesidad de más instrumentación.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pumuki-ast-hooks",
|
|
3
|
-
"version": "5.3.
|
|
3
|
+
"version": "5.3.19",
|
|
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": {
|
|
@@ -116,4 +116,4 @@
|
|
|
116
116
|
"./skills": "./skills/skill-rules.json",
|
|
117
117
|
"./hooks": "./hooks/index.js"
|
|
118
118
|
}
|
|
119
|
-
}
|
|
119
|
+
}
|
|
@@ -21,54 +21,19 @@ const TokenMonitor = require('./services/monitoring/TokenMonitor');
|
|
|
21
21
|
const ActivityMonitor = require('./services/monitoring/ActivityMonitor');
|
|
22
22
|
const DevDocsMonitor = require('./services/monitoring/DevDocsMonitor');
|
|
23
23
|
const AstMonitor = require('./services/monitoring/AstMonitor');
|
|
24
|
-
const AuditLogger = require('./services/logging/AuditLogger');
|
|
25
24
|
|
|
26
25
|
const path = require('path');
|
|
27
26
|
const fs = require('fs');
|
|
28
|
-
const env = require('../config/env');
|
|
29
|
-
|
|
30
|
-
// Import recordMetric for prometheus metrics
|
|
31
|
-
const { recordMetric } = require('../infrastructure/telemetry/metrics-logger');
|
|
32
27
|
|
|
33
28
|
class CompositionRoot {
|
|
34
29
|
constructor(repoRoot) {
|
|
35
30
|
this.repoRoot = repoRoot;
|
|
36
31
|
this.instances = new Map();
|
|
37
32
|
|
|
38
|
-
this._initializeInfrastructure();
|
|
39
|
-
this._initializeServices();
|
|
40
|
-
this._initializeMonitors();
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
_initializeInfrastructure() {
|
|
44
33
|
// Ensure audit directories exist
|
|
45
|
-
this.auditDir = path.join(
|
|
46
|
-
this.tempDir = path.join(
|
|
34
|
+
this.auditDir = path.join(repoRoot, '.audit-reports');
|
|
35
|
+
this.tempDir = path.join(repoRoot, '.audit_tmp');
|
|
47
36
|
this._ensureDirectories([this.auditDir, this.tempDir]);
|
|
48
|
-
|
|
49
|
-
// Audit log composition root creation
|
|
50
|
-
const auditLogger = this.getAuditLogger();
|
|
51
|
-
auditLogger.log({
|
|
52
|
-
action: 'composition_root_created',
|
|
53
|
-
category: 'system',
|
|
54
|
-
severity: 'info',
|
|
55
|
-
message: 'CompositionRoot initialized for dependency injection',
|
|
56
|
-
metadata: {
|
|
57
|
-
repoRoot: this.repoRoot,
|
|
58
|
-
auditDir: this.auditDir,
|
|
59
|
-
tempDir: this.tempDir
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
_initializeServices() {
|
|
65
|
-
// Services are created lazily when requested
|
|
66
|
-
// This reduces the initialization load
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
_initializeMonitors() {
|
|
70
|
-
// Monitors are created lazily when requested
|
|
71
|
-
// This reduces the initialization load
|
|
72
37
|
}
|
|
73
38
|
|
|
74
39
|
_ensureDirectories(dirs) {
|
|
@@ -86,7 +51,7 @@ class CompositionRoot {
|
|
|
86
51
|
file: {
|
|
87
52
|
enabled: true,
|
|
88
53
|
path: path.join(this.auditDir, 'guard-audit.jsonl'),
|
|
89
|
-
level: env.
|
|
54
|
+
level: process.env.HOOK_LOG_LEVEL || 'info'
|
|
90
55
|
},
|
|
91
56
|
console: {
|
|
92
57
|
enabled: false,
|
|
@@ -108,18 +73,6 @@ class CompositionRoot {
|
|
|
108
73
|
return this.instances.get('notificationService');
|
|
109
74
|
}
|
|
110
75
|
|
|
111
|
-
getAuditLogger() {
|
|
112
|
-
if (!this.instances.has('auditLogger')) {
|
|
113
|
-
const logger = this.getLogger();
|
|
114
|
-
this.instances.set('auditLogger', new AuditLogger({
|
|
115
|
-
repoRoot: this.repoRoot,
|
|
116
|
-
filename: path.join('.audit_tmp', 'audit.log'),
|
|
117
|
-
logger
|
|
118
|
-
}));
|
|
119
|
-
}
|
|
120
|
-
return this.instances.get('auditLogger');
|
|
121
|
-
}
|
|
122
|
-
|
|
123
76
|
// --- Infrastructure Adapters ---
|
|
124
77
|
|
|
125
78
|
getNotificationAdapter() {
|
|
@@ -230,9 +183,9 @@ class CompositionRoot {
|
|
|
230
183
|
getEvidenceMonitor() {
|
|
231
184
|
if (!this.instances.has('evidenceMonitor')) {
|
|
232
185
|
this.instances.set('evidenceMonitor', new EvidenceMonitor(this.repoRoot, {
|
|
233
|
-
staleThresholdMs: env.
|
|
234
|
-
pollIntervalMs: env.
|
|
235
|
-
reminderIntervalMs: env.
|
|
186
|
+
staleThresholdMs: Number(process.env.HOOK_GUARD_EVIDENCE_STALE_THRESHOLD || 180000),
|
|
187
|
+
pollIntervalMs: Number(process.env.HOOK_GUARD_EVIDENCE_POLL_INTERVAL || 30000),
|
|
188
|
+
reminderIntervalMs: Number(process.env.HOOK_GUARD_EVIDENCE_REMINDER_INTERVAL || 60000)
|
|
236
189
|
}));
|
|
237
190
|
}
|
|
238
191
|
return this.instances.get('evidenceMonitor');
|
|
@@ -241,11 +194,11 @@ class CompositionRoot {
|
|
|
241
194
|
getGitTreeMonitor() {
|
|
242
195
|
if (!this.instances.has('gitTreeMonitor')) {
|
|
243
196
|
this.instances.set('gitTreeMonitor', new GitTreeMonitor(this.repoRoot, {
|
|
244
|
-
stagedThreshold: env.
|
|
245
|
-
unstagedThreshold: env.
|
|
246
|
-
totalThreshold: env.
|
|
247
|
-
checkIntervalMs: env.
|
|
248
|
-
reminderMs: env.
|
|
197
|
+
stagedThreshold: Number(process.env.HOOK_GUARD_DIRTY_TREE_STAGED_LIMIT || 10),
|
|
198
|
+
unstagedThreshold: Number(process.env.HOOK_GUARD_DIRTY_TREE_UNSTAGED_LIMIT || 15),
|
|
199
|
+
totalThreshold: Number(process.env.HOOK_GUARD_DIRTY_TREE_TOTAL_LIMIT || 20),
|
|
200
|
+
checkIntervalMs: Number(process.env.HOOK_GUARD_DIRTY_TREE_INTERVAL || 60000),
|
|
201
|
+
reminderMs: Number(process.env.HOOK_GUARD_DIRTY_TREE_REMINDER || 300000)
|
|
249
202
|
}));
|
|
250
203
|
}
|
|
251
204
|
return this.instances.get('gitTreeMonitor');
|
|
@@ -266,11 +219,11 @@ class CompositionRoot {
|
|
|
266
219
|
const github = this.getGitHubAdapter();
|
|
267
220
|
|
|
268
221
|
this.instances.set('gitFlowService', new GitFlowService(this.repoRoot, {
|
|
269
|
-
developBranch: env.
|
|
270
|
-
mainBranch: env.
|
|
271
|
-
autoSyncEnabled: env.
|
|
272
|
-
autoCleanEnabled: env.
|
|
273
|
-
requireClean: env.
|
|
222
|
+
developBranch: process.env.HOOK_GUARD_GITFLOW_DEVELOP_BRANCH || 'develop',
|
|
223
|
+
mainBranch: process.env.HOOK_GUARD_GITFLOW_MAIN_BRANCH || 'main',
|
|
224
|
+
autoSyncEnabled: process.env.HOOK_GUARD_GITFLOW_AUTOSYNC !== 'false',
|
|
225
|
+
autoCleanEnabled: process.env.HOOK_GUARD_GITFLOW_AUTOCLEAN !== 'false',
|
|
226
|
+
requireClean: process.env.HOOK_GUARD_GITFLOW_REQUIRE_CLEAN !== 'false'
|
|
274
227
|
}, logger, gitQuery, gitCommand, github));
|
|
275
228
|
}
|
|
276
229
|
return this.instances.get('gitFlowService');
|
|
@@ -281,7 +234,7 @@ class CompositionRoot {
|
|
|
281
234
|
const logger = this.getLogger();
|
|
282
235
|
this.instances.set('activityMonitor', new ActivityMonitor({
|
|
283
236
|
repoRoot: this.repoRoot,
|
|
284
|
-
inactivityGraceMs: env.
|
|
237
|
+
inactivityGraceMs: Number(process.env.HOOK_GUARD_INACTIVITY_GRACE_MS || 420000),
|
|
285
238
|
logger
|
|
286
239
|
}));
|
|
287
240
|
}
|
|
@@ -294,9 +247,9 @@ class CompositionRoot {
|
|
|
294
247
|
const notificationService = this.getNotificationService();
|
|
295
248
|
this.instances.set('devDocsMonitor', new DevDocsMonitor({
|
|
296
249
|
repoRoot: this.repoRoot,
|
|
297
|
-
checkIntervalMs: env.
|
|
298
|
-
staleThresholdMs: env.
|
|
299
|
-
autoRefreshEnabled: env.
|
|
250
|
+
checkIntervalMs: Number(process.env.HOOK_GUARD_DEV_DOCS_CHECK_INTERVAL || 300000),
|
|
251
|
+
staleThresholdMs: Number(process.env.HOOK_GUARD_DEV_DOCS_STALE_THRESHOLD || 86400000),
|
|
252
|
+
autoRefreshEnabled: process.env.HOOK_GUARD_DEV_DOCS_AUTO_REFRESH !== 'false',
|
|
300
253
|
logger,
|
|
301
254
|
notificationService
|
|
302
255
|
}));
|
|
@@ -310,9 +263,9 @@ class CompositionRoot {
|
|
|
310
263
|
const notificationService = this.getNotificationService();
|
|
311
264
|
this.instances.set('astMonitor', new AstMonitor({
|
|
312
265
|
repoRoot: this.repoRoot,
|
|
313
|
-
debounceMs: env.
|
|
314
|
-
cooldownMs: env.
|
|
315
|
-
enabled: env.
|
|
266
|
+
debounceMs: Number(process.env.HOOK_AST_WATCH_DEBOUNCE || 8000),
|
|
267
|
+
cooldownMs: Number(process.env.HOOK_AST_WATCH_COOLDOWN || 30000),
|
|
268
|
+
enabled: process.env.HOOK_AST_WATCH !== 'false',
|
|
316
269
|
logger,
|
|
317
270
|
notificationService
|
|
318
271
|
}));
|
|
@@ -338,7 +291,6 @@ class CompositionRoot {
|
|
|
338
291
|
const notificationService = this.getNotificationService();
|
|
339
292
|
const monitors = this.getMonitors();
|
|
340
293
|
const orchestrator = this.getOrchestrator();
|
|
341
|
-
const auditLogger = this.getAuditLogger();
|
|
342
294
|
const config = {
|
|
343
295
|
debugLogPath: path.join(this.auditDir, 'guard-debug.log'),
|
|
344
296
|
repoRoot: this.repoRoot
|
|
@@ -349,8 +301,7 @@ class CompositionRoot {
|
|
|
349
301
|
notificationService,
|
|
350
302
|
monitors,
|
|
351
303
|
orchestration: orchestrator,
|
|
352
|
-
config
|
|
353
|
-
auditLogger
|
|
304
|
+
config
|
|
354
305
|
}));
|
|
355
306
|
}
|
|
356
307
|
return this.instances.get('guardService');
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
const fs = require('fs').promises;
|
|
2
2
|
const path = require('path');
|
|
3
|
-
const env = require('../config/env');
|
|
4
3
|
|
|
5
4
|
class DynamicRulesLoader {
|
|
6
5
|
constructor(rulesDirectory, logger = console) {
|
|
@@ -28,7 +27,7 @@ class DynamicRulesLoader {
|
|
|
28
27
|
return [this.rulesDirectory];
|
|
29
28
|
}
|
|
30
29
|
|
|
31
|
-
const envRaw = env.
|
|
30
|
+
const envRaw = process.env.AST_RULES_DIRECTORIES;
|
|
32
31
|
if (envRaw && typeof envRaw === 'string' && envRaw.trim().length > 0) {
|
|
33
32
|
return envRaw
|
|
34
33
|
.split(',')
|
|
@@ -1,16 +1,53 @@
|
|
|
1
1
|
const { execSync } = require('child_process');
|
|
2
2
|
|
|
3
|
+
// Import recordMetric for prometheus metrics
|
|
4
|
+
const { recordMetric } = require('../../../infrastructure/telemetry/metrics-logger');
|
|
5
|
+
|
|
3
6
|
const extractFilePath = line => {
|
|
7
|
+
recordMetric({
|
|
8
|
+
hook: 'git_tree_state',
|
|
9
|
+
operation: 'extract_file_path',
|
|
10
|
+
status: 'started',
|
|
11
|
+
lineLength: line ? line.length : 0
|
|
12
|
+
});
|
|
13
|
+
|
|
4
14
|
if (!line) {
|
|
15
|
+
recordMetric({
|
|
16
|
+
hook: 'git_tree_state',
|
|
17
|
+
operation: 'extract_file_path',
|
|
18
|
+
status: 'success',
|
|
19
|
+
result: ''
|
|
20
|
+
});
|
|
5
21
|
return '';
|
|
6
22
|
}
|
|
7
23
|
if (line.startsWith('??')) {
|
|
8
|
-
|
|
24
|
+
const result = line.slice(3).trim();
|
|
25
|
+
recordMetric({
|
|
26
|
+
hook: 'git_tree_state',
|
|
27
|
+
operation: 'extract_file_path',
|
|
28
|
+
status: 'success',
|
|
29
|
+
resultLength: result.length
|
|
30
|
+
});
|
|
31
|
+
return result;
|
|
9
32
|
}
|
|
10
|
-
|
|
33
|
+
const result = line.length > 3 ? line.slice(3).trim() : line.trim();
|
|
34
|
+
recordMetric({
|
|
35
|
+
hook: 'git_tree_state',
|
|
36
|
+
operation: 'extract_file_path',
|
|
37
|
+
status: 'success',
|
|
38
|
+
resultLength: result.length
|
|
39
|
+
});
|
|
40
|
+
return result;
|
|
11
41
|
};
|
|
12
42
|
|
|
13
43
|
const buildStateFromStatus = (statusOutput = '') => {
|
|
44
|
+
recordMetric({
|
|
45
|
+
hook: 'git_tree_state',
|
|
46
|
+
operation: 'build_state_from_status',
|
|
47
|
+
status: 'started',
|
|
48
|
+
statusOutputLength: statusOutput ? statusOutput.length : 0
|
|
49
|
+
});
|
|
50
|
+
|
|
14
51
|
const lines = statusOutput
|
|
15
52
|
.split('\n')
|
|
16
53
|
.map(entry => entry.replace(/\r$/, ''))
|
|
@@ -44,24 +81,51 @@ const buildStateFromStatus = (statusOutput = '') => {
|
|
|
44
81
|
|
|
45
82
|
const uniqueSet = new Set([...stagedSet, ...workingSet]);
|
|
46
83
|
|
|
47
|
-
|
|
84
|
+
const result = {
|
|
48
85
|
stagedFiles: Array.from(stagedSet),
|
|
49
86
|
workingFiles: Array.from(workingSet),
|
|
50
87
|
stagedCount: stagedSet.size,
|
|
51
88
|
workingCount: workingSet.size,
|
|
52
89
|
uniqueCount: uniqueSet.size
|
|
53
90
|
};
|
|
91
|
+
|
|
92
|
+
recordMetric({
|
|
93
|
+
hook: 'git_tree_state',
|
|
94
|
+
operation: 'build_state_from_status',
|
|
95
|
+
status: 'success',
|
|
96
|
+
stagedCount: stagedSet.size,
|
|
97
|
+
workingCount: workingSet.size,
|
|
98
|
+
uniqueCount: uniqueSet.size
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
return result;
|
|
54
102
|
};
|
|
55
103
|
|
|
56
104
|
const getGitTreeState = ({ repoRoot = process.cwd() } = {}) => {
|
|
105
|
+
recordMetric({
|
|
106
|
+
hook: 'git_tree_state',
|
|
107
|
+
operation: 'get_git_tree_state',
|
|
108
|
+
status: 'started',
|
|
109
|
+
repoRoot: repoRoot.substring(0, 100)
|
|
110
|
+
});
|
|
111
|
+
|
|
57
112
|
try {
|
|
58
113
|
const statusOutput = execSync('git status --porcelain', {
|
|
59
114
|
cwd: repoRoot,
|
|
60
115
|
encoding: 'utf8'
|
|
61
116
|
});
|
|
62
|
-
|
|
117
|
+
const result = buildStateFromStatus(statusOutput);
|
|
118
|
+
recordMetric({
|
|
119
|
+
hook: 'git_tree_state',
|
|
120
|
+
operation: 'get_git_tree_state',
|
|
121
|
+
status: 'success',
|
|
122
|
+
stagedCount: result.stagedCount,
|
|
123
|
+
workingCount: result.workingCount,
|
|
124
|
+
uniqueCount: result.uniqueCount
|
|
125
|
+
});
|
|
126
|
+
return result;
|
|
63
127
|
} catch (error) {
|
|
64
|
-
|
|
128
|
+
const result = {
|
|
65
129
|
stagedFiles: [],
|
|
66
130
|
workingFiles: [],
|
|
67
131
|
stagedCount: 0,
|
|
@@ -69,37 +133,92 @@ const getGitTreeState = ({ repoRoot = process.cwd() } = {}) => {
|
|
|
69
133
|
uniqueCount: 0,
|
|
70
134
|
error: error.message
|
|
71
135
|
};
|
|
136
|
+
recordMetric({
|
|
137
|
+
hook: 'git_tree_state',
|
|
138
|
+
operation: 'get_git_tree_state',
|
|
139
|
+
status: 'failed',
|
|
140
|
+
error: error.message
|
|
141
|
+
});
|
|
142
|
+
return result;
|
|
72
143
|
}
|
|
73
144
|
};
|
|
74
145
|
|
|
75
146
|
const isTreeBeyondLimit = (state, limits) => {
|
|
147
|
+
recordMetric({
|
|
148
|
+
hook: 'git_tree_state',
|
|
149
|
+
operation: 'is_tree_beyond_limit',
|
|
150
|
+
status: 'started',
|
|
151
|
+
hasState: !!state,
|
|
152
|
+
limitsType: typeof limits
|
|
153
|
+
});
|
|
154
|
+
|
|
76
155
|
if (!state) {
|
|
156
|
+
recordMetric({
|
|
157
|
+
hook: 'git_tree_state',
|
|
158
|
+
operation: 'is_tree_beyond_limit',
|
|
159
|
+
status: 'success',
|
|
160
|
+
result: false
|
|
161
|
+
});
|
|
77
162
|
return false;
|
|
78
163
|
}
|
|
79
|
-
|
|
164
|
+
|
|
80
165
|
if (typeof limits === 'number') {
|
|
81
166
|
const limit = limits;
|
|
82
167
|
if (!Number.isFinite(limit) || limit <= 0) {
|
|
168
|
+
recordMetric({
|
|
169
|
+
hook: 'git_tree_state',
|
|
170
|
+
operation: 'is_tree_beyond_limit',
|
|
171
|
+
status: 'success',
|
|
172
|
+
result: false
|
|
173
|
+
});
|
|
83
174
|
return false;
|
|
84
175
|
}
|
|
85
|
-
|
|
176
|
+
const result = (
|
|
86
177
|
state.stagedCount > limit ||
|
|
87
178
|
state.workingCount > limit ||
|
|
88
179
|
state.uniqueCount > limit
|
|
89
180
|
);
|
|
181
|
+
recordMetric({
|
|
182
|
+
hook: 'git_tree_state',
|
|
183
|
+
operation: 'is_tree_beyond_limit',
|
|
184
|
+
status: 'success',
|
|
185
|
+
result: result
|
|
186
|
+
});
|
|
187
|
+
return result;
|
|
90
188
|
}
|
|
91
|
-
|
|
189
|
+
|
|
92
190
|
const { stagedLimit = 10, unstagedLimit = 15, totalLimit = 20 } = limits || {};
|
|
93
|
-
|
|
191
|
+
|
|
94
192
|
const stagedExceeded = Number.isFinite(stagedLimit) && stagedLimit > 0 && state.stagedCount > stagedLimit;
|
|
95
193
|
const unstagedExceeded = Number.isFinite(unstagedLimit) && unstagedLimit > 0 && state.workingCount > unstagedLimit;
|
|
96
194
|
const totalExceeded = Number.isFinite(totalLimit) && totalLimit > 0 && state.uniqueCount > totalLimit;
|
|
97
|
-
|
|
98
|
-
|
|
195
|
+
|
|
196
|
+
const result = stagedExceeded || unstagedExceeded || totalExceeded;
|
|
197
|
+
recordMetric({
|
|
198
|
+
hook: 'git_tree_state',
|
|
199
|
+
operation: 'is_tree_beyond_limit',
|
|
200
|
+
status: 'success',
|
|
201
|
+
result: result
|
|
202
|
+
});
|
|
203
|
+
return result;
|
|
99
204
|
};
|
|
100
205
|
|
|
101
206
|
const summarizeTreeState = (state, limits) => {
|
|
207
|
+
recordMetric({
|
|
208
|
+
hook: 'git_tree_state',
|
|
209
|
+
operation: 'summarize_tree_state',
|
|
210
|
+
status: 'started',
|
|
211
|
+
hasState: !!state,
|
|
212
|
+
limitsType: typeof limits
|
|
213
|
+
});
|
|
214
|
+
|
|
102
215
|
if (!state) {
|
|
216
|
+
recordMetric({
|
|
217
|
+
hook: 'git_tree_state',
|
|
218
|
+
operation: 'summarize_tree_state',
|
|
219
|
+
status: 'success',
|
|
220
|
+
result: 'no data'
|
|
221
|
+
});
|
|
103
222
|
return 'no data';
|
|
104
223
|
}
|
|
105
224
|
const parts = [
|
|
@@ -107,7 +226,7 @@ const summarizeTreeState = (state, limits) => {
|
|
|
107
226
|
`working ${state.workingCount}`,
|
|
108
227
|
`unique ${state.uniqueCount}`
|
|
109
228
|
];
|
|
110
|
-
|
|
229
|
+
|
|
111
230
|
if (typeof limits === 'number') {
|
|
112
231
|
const limit = limits;
|
|
113
232
|
if (Number.isFinite(limit) && limit > 0) {
|
|
@@ -129,7 +248,14 @@ const summarizeTreeState = (state, limits) => {
|
|
|
129
248
|
parts.push(`(${limitParts.join(', ')})`);
|
|
130
249
|
}
|
|
131
250
|
}
|
|
132
|
-
|
|
251
|
+
const result = parts.join(', ');
|
|
252
|
+
recordMetric({
|
|
253
|
+
hook: 'git_tree_state',
|
|
254
|
+
operation: 'summarize_tree_state',
|
|
255
|
+
status: 'success',
|
|
256
|
+
resultLength: result.length
|
|
257
|
+
});
|
|
258
|
+
return result;
|
|
133
259
|
};
|
|
134
260
|
|
|
135
261
|
module.exports = {
|
|
@@ -3,23 +3,66 @@ const HookSystemStateMachine = require('../state/HookSystemStateMachine');
|
|
|
3
3
|
|
|
4
4
|
class HookSystemScheduler {
|
|
5
5
|
constructor({ orchestrator, contextEngine, intervalMs = 30000 }) {
|
|
6
|
+
recordMetric({
|
|
7
|
+
hook: 'hook_system_scheduler',
|
|
8
|
+
operation: 'constructor',
|
|
9
|
+
status: 'started',
|
|
10
|
+
intervalMs
|
|
11
|
+
});
|
|
12
|
+
|
|
6
13
|
this.orchestrator = orchestrator;
|
|
7
14
|
this.contextEngine = contextEngine;
|
|
8
15
|
this.intervalMs = intervalMs;
|
|
9
16
|
this.stateMachine = new HookSystemStateMachine();
|
|
10
17
|
this.timer = null;
|
|
18
|
+
|
|
19
|
+
recordMetric({
|
|
20
|
+
hook: 'hook_system_scheduler',
|
|
21
|
+
operation: 'constructor',
|
|
22
|
+
status: 'success',
|
|
23
|
+
intervalMs
|
|
24
|
+
});
|
|
11
25
|
}
|
|
12
26
|
|
|
13
27
|
start() {
|
|
28
|
+
recordMetric({
|
|
29
|
+
hook: 'hook_system_scheduler',
|
|
30
|
+
operation: 'start',
|
|
31
|
+
status: 'started',
|
|
32
|
+
intervalMs: this.intervalMs
|
|
33
|
+
});
|
|
34
|
+
|
|
14
35
|
if (this.timer) return;
|
|
36
|
+
|
|
15
37
|
this.timer = setInterval(() => this.tick(), this.intervalMs);
|
|
38
|
+
|
|
39
|
+
recordMetric({
|
|
40
|
+
hook: 'hook_system_scheduler',
|
|
41
|
+
operation: 'start',
|
|
42
|
+
status: 'success',
|
|
43
|
+
intervalMs: this.intervalMs
|
|
44
|
+
});
|
|
16
45
|
}
|
|
17
46
|
|
|
18
47
|
stop() {
|
|
48
|
+
recordMetric({
|
|
49
|
+
hook: 'hook_system_scheduler',
|
|
50
|
+
operation: 'stop',
|
|
51
|
+
status: 'started',
|
|
52
|
+
hadTimer: !!this.timer
|
|
53
|
+
});
|
|
54
|
+
|
|
19
55
|
if (this.timer) {
|
|
20
56
|
clearInterval(this.timer);
|
|
21
57
|
this.timer = null;
|
|
22
58
|
}
|
|
59
|
+
|
|
60
|
+
recordMetric({
|
|
61
|
+
hook: 'hook_system_scheduler',
|
|
62
|
+
operation: 'stop',
|
|
63
|
+
status: 'success',
|
|
64
|
+
hadTimer: !!this.timer
|
|
65
|
+
});
|
|
23
66
|
}
|
|
24
67
|
|
|
25
68
|
async tick() {
|