pumuki-ast-hooks 5.3.30 → 5.4.1

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.
@@ -45,22 +45,22 @@ gantt
45
45
  ## 🔴 Phase 1: BLOCKER Violations (CRITICAL + HIGH)
46
46
  | Status | Severity | Count | Owner | DOD (Definition of Done) | Source |
47
47
  |--------|-----------|-------|-------------|--------------------------|--------|
48
- | 🚧 | CRITICAL | 3 | BE | Resolve CRITICAL violations in repository (0 CRITICAL to unblock) | `.audit_tmp/ast-summary.json` / `.violations-by-priority.md` |
49
- | 🚧 | HIGH | 6 | BE | Resolve HIGH violations in repository (0 HIGH to unblock) | `.audit_tmp/ast-summary.json` / `.violations-by-priority.md` |
48
+ | | CRITICAL | 0 | BE | Resolve CRITICAL violations in repository (0 CRITICAL to unblock) | `.audit_tmp/ast-summary.json` / `.violations-by-priority.md` |
49
+ | | HIGH | 0 | BE | Resolve HIGH violations in repository (0 HIGH to unblock) | `.audit_tmp/ast-summary.json` / `.violations-by-priority.md` |
50
50
 
51
51
  ---
52
52
 
53
- ## 🟠 Phase 2: MEDIUM Violations (272)
53
+ ## 🟠 Phase 2: MEDIUM Violations (277)
54
54
  | Status | Violation | Count | Owner | DOD | Doc |
55
55
  |--------|-----------|-------|-------------|-----|-----|
56
- | 🚧 | MEDIUM | 272 | BE | Resolve remaining medium-complexity violations | [Medium violations](../docs/medium-violations.md) |
56
+ | 🚧 | MEDIUM | 277 | BE | Resolve remaining medium-complexity violations | [Medium violations](../docs/medium-violations.md) |
57
57
 
58
58
  ---
59
59
 
60
- ## 🔵 Phase 3: LOW Violations (213)
60
+ ## 🔵 Phase 3: LOW Violations (218)
61
61
  | Status | Violation | Count | Owner | DOD | Doc |
62
62
  |--------|-----------|-------|-------------|-----|-----|
63
- | 🚧 | LOW | 213 | BE/FE | Resolve remaining low-priority violations | [Low violations](../docs/low-violations.md) |
63
+ | 🚧 | LOW | 218 | BE/FE | Resolve remaining low-priority violations | [Low violations](../docs/low-violations.md) |
64
64
 
65
65
  ---
66
66
 
@@ -83,10 +83,10 @@ gantt
83
83
  ## 📈 Progress Metrics
84
84
  | Phase | Total | Completed | % |
85
85
  |------|-------|------------|---|
86
- | BLOCKERS (CRITICAL + HIGH) | 216 | 0 | 0% |
87
- | MEDIUM | 122 | 0 | 0% |
88
- | LOW | 185 | 0 | 0% |
89
- | **TOTAL** | **523** | **0** | **0%** |
86
+ | BLOCKERS (CRITICAL + HIGH) | 9 | 9 | 100% |
87
+ | MEDIUM | 272 | 0 | 0% |
88
+ | LOW | 213 | 0 | 0% |
89
+ | **TOTAL** | **494** | **9** | **1.8%** |
90
90
 
91
91
  **Updated risks:**
92
92
  1) Prometheus implementation may require infra changes; 2) Security review depends on team availability; 3) Refactors may impact timelines.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pumuki-ast-hooks",
3
- "version": "5.3.30",
3
+ "version": "5.4.1",
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": {
@@ -123,4 +123,4 @@
123
123
  "./skills": "./skills/skill-rules.json",
124
124
  "./hooks": "./hooks/index.js"
125
125
  }
126
- }
126
+ }
@@ -1,31 +1,8 @@
1
- const MacOSNotificationAdapter = require('../infrastructure/adapters/MacOSNotificationAdapter');
2
- const FileEvidenceAdapter = require('../infrastructure/adapters/FileEvidenceAdapter');
3
- const GitQueryAdapter = require('../infrastructure/adapters/GitQueryAdapter');
4
- const GitCommandAdapter = require('../infrastructure/adapters/GitCommandAdapter');
5
- const GitHubCliAdapter = require('../infrastructure/adapters/GitHubCliAdapter');
6
- const AstAnalyzerAdapter = require('../infrastructure/adapters/AstAnalyzerAdapter');
7
-
8
- const AutonomousOrchestrator = require('./services/AutonomousOrchestrator');
9
- const ContextDetectionEngine = require('./services/ContextDetectionEngine');
10
- const PlatformDetectionService = require('./services/PlatformDetectionService');
11
- const AutoExecuteAIStartUseCase = require('./use-cases/AutoExecuteAIStartUseCase');
12
-
13
- // Services & Monitors
14
- const RealtimeGuardService = require('./services/RealtimeGuardService');
15
- const UnifiedLogger = require('./services/logging/UnifiedLogger');
16
- const NotificationCenterService = require('./services/notification/NotificationCenterService');
17
- const GitFlowService = require('./services/GitFlowService');
18
- const EvidenceMonitor = require('./services/monitoring/EvidenceMonitor');
19
- const GitTreeMonitor = require('./services/monitoring/GitTreeMonitor');
20
- const TokenMonitor = require('./services/monitoring/TokenMonitor');
21
- const ActivityMonitor = require('./services/monitoring/ActivityMonitor');
22
- const DevDocsMonitor = require('./services/monitoring/DevDocsMonitor');
23
- const AstMonitor = require('./services/monitoring/AstMonitor');
24
- const AuditLogger = require('./services/logging/AuditLogger');
25
-
1
+ const AdapterFactory = require('./factories/AdapterFactory');
2
+ const ServiceFactory = require('./factories/ServiceFactory');
3
+ const MonitorFactory = require('./factories/MonitorFactory');
26
4
  const path = require('path');
27
5
  const fs = require('fs');
28
- const env = require('../config/env');
29
6
 
30
7
  class CompositionRoot {
31
8
  constructor(repoRoot) {
@@ -36,6 +13,39 @@ class CompositionRoot {
36
13
  this.auditDir = path.join(repoRoot, '.audit-reports');
37
14
  this.tempDir = path.join(repoRoot, '.audit_tmp');
38
15
  this._ensureDirectories([this.auditDir, this.tempDir]);
16
+
17
+ // Initialize factories lazily
18
+ this._adapterFactory = null;
19
+ this._serviceFactory = null;
20
+ this._monitorFactory = null;
21
+
22
+ // Create dynamic proxy for automatic delegation
23
+ return new Proxy(this, {
24
+ get(target, prop) {
25
+ // If method exists in CompositionRoot, use it
26
+ if (typeof target[prop] === 'function' && target.hasOwnProperty(prop)) {
27
+ return target[prop].bind(target);
28
+ }
29
+
30
+ // Delegate to specialized factories
31
+ if (target._serviceFactory && typeof target._serviceFactory[prop] === 'function') {
32
+ return target._serviceFactory[prop].bind(target._serviceFactory);
33
+ }
34
+ if (target._adapterFactory && typeof target._adapterFactory[prop] === 'function') {
35
+ return target._adapterFactory[prop].bind(target._adapterFactory);
36
+ }
37
+ if (target._monitorFactory && typeof target._monitorFactory[prop] === 'function') {
38
+ return target._monitorFactory[prop].bind(target._monitorFactory);
39
+ }
40
+
41
+ // Para acceso a propiedades de factories
42
+ if (prop === '_serviceFactory') return target._serviceFactory;
43
+ if (prop === '_adapterFactory') return target._adapterFactory;
44
+ if (prop === '_monitorFactory') return target._monitorFactory;
45
+
46
+ return target[prop];
47
+ }
48
+ });
39
49
  }
40
50
 
41
51
  _ensureDirectories(dirs) {
@@ -46,283 +56,48 @@ class CompositionRoot {
46
56
  });
47
57
  }
48
58
 
49
- getLogger() {
50
- if (!this.instances.has('logger')) {
51
- this.instances.set('logger', new UnifiedLogger({
52
- component: 'HookSystem',
53
- file: {
54
- enabled: true,
55
- path: path.join(this.auditDir, 'guard-audit.jsonl'),
56
- level: env.get('HOOK_LOG_LEVEL', env.isProd ? 'warn' : 'info')
57
- },
58
- console: {
59
- enabled: false,
60
- level: 'info'
61
- }
62
- }));
63
- }
64
- return this.instances.get('logger');
65
- }
66
-
67
- getNotificationService() {
68
- if (!this.instances.has('notificationService')) {
69
- const logger = this.getLogger();
70
- this.instances.set('notificationService', new NotificationCenterService({
71
- repoRoot: this.repoRoot,
72
- logger
73
- }));
74
- }
75
- return this.instances.get('notificationService');
76
- }
77
-
78
- getAuditLogger() {
79
- if (!this.instances.has('auditLogger')) {
80
- const logger = this.getLogger();
81
- this.instances.set('auditLogger', new AuditLogger({
82
- repoRoot: this.repoRoot,
83
- filename: path.join('.audit_tmp', 'audit.log'),
84
- logger
85
- }));
86
- }
87
- return this.instances.get('auditLogger');
88
- }
89
-
90
- // --- Infrastructure Adapters ---
91
-
92
- getNotificationAdapter() {
93
- if (!this.instances.has('notificationAdapter')) {
94
- this.instances.set('notificationAdapter', new MacOSNotificationAdapter());
95
- }
96
- return this.instances.get('notificationAdapter');
97
- }
98
-
99
- getEvidenceAdapter() {
100
- if (!this.instances.has('evidenceAdapter')) {
101
- this.instances.set('evidenceAdapter', new FileEvidenceAdapter(this.repoRoot));
102
- }
103
- return this.instances.get('evidenceAdapter');
104
- }
105
-
106
- getGitQueryAdapter() {
107
- if (!this.instances.has('gitQuery')) {
108
- const logger = this.getLogger();
109
- this.instances.set('gitQuery', new GitQueryAdapter({ repoRoot: this.repoRoot, logger }));
110
- }
111
- return this.instances.get('gitQuery');
112
- }
113
-
114
- getGitCommandAdapter() {
115
- if (!this.instances.has('gitCommand')) {
116
- const logger = this.getLogger();
117
- this.instances.set('gitCommand', new GitCommandAdapter({ repoRoot: this.repoRoot, logger }));
118
- }
119
- return this.instances.get('gitCommand');
120
- }
121
-
122
- getGitHubAdapter() {
123
- if (!this.instances.has('github')) {
124
- const logger = this.getLogger();
125
- this.instances.set('github', new GitHubCliAdapter(this.repoRoot, logger));
59
+ _getAdapterFactory() {
60
+ if (!this._adapterFactory) {
61
+ this._adapterFactory = new AdapterFactory(this.repoRoot, this.instances, this.getLogger());
126
62
  }
127
- return this.instances.get('github');
63
+ return this._adapterFactory;
128
64
  }
129
65
 
130
- getAstAdapter() {
131
- if (!this.instances.has('ast')) {
132
- this.instances.set('ast', new AstAnalyzerAdapter(this.repoRoot));
66
+ _getServiceFactory() {
67
+ if (!this._serviceFactory) {
68
+ this._serviceFactory = new ServiceFactory(this.repoRoot, this.instances, this._getAdapterFactory());
133
69
  }
134
- return this.instances.get('ast');
70
+ return this._serviceFactory;
135
71
  }
136
72
 
137
- // --- Domain Services ---
138
-
139
- getContextDetectionEngine() {
140
- if (!this.instances.has('contextEngine')) {
141
- const gitQuery = this.getGitQueryAdapter();
142
- const logger = this.getLogger();
143
- this.instances.set('contextEngine', new ContextDetectionEngine(gitQuery, logger));
73
+ _getMonitorFactory() {
74
+ if (!this._monitorFactory) {
75
+ this._monitorFactory = new MonitorFactory(this.repoRoot, this.instances, this._getServiceFactory());
144
76
  }
145
- return this.instances.get('contextEngine');
77
+ return this._monitorFactory;
146
78
  }
147
79
 
148
- getPlatformDetectionService() {
149
- if (!this.instances.has('platformDetector')) {
150
- this.instances.set('platformDetector', new PlatformDetectionService());
151
- }
152
- return this.instances.get('platformDetector');
153
- }
154
-
155
- getOrchestrator() {
156
- if (!this.instances.has('orchestrator')) {
157
- const contextEngine = this.getContextDetectionEngine();
158
- const platformDetector = this.getPlatformDetectionService();
159
- const logger = this.getLogger();
160
- // Note: RulesLoader is currently null in Factory, maintaining that behavior or adding if needed
161
-
162
- this.instances.set('orchestrator', new AutonomousOrchestrator(
163
- contextEngine,
164
- platformDetector,
165
- null,
166
- logger
167
- ));
168
- }
169
- return this.instances.get('orchestrator');
80
+ // Essential methods that are not delegated
81
+ getLogger() {
82
+ return this._getServiceFactory().getLogger();
170
83
  }
171
84
 
172
- getAutoExecuteAIStartUseCase() {
173
- if (!this.instances.has('autoExecuteAIStart')) {
174
- const orchestrator = this.getOrchestrator();
175
- const logger = this.getLogger();
176
- this.instances.set('autoExecuteAIStart', new AutoExecuteAIStartUseCase(orchestrator, this.repoRoot, logger));
177
- }
178
- return this.instances.get('autoExecuteAIStart');
85
+ getMonitors() {
86
+ return this._getMonitorFactory().getMonitors();
179
87
  }
180
88
 
181
- getBlockCommitUseCase() {
182
- if (!this.instances.has('blockCommit')) {
183
- const BlockCommitUseCase = require('./use-cases/BlockCommitUseCase');
184
- this.instances.set('blockCommit', new BlockCommitUseCase());
185
- }
186
- return this.instances.get('blockCommit');
89
+ getRealtimeGuardService() {
90
+ const monitors = this.getMonitors();
91
+ return this._getServiceFactory().getRealtimeGuardService(monitors);
187
92
  }
188
93
 
94
+ // MCP Protocol Handler (kept here as it's specific to MCP infrastructure)
189
95
  getMcpProtocolHandler(inputStream, outputStream) {
190
96
  const McpProtocolHandler = require('../infrastructure/mcp/services/McpProtocolHandler');
191
97
  const logger = this.getLogger();
192
98
  return new McpProtocolHandler(inputStream, outputStream, logger);
193
99
  }
194
100
 
195
- // --- Monitors ---
196
-
197
- getEvidenceMonitor() {
198
- if (!this.instances.has('evidenceMonitor')) {
199
- this.instances.set('evidenceMonitor', new EvidenceMonitor(this.repoRoot, {
200
- staleThresholdMs: env.getNumber('HOOK_GUARD_EVIDENCE_STALE_THRESHOLD', 180000),
201
- pollIntervalMs: env.getNumber('HOOK_GUARD_EVIDENCE_POLL_INTERVAL', 30000),
202
- reminderIntervalMs: env.getNumber('HOOK_GUARD_EVIDENCE_REMINDER_INTERVAL', 60000)
203
- }));
204
- }
205
- return this.instances.get('evidenceMonitor');
206
- }
207
-
208
- getGitTreeMonitor() {
209
- if (!this.instances.has('gitTreeMonitor')) {
210
- this.instances.set('gitTreeMonitor', new GitTreeMonitor(this.repoRoot, {
211
- stagedThreshold: env.getNumber('HOOK_GUARD_DIRTY_TREE_STAGED_LIMIT', 10),
212
- unstagedThreshold: env.getNumber('HOOK_GUARD_DIRTY_TREE_UNSTAGED_LIMIT', 15),
213
- totalThreshold: env.getNumber('HOOK_GUARD_DIRTY_TREE_TOTAL_LIMIT', 20),
214
- checkIntervalMs: env.getNumber('HOOK_GUARD_DIRTY_TREE_INTERVAL', 60000),
215
- reminderMs: env.getNumber('HOOK_GUARD_DIRTY_TREE_REMINDER', 300000)
216
- }));
217
- }
218
- return this.instances.get('gitTreeMonitor');
219
- }
220
-
221
- getTokenMonitor() {
222
- if (!this.instances.has('tokenMonitor')) {
223
- this.instances.set('tokenMonitor', new TokenMonitor(this.repoRoot));
224
- }
225
- return this.instances.get('tokenMonitor');
226
- }
227
-
228
- getGitFlowService() {
229
- if (!this.instances.has('gitFlowService')) {
230
- const logger = this.getLogger();
231
- const gitQuery = this.getGitQueryAdapter();
232
- const gitCommand = this.getGitCommandAdapter();
233
- const github = this.getGitHubAdapter();
234
-
235
- this.instances.set('gitFlowService', new GitFlowService(this.repoRoot, {
236
- developBranch: env.get('HOOK_GUARD_GITFLOW_DEVELOP_BRANCH', 'develop'),
237
- mainBranch: env.get('HOOK_GUARD_GITFLOW_MAIN_BRANCH', 'main'),
238
- autoSyncEnabled: env.getBool('HOOK_GUARD_GITFLOW_AUTOSYNC', true),
239
- autoCleanEnabled: env.getBool('HOOK_GUARD_GITFLOW_AUTOCLEAN', true),
240
- requireClean: env.getBool('HOOK_GUARD_GITFLOW_REQUIRE_CLEAN', true)
241
- }, logger, gitQuery, gitCommand, github));
242
- }
243
- return this.instances.get('gitFlowService');
244
- }
245
-
246
- getActivityMonitor() {
247
- if (!this.instances.has('activityMonitor')) {
248
- const logger = this.getLogger();
249
- this.instances.set('activityMonitor', new ActivityMonitor({
250
- repoRoot: this.repoRoot,
251
- inactivityGraceMs: env.getNumber('HOOK_GUARD_INACTIVITY_GRACE_MS', 420000),
252
- logger
253
- }));
254
- }
255
- return this.instances.get('activityMonitor');
256
- }
257
-
258
- getDevDocsMonitor() {
259
- if (!this.instances.has('devDocsMonitor')) {
260
- const logger = this.getLogger();
261
- const notificationService = this.getNotificationService();
262
- this.instances.set('devDocsMonitor', new DevDocsMonitor({
263
- repoRoot: this.repoRoot,
264
- checkIntervalMs: env.getNumber('HOOK_GUARD_DEV_DOCS_CHECK_INTERVAL', 300000),
265
- staleThresholdMs: env.getNumber('HOOK_GUARD_DEV_DOCS_STALE_THRESHOLD', 86400000),
266
- autoRefreshEnabled: env.getBool('HOOK_GUARD_DEV_DOCS_AUTO_REFRESH', true),
267
- logger,
268
- notificationService
269
- }));
270
- }
271
- return this.instances.get('devDocsMonitor');
272
- }
273
-
274
- getAstMonitor() {
275
- if (!this.instances.has('astMonitor')) {
276
- const logger = this.getLogger();
277
- const notificationService = this.getNotificationService();
278
- this.instances.set('astMonitor', new AstMonitor({
279
- repoRoot: this.repoRoot,
280
- debounceMs: env.getNumber('HOOK_AST_WATCH_DEBOUNCE', 8000),
281
- cooldownMs: env.getNumber('HOOK_AST_WATCH_COOLDOWN', 30000),
282
- enabled: env.getBool('HOOK_AST_WATCH', true),
283
- logger,
284
- notificationService
285
- }));
286
- }
287
- return this.instances.get('astMonitor');
288
- }
289
-
290
- getMonitors() {
291
- return {
292
- evidence: this.getEvidenceMonitor(),
293
- gitTree: this.getGitTreeMonitor(),
294
- token: this.getTokenMonitor(),
295
- gitFlow: this.getGitFlowService(),
296
- activity: this.getActivityMonitor(),
297
- devDocs: this.getDevDocsMonitor(),
298
- ast: this.getAstMonitor()
299
- };
300
- }
301
-
302
- getRealtimeGuardService() {
303
- if (!this.instances.has('guardService')) {
304
- const logger = this.getLogger();
305
- const notificationService = this.getNotificationService();
306
- const monitors = this.getMonitors();
307
- const orchestrator = this.getOrchestrator();
308
- const auditLogger = this.getAuditLogger();
309
- const config = {
310
- debugLogPath: path.join(this.auditDir, 'guard-debug.log'),
311
- repoRoot: this.repoRoot
312
- };
313
-
314
- this.instances.set('guardService', new RealtimeGuardService({
315
- logger,
316
- notificationService,
317
- monitors,
318
- orchestration: orchestrator,
319
- config,
320
- auditLogger
321
- }));
322
- }
323
- return this.instances.get('guardService');
324
- }
325
-
326
101
  static createForProduction(repoRoot) {
327
102
  return new CompositionRoot(repoRoot);
328
103
  }
@@ -0,0 +1,58 @@
1
+ const MacOSNotificationAdapter = require('../../adapters/MacOSNotificationAdapter');
2
+ const FileEvidenceAdapter = require('../../adapters/FileEvidenceAdapter');
3
+ const GitQueryAdapter = require('../../adapters/GitQueryAdapter');
4
+ const GitCommandAdapter = require('../../adapters/GitCommandAdapter');
5
+ const GitHubCliAdapter = require('../../adapters/GitHubCliAdapter');
6
+ const AstAnalyzerAdapter = require('../../adapters/AstAnalyzerAdapter');
7
+
8
+ class AdapterFactory {
9
+ constructor(repoRoot, instances, logger) {
10
+ this.repoRoot = repoRoot;
11
+ this.instances = instances;
12
+ this.logger = logger;
13
+ }
14
+
15
+ getNotificationAdapter() {
16
+ if (!this.instances.has('notificationAdapter')) {
17
+ this.instances.set('notificationAdapter', new MacOSNotificationAdapter());
18
+ }
19
+ return this.instances.get('notificationAdapter');
20
+ }
21
+
22
+ getEvidenceAdapter() {
23
+ if (!this.instances.has('evidenceAdapter')) {
24
+ this.instances.set('evidenceAdapter', new FileEvidenceAdapter(this.repoRoot));
25
+ }
26
+ return this.instances.get('evidenceAdapter');
27
+ }
28
+
29
+ getGitQueryAdapter() {
30
+ if (!this.instances.has('gitQuery')) {
31
+ this.instances.set('gitQuery', new GitQueryAdapter({ repoRoot: this.repoRoot, logger: this.logger }));
32
+ }
33
+ return this.instances.get('gitQuery');
34
+ }
35
+
36
+ getGitCommandAdapter() {
37
+ if (!this.instances.has('gitCommand')) {
38
+ this.instances.set('gitCommand', new GitCommandAdapter({ repoRoot: this.repoRoot, logger: this.logger }));
39
+ }
40
+ return this.instances.get('gitCommand');
41
+ }
42
+
43
+ getGitHubAdapter() {
44
+ if (!this.instances.has('github')) {
45
+ this.instances.set('github', new GitHubCliAdapter(this.repoRoot, this.logger));
46
+ }
47
+ return this.instances.get('github');
48
+ }
49
+
50
+ getAstAdapter() {
51
+ if (!this.instances.has('ast')) {
52
+ this.instances.set('ast', new AstAnalyzerAdapter(this.repoRoot));
53
+ }
54
+ return this.instances.get('ast');
55
+ }
56
+ }
57
+
58
+ module.exports = AdapterFactory;
@@ -0,0 +1,104 @@
1
+ const EvidenceMonitor = require('../services/monitoring/EvidenceMonitor');
2
+ const GitTreeMonitor = require('../services/monitoring/GitTreeMonitor');
3
+ const TokenMonitor = require('../services/monitoring/TokenMonitor');
4
+ const ActivityMonitor = require('../services/monitoring/ActivityMonitor');
5
+ const DevDocsMonitor = require('../services/monitoring/DevDocsMonitor');
6
+ const AstMonitor = require('../services/monitoring/AstMonitor');
7
+ const env = require('../../config/env');
8
+
9
+ class MonitorFactory {
10
+ constructor(repoRoot, instances, serviceFactory) {
11
+ this.repoRoot = repoRoot;
12
+ this.instances = instances;
13
+ this.serviceFactory = serviceFactory;
14
+ }
15
+
16
+ getEvidenceMonitor() {
17
+ if (!this.instances.has('evidenceMonitor')) {
18
+ this.instances.set('evidenceMonitor', new EvidenceMonitor(this.repoRoot, {
19
+ staleThresholdMs: env.getNumber('HOOK_GUARD_EVIDENCE_STALE_THRESHOLD', 180000),
20
+ pollIntervalMs: env.getNumber('HOOK_GUARD_EVIDENCE_POLL_INTERVAL', 30000),
21
+ reminderIntervalMs: env.getNumber('HOOK_GUARD_EVIDENCE_REMINDER_INTERVAL', 60000)
22
+ }));
23
+ }
24
+ return this.instances.get('evidenceMonitor');
25
+ }
26
+
27
+ getGitTreeMonitor() {
28
+ if (!this.instances.has('gitTreeMonitor')) {
29
+ this.instances.set('gitTreeMonitor', new GitTreeMonitor(this.repoRoot, {
30
+ stagedThreshold: env.getNumber('HOOK_GUARD_DIRTY_TREE_STAGED_LIMIT', 10),
31
+ unstagedThreshold: env.getNumber('HOOK_GUARD_DIRTY_TREE_UNSTAGED_LIMIT', 15),
32
+ totalThreshold: env.getNumber('HOOK_GUARD_DIRTY_TREE_TOTAL_LIMIT', 20),
33
+ checkIntervalMs: env.getNumber('HOOK_GUARD_DIRTY_TREE_INTERVAL', 60000),
34
+ reminderMs: env.getNumber('HOOK_GUARD_DIRTY_TREE_REMINDER', 300000)
35
+ }));
36
+ }
37
+ return this.instances.get('gitTreeMonitor');
38
+ }
39
+
40
+ getTokenMonitor() {
41
+ if (!this.instances.has('tokenMonitor')) {
42
+ this.instances.set('tokenMonitor', new TokenMonitor(this.repoRoot));
43
+ }
44
+ return this.instances.get('tokenMonitor');
45
+ }
46
+
47
+ getActivityMonitor() {
48
+ if (!this.instances.has('activityMonitor')) {
49
+ const logger = this.serviceFactory.getLogger();
50
+ this.instances.set('activityMonitor', new ActivityMonitor({
51
+ repoRoot: this.repoRoot,
52
+ inactivityGraceMs: env.getNumber('HOOK_GUARD_INACTIVITY_GRACE_MS', 420000),
53
+ logger
54
+ }));
55
+ }
56
+ return this.instances.get('activityMonitor');
57
+ }
58
+
59
+ getDevDocsMonitor() {
60
+ if (!this.instances.has('devDocsMonitor')) {
61
+ const logger = this.serviceFactory.getLogger();
62
+ const notificationService = this.serviceFactory.getNotificationService();
63
+ this.instances.set('devDocsMonitor', new DevDocsMonitor({
64
+ repoRoot: this.repoRoot,
65
+ checkIntervalMs: env.getNumber('HOOK_GUARD_DEV_DOCS_CHECK_INTERVAL', 300000),
66
+ staleThresholdMs: env.getNumber('HOOK_GUARD_DEV_DOCS_STALE_THRESHOLD', 86400000),
67
+ autoRefreshEnabled: env.getBool('HOOK_GUARD_DEV_DOCS_AUTO_REFRESH', true),
68
+ logger,
69
+ notificationService
70
+ }));
71
+ }
72
+ return this.instances.get('devDocsMonitor');
73
+ }
74
+
75
+ getAstMonitor() {
76
+ if (!this.instances.has('astMonitor')) {
77
+ const logger = this.serviceFactory.getLogger();
78
+ const notificationService = this.serviceFactory.getNotificationService();
79
+ this.instances.set('astMonitor', new AstMonitor({
80
+ repoRoot: this.repoRoot,
81
+ debounceMs: env.getNumber('HOOK_AST_WATCH_DEBOUNCE', 8000),
82
+ cooldownMs: env.getNumber('HOOK_AST_WATCH_COOLDOWN', 30000),
83
+ enabled: env.getBool('HOOK_AST_WATCH', true),
84
+ logger,
85
+ notificationService
86
+ }));
87
+ }
88
+ return this.instances.get('astMonitor');
89
+ }
90
+
91
+ getMonitors() {
92
+ return {
93
+ evidence: this.getEvidenceMonitor(),
94
+ gitTree: this.getGitTreeMonitor(),
95
+ token: this.getTokenMonitor(),
96
+ gitFlow: this.serviceFactory.getGitFlowService(),
97
+ activity: this.getActivityMonitor(),
98
+ devDocs: this.getDevDocsMonitor(),
99
+ ast: this.getAstMonitor()
100
+ };
101
+ }
102
+ }
103
+
104
+ module.exports = MonitorFactory;