pumuki-ast-hooks 5.5.60 → 5.6.0

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.
Files changed (45) hide show
  1. package/README.md +361 -1101
  2. package/bin/__tests__/check-version.spec.js +32 -57
  3. package/docs/ARCHITECTURE.md +66 -1
  4. package/docs/TODO.md +41 -0
  5. package/docs/images/ast_intelligence_01.svg +40 -0
  6. package/docs/images/ast_intelligence_02.svg +39 -0
  7. package/docs/images/ast_intelligence_03.svg +55 -0
  8. package/docs/images/ast_intelligence_04.svg +39 -0
  9. package/docs/images/ast_intelligence_05.svg +45 -0
  10. package/docs/images/logo.png +0 -0
  11. package/package.json +1 -1
  12. package/scripts/hooks-system/.audit_tmp/hook-metrics.jsonl +20 -0
  13. package/scripts/hooks-system/application/DIValidationService.js +43 -0
  14. package/scripts/hooks-system/application/__tests__/DIValidationService.spec.js +81 -0
  15. package/scripts/hooks-system/bin/__tests__/check-version.spec.js +37 -57
  16. package/scripts/hooks-system/bin/cli.js +109 -0
  17. package/scripts/hooks-system/config/di-rules.json +42 -0
  18. package/scripts/hooks-system/domain/ports/FileSystemPort.js +19 -0
  19. package/scripts/hooks-system/domain/strategies/ConcreteDependencyStrategy.js +78 -0
  20. package/scripts/hooks-system/domain/strategies/DIStrategy.js +31 -0
  21. package/scripts/hooks-system/infrastructure/adapters/NodeFileSystemAdapter.js +28 -0
  22. package/scripts/hooks-system/infrastructure/ast/ast-core.js +124 -0
  23. package/scripts/hooks-system/infrastructure/ast/backend/ast-backend.js +19 -1
  24. package/scripts/hooks-system/infrastructure/ast/backend/detectors/god-class-detector.js +28 -8
  25. package/scripts/hooks-system/infrastructure/ast/common/ast-common.js +133 -0
  26. package/scripts/hooks-system/infrastructure/ast/frontend/analyzers/__tests__/FrontendArchitectureDetector.spec.js +4 -1
  27. package/scripts/hooks-system/infrastructure/ast/ios/analyzers/__tests__/iOSASTIntelligentAnalyzer.spec.js +3 -1
  28. package/scripts/hooks-system/infrastructure/ast/ios/analyzers/iOSASTIntelligentAnalyzer.js +3 -2
  29. package/scripts/hooks-system/infrastructure/ast/ios/ast-ios.js +1 -1
  30. package/scripts/hooks-system/infrastructure/ast/ios/detectors/ios-ast-intelligent-strategies.js +40 -46
  31. package/scripts/hooks-system/infrastructure/cascade-hooks/README.md +114 -0
  32. package/scripts/hooks-system/infrastructure/cascade-hooks/cascade-hooks-config.json +20 -0
  33. package/scripts/hooks-system/infrastructure/cascade-hooks/claude-code-hook.sh +127 -0
  34. package/scripts/hooks-system/infrastructure/cascade-hooks/post-write-code-hook.js +72 -0
  35. package/scripts/hooks-system/infrastructure/cascade-hooks/pre-write-code-hook.js +167 -0
  36. package/scripts/hooks-system/infrastructure/cascade-hooks/universal-hook-adapter.js +186 -0
  37. package/scripts/hooks-system/infrastructure/mcp/ast-intelligence-automation.js +739 -24
  38. package/scripts/hooks-system/infrastructure/observability/MetricsCollector.js +221 -0
  39. package/scripts/hooks-system/infrastructure/observability/index.js +23 -0
  40. package/scripts/hooks-system/infrastructure/orchestration/__tests__/intelligent-audit.spec.js +177 -0
  41. package/scripts/hooks-system/infrastructure/orchestration/intelligent-audit.js +87 -1
  42. package/scripts/hooks-system/infrastructure/registry/StrategyRegistry.js +63 -0
  43. package/scripts/hooks-system/infrastructure/resilience/CircuitBreaker.js +229 -0
  44. package/scripts/hooks-system/infrastructure/resilience/RetryPolicy.js +141 -0
  45. package/scripts/hooks-system/infrastructure/resilience/index.js +34 -0
@@ -0,0 +1,229 @@
1
+ /**
2
+ * =============================================================================
3
+ * CircuitBreaker - Enterprise Resilience for AST Intelligence
4
+ * =============================================================================
5
+ * Implements Circuit Breaker pattern to prevent cascading failures
6
+ * States: CLOSED (normal) → OPEN (failing) → HALF_OPEN (testing)
7
+ */
8
+
9
+ const STATES = {
10
+ CLOSED: 'CLOSED',
11
+ OPEN: 'OPEN',
12
+ HALF_OPEN: 'HALF_OPEN'
13
+ };
14
+
15
+ class CircuitBreaker {
16
+ constructor(options = {}) {
17
+ this.name = options.name || 'default';
18
+ this.failureThreshold = options.failureThreshold || 5;
19
+ this.successThreshold = options.successThreshold || 2;
20
+ this.timeout = options.timeout || 30000;
21
+ this.resetTimeout = options.resetTimeout || 60000;
22
+
23
+ this.state = STATES.CLOSED;
24
+ this.failures = 0;
25
+ this.successes = 0;
26
+ this.lastFailureTime = null;
27
+ this.nextAttempt = null;
28
+
29
+ this.listeners = {
30
+ stateChange: [],
31
+ failure: [],
32
+ success: [],
33
+ rejected: []
34
+ };
35
+ }
36
+
37
+ async execute(fn, fallback = null) {
38
+ if (this.state === STATES.OPEN) {
39
+ if (Date.now() < this.nextAttempt) {
40
+ this._emit('rejected', { reason: 'Circuit is OPEN' });
41
+ if (fallback) return fallback();
42
+ throw new CircuitBreakerError(`Circuit ${this.name} is OPEN`, this.state);
43
+ }
44
+ this._transition(STATES.HALF_OPEN);
45
+ }
46
+
47
+ try {
48
+ const result = await this._executeWithTimeout(fn);
49
+ this._onSuccess();
50
+ return result;
51
+ } catch (error) {
52
+ this._onFailure(error);
53
+ if (fallback) return fallback();
54
+ throw error;
55
+ }
56
+ }
57
+
58
+ async _executeWithTimeout(fn) {
59
+ return new Promise((resolve, reject) => {
60
+ const timer = setTimeout(() => {
61
+ reject(new Error(`Circuit ${this.name} timeout after ${this.timeout}ms`));
62
+ }, this.timeout);
63
+
64
+ Promise.resolve(fn())
65
+ .then(result => {
66
+ clearTimeout(timer);
67
+ resolve(result);
68
+ })
69
+ .catch(error => {
70
+ clearTimeout(timer);
71
+ reject(error);
72
+ });
73
+ });
74
+ }
75
+
76
+ _onSuccess() {
77
+ this.failures = 0;
78
+ this._emit('success', { state: this.state });
79
+
80
+ if (this.state === STATES.HALF_OPEN) {
81
+ this.successes++;
82
+ if (this.successes >= this.successThreshold) {
83
+ this._transition(STATES.CLOSED);
84
+ }
85
+ }
86
+ }
87
+
88
+ _onFailure(error) {
89
+ this.failures++;
90
+ this.lastFailureTime = Date.now();
91
+ this._emit('failure', { error, failures: this.failures, state: this.state });
92
+
93
+ if (this.state === STATES.HALF_OPEN) {
94
+ this._transition(STATES.OPEN);
95
+ } else if (this.failures >= this.failureThreshold) {
96
+ this._transition(STATES.OPEN);
97
+ }
98
+ }
99
+
100
+ _transition(newState) {
101
+ const oldState = this.state;
102
+ this.state = newState;
103
+
104
+ if (newState === STATES.OPEN) {
105
+ this.nextAttempt = Date.now() + this.resetTimeout;
106
+ this.successes = 0;
107
+ } else if (newState === STATES.CLOSED) {
108
+ this.failures = 0;
109
+ this.successes = 0;
110
+ this.nextAttempt = null;
111
+ } else if (newState === STATES.HALF_OPEN) {
112
+ this.successes = 0;
113
+ }
114
+
115
+ this._emit('stateChange', { from: oldState, to: newState });
116
+ }
117
+
118
+ on(event, callback) {
119
+ if (this.listeners[event]) {
120
+ this.listeners[event].push(callback);
121
+ }
122
+ return this;
123
+ }
124
+
125
+ _emit(event, data) {
126
+ if (this.listeners[event]) {
127
+ for (const callback of this.listeners[event]) {
128
+ try {
129
+ callback({ ...data, circuitName: this.name, timestamp: Date.now() });
130
+ } catch (listenerError) {
131
+ if (process.env.DEBUG) {
132
+ process.stderr.write(`[CircuitBreaker] Listener error: ${listenerError.message}\n`);
133
+ }
134
+ }
135
+ }
136
+ }
137
+ }
138
+
139
+ getState() {
140
+ return {
141
+ name: this.name,
142
+ state: this.state,
143
+ failures: this.failures,
144
+ successes: this.successes,
145
+ lastFailureTime: this.lastFailureTime,
146
+ nextAttempt: this.nextAttempt,
147
+ isOpen: this.state === STATES.OPEN,
148
+ isClosed: this.state === STATES.CLOSED,
149
+ isHalfOpen: this.state === STATES.HALF_OPEN
150
+ };
151
+ }
152
+
153
+ reset() {
154
+ this._transition(STATES.CLOSED);
155
+ }
156
+
157
+ forceOpen() {
158
+ this._transition(STATES.OPEN);
159
+ }
160
+ }
161
+
162
+ class CircuitBreakerError extends Error {
163
+ constructor(message, state) {
164
+ super(message);
165
+ this.name = 'CircuitBreakerError';
166
+ this.state = state;
167
+ }
168
+ }
169
+
170
+ class CircuitBreakerRegistry {
171
+ constructor() {
172
+ this.breakers = new Map();
173
+ }
174
+
175
+ get(name, options = {}) {
176
+ if (!this.breakers.has(name)) {
177
+ this.breakers.set(name, new CircuitBreaker({ name, ...options }));
178
+ }
179
+ return this.breakers.get(name);
180
+ }
181
+
182
+ getAll() {
183
+ const result = {};
184
+ for (const [name, breaker] of this.breakers) {
185
+ result[name] = breaker.getState();
186
+ }
187
+ return result;
188
+ }
189
+
190
+ resetAll() {
191
+ for (const [, breaker] of this.breakers) {
192
+ breaker.reset();
193
+ }
194
+ }
195
+ }
196
+
197
+ const globalRegistry = new CircuitBreakerRegistry();
198
+
199
+ const mcpCircuit = globalRegistry.get('mcp', {
200
+ failureThreshold: 3,
201
+ successThreshold: 2,
202
+ timeout: 5000,
203
+ resetTimeout: 30000
204
+ });
205
+
206
+ const gitCircuit = globalRegistry.get('git', {
207
+ failureThreshold: 5,
208
+ successThreshold: 2,
209
+ timeout: 10000,
210
+ resetTimeout: 60000
211
+ });
212
+
213
+ const astCircuit = globalRegistry.get('ast', {
214
+ failureThreshold: 3,
215
+ successThreshold: 1,
216
+ timeout: 15000,
217
+ resetTimeout: 45000
218
+ });
219
+
220
+ module.exports = {
221
+ CircuitBreaker,
222
+ CircuitBreakerError,
223
+ CircuitBreakerRegistry,
224
+ globalRegistry,
225
+ mcpCircuit,
226
+ gitCircuit,
227
+ astCircuit,
228
+ STATES
229
+ };
@@ -0,0 +1,141 @@
1
+ /**
2
+ * =============================================================================
3
+ * RetryPolicy - Enterprise Resilience for AST Intelligence
4
+ * =============================================================================
5
+ * Configurable retry strategies with exponential backoff, jitter, and hooks
6
+ */
7
+
8
+ class RetryPolicy {
9
+ constructor(options = {}) {
10
+ this.maxRetries = options.maxRetries ?? 3;
11
+ this.baseDelay = options.baseDelay ?? 1000;
12
+ this.maxDelay = options.maxDelay ?? 30000;
13
+ this.backoffMultiplier = options.backoffMultiplier ?? 2;
14
+ this.jitter = options.jitter ?? true;
15
+ this.retryOn = options.retryOn || this._defaultRetryOn;
16
+ this.onRetry = options.onRetry || (() => { });
17
+ }
18
+
19
+ _defaultRetryOn(error) {
20
+ if (error.name === 'CircuitBreakerError') return false;
21
+ if (error.code === 'ECONNREFUSED') return true;
22
+ if (error.code === 'ETIMEDOUT') return true;
23
+ if (error.code === 'ENOTFOUND') return true;
24
+ if (error.message?.includes('timeout')) return true;
25
+ if (error.message?.includes('rate limit')) return true;
26
+ return true;
27
+ }
28
+
29
+ _calculateDelay(attempt) {
30
+ let delay = this.baseDelay * Math.pow(this.backoffMultiplier, attempt);
31
+ delay = Math.min(delay, this.maxDelay);
32
+
33
+ if (this.jitter) {
34
+ const jitterRange = delay * 0.2;
35
+ delay = delay - jitterRange + (Math.random() * jitterRange * 2);
36
+ }
37
+
38
+ return Math.round(delay);
39
+ }
40
+
41
+ async execute(fn) {
42
+ let lastError;
43
+
44
+ for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
45
+ try {
46
+ return await fn();
47
+ } catch (error) {
48
+ lastError = error;
49
+
50
+ if (attempt === this.maxRetries) {
51
+ throw new RetryExhaustedError(
52
+ `All ${this.maxRetries + 1} attempts failed`,
53
+ lastError,
54
+ attempt + 1
55
+ );
56
+ }
57
+
58
+ const shouldRetry = typeof this.retryOn === 'function'
59
+ ? this.retryOn(error, attempt)
60
+ : true;
61
+
62
+ if (!shouldRetry) {
63
+ throw error;
64
+ }
65
+
66
+ const delay = this._calculateDelay(attempt);
67
+
68
+ this.onRetry({
69
+ attempt: attempt + 1,
70
+ maxRetries: this.maxRetries,
71
+ delay,
72
+ error: error.message
73
+ });
74
+
75
+ await this._sleep(delay);
76
+ }
77
+ }
78
+
79
+ throw lastError;
80
+ }
81
+
82
+ _sleep(ms) {
83
+ return new Promise(resolve => setTimeout(resolve, ms));
84
+ }
85
+
86
+ static immediate(maxRetries = 3) {
87
+ return new RetryPolicy({
88
+ maxRetries,
89
+ baseDelay: 0,
90
+ jitter: false
91
+ });
92
+ }
93
+
94
+ static linear(maxRetries = 3, delay = 1000) {
95
+ return new RetryPolicy({
96
+ maxRetries,
97
+ baseDelay: delay,
98
+ backoffMultiplier: 1,
99
+ jitter: false
100
+ });
101
+ }
102
+
103
+ static exponential(maxRetries = 3, baseDelay = 1000) {
104
+ return new RetryPolicy({
105
+ maxRetries,
106
+ baseDelay,
107
+ backoffMultiplier: 2,
108
+ jitter: true
109
+ });
110
+ }
111
+
112
+ static aggressive(maxRetries = 5, baseDelay = 500) {
113
+ return new RetryPolicy({
114
+ maxRetries,
115
+ baseDelay,
116
+ backoffMultiplier: 1.5,
117
+ maxDelay: 10000,
118
+ jitter: true
119
+ });
120
+ }
121
+ }
122
+
123
+ class RetryExhaustedError extends Error {
124
+ constructor(message, lastError, attempts) {
125
+ super(message);
126
+ this.name = 'RetryExhaustedError';
127
+ this.lastError = lastError;
128
+ this.attempts = attempts;
129
+ }
130
+ }
131
+
132
+ async function withRetry(fn, options = {}) {
133
+ const policy = new RetryPolicy(options);
134
+ return policy.execute(fn);
135
+ }
136
+
137
+ module.exports = {
138
+ RetryPolicy,
139
+ RetryExhaustedError,
140
+ withRetry
141
+ };
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Resilience Module - Circuit Breaker & Retry Policies
3
+ */
4
+
5
+ const {
6
+ CircuitBreaker,
7
+ CircuitBreakerError,
8
+ CircuitBreakerRegistry,
9
+ globalRegistry,
10
+ mcpCircuit,
11
+ gitCircuit,
12
+ astCircuit,
13
+ STATES
14
+ } = require('./CircuitBreaker');
15
+
16
+ const {
17
+ RetryPolicy,
18
+ RetryExhaustedError,
19
+ withRetry
20
+ } = require('./RetryPolicy');
21
+
22
+ module.exports = {
23
+ CircuitBreaker,
24
+ CircuitBreakerError,
25
+ CircuitBreakerRegistry,
26
+ globalRegistry,
27
+ mcpCircuit,
28
+ gitCircuit,
29
+ astCircuit,
30
+ STATES,
31
+ RetryPolicy,
32
+ RetryExhaustedError,
33
+ withRetry
34
+ };