pumuki-ast-hooks 5.3.18 → 5.3.20
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 +39 -37
- package/package.json +8 -2
- package/scripts/hooks-system/application/CompositionRoot.js +24 -73
- package/scripts/hooks-system/application/services/AutonomousOrchestrator.js +18 -0
- package/scripts/hooks-system/application/services/ContextDetectionEngine.js +58 -0
- package/scripts/hooks-system/application/services/DynamicRulesLoader.js +12 -2
- package/scripts/hooks-system/application/services/GitFlowService.js +80 -0
- package/scripts/hooks-system/application/services/GitTreeState.js +143 -13
- package/scripts/hooks-system/application/services/HookSystemScheduler.js +47 -0
- package/scripts/hooks-system/application/services/IntelligentCommitAnalyzer.js +25 -0
- package/scripts/hooks-system/application/services/IntelligentGitTreeMonitor.js +11 -0
- package/scripts/hooks-system/application/services/PlatformAnalysisService.js +19 -0
- package/scripts/hooks-system/application/services/PlatformDetectionService.js +19 -0
- package/scripts/hooks-system/application/services/PlaybookRunner.js +22 -1
- package/scripts/hooks-system/application/services/PredictiveHookAdvisor.js +19 -0
- package/scripts/hooks-system/application/services/RealtimeGuardPlugin.js +25 -0
- package/scripts/hooks-system/application/services/RealtimeGuardService.js +41 -84
- package/scripts/hooks-system/application/services/SmartDirtyTreeAnalyzer.js +11 -0
- package/scripts/hooks-system/application/services/commit/CommitMessageGenerator.js +11 -0
- package/scripts/hooks-system/application/services/commit/FeatureDetector.js +11 -0
- package/scripts/hooks-system/application/services/evidence/EvidenceContextManager.js +25 -0
- package/scripts/hooks-system/application/services/guard/GuardAutoManagerService.js +21 -31
- package/scripts/hooks-system/application/services/guard/GuardConfig.js +18 -15
- package/scripts/hooks-system/application/services/guard/GuardEventLogger.js +11 -0
- package/scripts/hooks-system/application/services/guard/GuardHealthReminder.js +26 -0
- package/scripts/hooks-system/application/services/guard/GuardHeartbeatMonitor.js +20 -6
- package/scripts/hooks-system/application/services/guard/GuardLockManager.js +11 -0
- package/scripts/hooks-system/application/services/guard/GuardMonitorLoop.js +25 -0
- package/scripts/hooks-system/application/services/guard/GuardNotificationHandler.js +11 -0
- package/scripts/hooks-system/application/services/guard/GuardProcessManager.js +10 -28
- package/scripts/hooks-system/application/services/guard/GuardRecoveryService.js +11 -0
- package/scripts/hooks-system/application/services/installation/ConfigurationGeneratorService.js +18 -0
- package/scripts/hooks-system/application/services/installation/FileSystemInstallerService.js +18 -0
- package/scripts/hooks-system/application/services/installation/GitEnvironmentService.js +18 -3
- package/scripts/hooks-system/application/services/installation/HookInstaller.js +19 -0
- package/scripts/hooks-system/application/services/installation/IdeIntegrationService.js +11 -0
- package/scripts/hooks-system/application/services/installation/InstallService.js +25 -1
- package/scripts/hooks-system/application/services/installation/McpConfigurator.js +19 -2
- package/scripts/hooks-system/application/services/installation/PlatformDetectorService.js +11 -0
- package/scripts/hooks-system/application/services/installation/VSCodeTaskConfigurator.js +11 -0
- package/scripts/hooks-system/application/services/logging/AuditLogger.js +90 -1
- package/scripts/hooks-system/application/services/logging/UnifiedLogger.js +15 -13
- package/scripts/hooks-system/application/services/monitoring/ActivityMonitor.js +33 -0
- package/scripts/hooks-system/application/services/monitoring/AstMonitor.js +27 -0
- package/scripts/hooks-system/application/services/monitoring/DevDocsMonitor.js +26 -0
- package/scripts/hooks-system/application/services/monitoring/EvidenceMonitor.js +19 -0
- package/scripts/hooks-system/application/services/monitoring/EvidenceMonitorService.js +27 -6
- package/scripts/hooks-system/application/services/monitoring/GitTreeMonitor.js +28 -0
- package/scripts/hooks-system/application/services/monitoring/GitTreeMonitorService.js +26 -0
- package/scripts/hooks-system/application/services/monitoring/HealthCheckProviders.js +4 -0
- package/scripts/hooks-system/application/services/monitoring/HealthCheckService.js +25 -0
- package/scripts/hooks-system/application/services/monitoring/HeartbeatMonitorService.js +26 -0
- package/scripts/hooks-system/application/services/monitoring/TokenMonitor.js +26 -0
- package/scripts/hooks-system/application/services/notification/MacNotificationSender.js +11 -0
- package/scripts/hooks-system/application/services/notification/NotificationCenterService.js +18 -0
- package/scripts/hooks-system/application/services/notification/NotificationDispatcher.js +11 -0
- package/scripts/hooks-system/application/services/notification/components/NotificationCooldownManager.js +18 -0
- package/scripts/hooks-system/application/services/notification/components/NotificationDeduplicator.js +18 -0
- package/scripts/hooks-system/application/services/notification/components/NotificationQueue.js +11 -0
- package/scripts/hooks-system/application/services/notification/components/NotificationRetryExecutor.js +20 -0
- package/scripts/hooks-system/application/services/platform/PlatformHeuristics.js +19 -0
- package/scripts/hooks-system/application/services/recovery/AutoRecoveryManager.js +19 -0
- package/scripts/hooks-system/application/services/smart-commit/CommitMessageSuggester.js +11 -0
- package/scripts/hooks-system/application/services/smart-commit/FileContextGrouper.js +19 -0
- package/scripts/hooks-system/application/services/smart-commit/SmartCommitSummaryBuilder.js +4 -0
- package/scripts/hooks-system/application/services/token/CursorTokenService.js +20 -0
- package/scripts/hooks-system/application/services/token/TokenMetricsService.js +11 -13
- package/scripts/hooks-system/application/services/token/TokenMonitorService.js +19 -0
- package/scripts/hooks-system/application/services/token/TokenStatusReporter.js +12 -0
- 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/config/project.config.json +1 -1
- package/scripts/hooks-system/domain/events/index.js +24 -31
- package/scripts/hooks-system/domain/exceptions/index.js +87 -0
- 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 +14 -18
- 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/config/config.js +5 -0
- 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/shell/orchestrators/audit-orchestrator.sh +54 -92
- package/scripts/hooks-system/infrastructure/telemetry/metric-scope.js +98 -0
- package/scripts/hooks-system/infrastructure/telemetry/metrics-server.js +2 -51
- package/scripts/hooks-system/infrastructure/validators/enforce-english-literals.js +8 -6
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
const CursorTokenRepository = require('../../../infrastructure/repositories/CursorTokenRepository');
|
|
2
2
|
|
|
3
|
+
const {
|
|
4
|
+
createMetricScope: createMetricScope
|
|
5
|
+
} = require('../../../infrastructure/telemetry/metric-scope');
|
|
6
|
+
|
|
3
7
|
class CursorTokenService {
|
|
4
8
|
constructor({
|
|
5
9
|
cursorTokenRepository = null,
|
|
@@ -10,6 +14,12 @@ class CursorTokenService {
|
|
|
10
14
|
fetchImpl,
|
|
11
15
|
logger = console
|
|
12
16
|
} = {}) {
|
|
17
|
+
const m_constructor = createMetricScope({
|
|
18
|
+
hook: 'cursor_token_service',
|
|
19
|
+
operation: 'constructor'
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
m_constructor.started();
|
|
13
23
|
this.logger = logger;
|
|
14
24
|
this.repository = cursorTokenRepository || new CursorTokenRepository({
|
|
15
25
|
repoRoot,
|
|
@@ -19,24 +29,34 @@ class CursorTokenService {
|
|
|
19
29
|
fetchImpl,
|
|
20
30
|
logger
|
|
21
31
|
});
|
|
32
|
+
m_constructor.success();
|
|
22
33
|
}
|
|
23
34
|
|
|
24
35
|
async getCurrentUsage() {
|
|
36
|
+
const m_get_current_usage = createMetricScope({
|
|
37
|
+
hook: 'cursor_token_service',
|
|
38
|
+
operation: 'get_current_usage'
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
m_get_current_usage.started();
|
|
25
42
|
// Strategy: First try API (most accurate), then File (fallback/offline)
|
|
26
43
|
|
|
27
44
|
const apiUsage = await this.repository.getUsageFromApi();
|
|
28
45
|
if (apiUsage) {
|
|
29
46
|
this.logger.debug?.('CURSOR_SERVICE_USING_API', { usage: apiUsage });
|
|
47
|
+
m_get_current_usage.success();
|
|
30
48
|
return apiUsage;
|
|
31
49
|
}
|
|
32
50
|
|
|
33
51
|
const fileUsage = await this.repository.getUsageFromFile();
|
|
34
52
|
if (fileUsage) {
|
|
35
53
|
this.logger.debug?.('CURSOR_SERVICE_USING_FILE', { usage: fileUsage });
|
|
54
|
+
m_get_current_usage.success();
|
|
36
55
|
return fileUsage;
|
|
37
56
|
}
|
|
38
57
|
|
|
39
58
|
this.logger.warn?.('CURSOR_SERVICE_NO_DATA_AVAILABLE');
|
|
59
|
+
m_get_current_usage.success();
|
|
40
60
|
return null;
|
|
41
61
|
}
|
|
42
62
|
}
|
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
const { execSync } = require('child_process');
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
const {
|
|
4
|
+
createMetricScope: createMetricScope
|
|
5
|
+
} = require('../../../infrastructure/telemetry/metric-scope');
|
|
5
6
|
|
|
6
7
|
class TokenMetricsService {
|
|
7
8
|
constructor(cursorTokenService, thresholds, logger) {
|
|
9
|
+
const m_constructor = createMetricScope({
|
|
10
|
+
hook: 'token_metrics_service',
|
|
11
|
+
operation: 'constructor'
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
m_constructor.started();
|
|
8
15
|
this.cursorTokenService = cursorTokenService;
|
|
9
16
|
this.thresholds = thresholds;
|
|
10
17
|
this.logger = logger;
|
|
11
18
|
this.repoRoot = process.cwd();
|
|
19
|
+
m_constructor.success();
|
|
12
20
|
}
|
|
13
21
|
|
|
14
22
|
async collectMetrics(fallbackEstimator) {
|
|
@@ -57,8 +65,7 @@ class TokenMetricsService {
|
|
|
57
65
|
if (untrusted) {
|
|
58
66
|
level = 'ok';
|
|
59
67
|
}
|
|
60
|
-
const
|
|
61
|
-
const forceLevel = (env.get('TOKEN_MONITOR_FORCE_LEVEL', '') || '').toLowerCase();
|
|
68
|
+
const forceLevel = (process.env.TOKEN_MONITOR_FORCE_LEVEL || '').toLowerCase();
|
|
62
69
|
if (forceLevel === 'warning' || forceLevel === 'critical' || forceLevel === 'ok') {
|
|
63
70
|
level = forceLevel;
|
|
64
71
|
}
|
|
@@ -79,15 +86,6 @@ class TokenMetricsService {
|
|
|
79
86
|
this.logger.debug('TOKEN_MONITOR_METRICS', metrics);
|
|
80
87
|
}
|
|
81
88
|
|
|
82
|
-
// Record prometheus metrics
|
|
83
|
-
recordMetric({
|
|
84
|
-
hook: 'token_monitor',
|
|
85
|
-
status: 'collect',
|
|
86
|
-
tokensUsed,
|
|
87
|
-
percentUsed: Number(percentUsed.toFixed(0)),
|
|
88
|
-
level
|
|
89
|
-
});
|
|
90
|
-
|
|
91
89
|
return metrics;
|
|
92
90
|
}
|
|
93
91
|
|
|
@@ -2,6 +2,10 @@ const fs = require('fs');
|
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const { execSync } = require('child_process');
|
|
4
4
|
|
|
5
|
+
const {
|
|
6
|
+
createMetricScope: createMetricScope
|
|
7
|
+
} = require('../../../infrastructure/telemetry/metric-scope');
|
|
8
|
+
|
|
5
9
|
const fsPromises = fs.promises;
|
|
6
10
|
const CursorTokenService = require('./CursorTokenService');
|
|
7
11
|
const NotificationCenterService = require('../notification/NotificationCenterService');
|
|
@@ -21,6 +25,12 @@ class TokenMonitorService {
|
|
|
21
25
|
fallbackEstimator = null,
|
|
22
26
|
cursorTokenService = null
|
|
23
27
|
} = {}) {
|
|
28
|
+
const m_constructor = createMetricScope({
|
|
29
|
+
hook: 'token_monitor_service',
|
|
30
|
+
operation: 'constructor'
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
m_constructor.started();
|
|
24
34
|
this.repoRoot = repoRoot;
|
|
25
35
|
this.dataFile = dataFile || path.join(this.repoRoot, '.audit_tmp', 'token-usage.jsonl');
|
|
26
36
|
this.stateFile = stateFile || path.join(this.repoRoot, '.AI_TOKEN_STATUS.txt');
|
|
@@ -47,9 +57,16 @@ class TokenMonitorService {
|
|
|
47
57
|
|
|
48
58
|
this.metricsService = new TokenMetricsService(this.cursorTokenService, this.thresholds, this.logger);
|
|
49
59
|
this.statusReporter = new TokenStatusReporter(this.stateFile);
|
|
60
|
+
m_constructor.success();
|
|
50
61
|
}
|
|
51
62
|
|
|
52
63
|
async run() {
|
|
64
|
+
const m_run = createMetricScope({
|
|
65
|
+
hook: 'token_monitor_service',
|
|
66
|
+
operation: 'run'
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
m_run.started();
|
|
53
70
|
// Collect metrics
|
|
54
71
|
const metrics = await this.metricsService.collectMetrics(this.fallbackEstimator);
|
|
55
72
|
|
|
@@ -59,6 +76,8 @@ class TokenMonitorService {
|
|
|
59
76
|
// Notify
|
|
60
77
|
await this.emitNotification(metrics);
|
|
61
78
|
|
|
79
|
+
m_run.success();
|
|
80
|
+
|
|
62
81
|
return metrics;
|
|
63
82
|
}
|
|
64
83
|
|
|
@@ -1,9 +1,21 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
createMetricScope: createMetricScope
|
|
5
|
+
} = require('../../../infrastructure/telemetry/metric-scope');
|
|
6
|
+
|
|
2
7
|
const fsPromises = fs.promises;
|
|
3
8
|
|
|
4
9
|
class TokenStatusReporter {
|
|
5
10
|
constructor(stateFile) {
|
|
11
|
+
const m_constructor = createMetricScope({
|
|
12
|
+
hook: 'token_status_reporter',
|
|
13
|
+
operation: 'constructor'
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
m_constructor.started();
|
|
6
17
|
this.stateFile = stateFile;
|
|
18
|
+
m_constructor.success();
|
|
7
19
|
}
|
|
8
20
|
|
|
9
21
|
async writeStatusFile(metrics) {
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const os = require('os');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const { execSync } = require('child_process');
|
|
5
|
+
|
|
6
|
+
describe('ast-hooks evidence:update', () => {
|
|
7
|
+
let repoRoot;
|
|
8
|
+
let subdir;
|
|
9
|
+
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'ast-hooks-evidence-cli-'));
|
|
12
|
+
subdir = path.join(repoRoot, 'packages', 'app');
|
|
13
|
+
fs.mkdirSync(subdir, { recursive: true });
|
|
14
|
+
|
|
15
|
+
execSync('git init', { cwd: repoRoot, stdio: 'ignore' });
|
|
16
|
+
execSync('git config user.email "test@example.com"', { cwd: repoRoot, stdio: 'ignore' });
|
|
17
|
+
execSync('git config user.name "Test"', { cwd: repoRoot, stdio: 'ignore' });
|
|
18
|
+
|
|
19
|
+
fs.writeFileSync(path.join(repoRoot, 'README.md'), 'test', 'utf8');
|
|
20
|
+
execSync('git add README.md', { cwd: repoRoot, stdio: 'ignore' });
|
|
21
|
+
execSync('git commit -m "chore: init"', { cwd: repoRoot, stdio: 'ignore' });
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
afterEach(() => {
|
|
25
|
+
fs.rmSync(repoRoot, { recursive: true, force: true });
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('updates .AI_EVIDENCE.json in repo root even when executed from subdirectory', () => {
|
|
29
|
+
const cliPath = path.resolve(__dirname, '..', 'cli.js');
|
|
30
|
+
const output = execSync(`node ${cliPath} evidence:update`, {
|
|
31
|
+
cwd: subdir,
|
|
32
|
+
encoding: 'utf8',
|
|
33
|
+
env: {
|
|
34
|
+
...process.env,
|
|
35
|
+
AUTO_EVIDENCE_TRIGGER: 'test',
|
|
36
|
+
AUTO_EVIDENCE_REASON: 'test',
|
|
37
|
+
AUTO_EVIDENCE_SUMMARY: 'test'
|
|
38
|
+
}
|
|
39
|
+
}).trim();
|
|
40
|
+
|
|
41
|
+
const evidencePath = path.join(repoRoot, '.AI_EVIDENCE.json');
|
|
42
|
+
expect(fs.realpathSync(output)).toBe(fs.realpathSync(evidencePath));
|
|
43
|
+
expect(fs.existsSync(evidencePath)).toBe(true);
|
|
44
|
+
|
|
45
|
+
const json = JSON.parse(fs.readFileSync(evidencePath, 'utf8'));
|
|
46
|
+
expect(typeof json.timestamp).toBe('string');
|
|
47
|
+
expect(json.timestamp.length).toBeGreaterThan(10);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
@@ -121,21 +121,7 @@ const commands = {
|
|
|
121
121
|
},
|
|
122
122
|
|
|
123
123
|
ast: () => {
|
|
124
|
-
|
|
125
|
-
const filteredArgs = [];
|
|
126
|
-
|
|
127
|
-
for (const arg of args) {
|
|
128
|
-
if (arg === '--staged') {
|
|
129
|
-
env.STAGING_ONLY_MODE = '1';
|
|
130
|
-
} else {
|
|
131
|
-
filteredArgs.push(arg);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
execSync(
|
|
136
|
-
`node ${path.join(HOOKS_ROOT, 'infrastructure/ast/ast-intelligence.js')} ${filteredArgs.join(' ')}`,
|
|
137
|
-
{ stdio: 'inherit', env }
|
|
138
|
-
);
|
|
124
|
+
execSync(`node ${path.join(HOOKS_ROOT, 'infrastructure/ast/ast-intelligence.js')}`, { stdio: 'inherit' });
|
|
139
125
|
},
|
|
140
126
|
|
|
141
127
|
install: () => {
|
|
@@ -1,7 +1,13 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const {
|
|
2
|
+
ValidationException,
|
|
3
|
+
BadRequestException,
|
|
4
|
+
InternalServerException
|
|
5
|
+
} = require('../exceptions');
|
|
2
6
|
|
|
3
7
|
class DomainEvent {
|
|
4
8
|
constructor(type, payload) {
|
|
9
|
+
if (!type) throw new ValidationException('Event type is required', { field: 'type' });
|
|
10
|
+
if (!payload) throw new ValidationException('Event payload is required', { field: 'payload' });
|
|
5
11
|
this.type = type;
|
|
6
12
|
this.payload = payload;
|
|
7
13
|
this.timestamp = new Date().toISOString();
|
|
@@ -9,8 +15,8 @@ class DomainEvent {
|
|
|
9
15
|
}
|
|
10
16
|
|
|
11
17
|
validate() {
|
|
12
|
-
if (!this.type) throw new
|
|
13
|
-
if (!this.payload) throw new
|
|
18
|
+
if (!this.type) throw new ValidationException('Event type is required', { field: 'type' });
|
|
19
|
+
if (!this.payload) throw new ValidationException('Event payload is required', { field: 'payload' });
|
|
14
20
|
return true;
|
|
15
21
|
}
|
|
16
22
|
|
|
@@ -31,9 +37,7 @@ class EvidenceStaleEvent extends DomainEvent {
|
|
|
31
37
|
|
|
32
38
|
validate() {
|
|
33
39
|
super.validate();
|
|
34
|
-
if (!this.payload.evidencePath) {
|
|
35
|
-
throw new ValidationError('Evidence path is required', 'payload.evidencePath', this.payload.evidencePath);
|
|
36
|
-
}
|
|
40
|
+
if (!this.payload.evidencePath) throw new ValidationException('Evidence path is required', { field: 'evidencePath' });
|
|
37
41
|
}
|
|
38
42
|
}
|
|
39
43
|
|
|
@@ -45,12 +49,8 @@ class GitFlowViolationEvent extends DomainEvent {
|
|
|
45
49
|
|
|
46
50
|
validate() {
|
|
47
51
|
super.validate();
|
|
48
|
-
if (!this.payload.branch) {
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
if (!this.payload.violation) {
|
|
52
|
-
throw new ValidationError('Violation details are required', 'payload.violation', this.payload.violation);
|
|
53
|
-
}
|
|
52
|
+
if (!this.payload.branch) throw new ValidationException('Branch name is required', { field: 'branch' });
|
|
53
|
+
if (!this.payload.violation) throw new ValidationException('Violation details are required', { field: 'violation' });
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
|
|
@@ -62,9 +62,7 @@ class AstCriticalFoundEvent extends DomainEvent {
|
|
|
62
62
|
|
|
63
63
|
validate() {
|
|
64
64
|
super.validate();
|
|
65
|
-
if (!Array.isArray(this.payload.findings)) {
|
|
66
|
-
throw new ValidationError('Findings must be an array', 'payload.findings', this.payload.findings);
|
|
67
|
-
}
|
|
65
|
+
if (!Array.isArray(this.payload.findings)) throw new ValidationException('Findings must be an array', { field: 'findings' });
|
|
68
66
|
}
|
|
69
67
|
}
|
|
70
68
|
|
|
@@ -73,6 +71,12 @@ class PreCommitBlockedEvent extends DomainEvent {
|
|
|
73
71
|
super('PRE_COMMIT_BLOCKED', { reason, violations });
|
|
74
72
|
this.validate();
|
|
75
73
|
}
|
|
74
|
+
|
|
75
|
+
validate() {
|
|
76
|
+
super.validate();
|
|
77
|
+
if (!this.payload.reason) throw new ValidationException('Reason is required', { field: 'reason' });
|
|
78
|
+
if (!this.payload.violations) throw new ValidationException('Violations are required', { field: 'violations' });
|
|
79
|
+
}
|
|
76
80
|
}
|
|
77
81
|
|
|
78
82
|
class AnalysisCompletedEvent extends DomainEvent {
|
|
@@ -80,13 +84,16 @@ class AnalysisCompletedEvent extends DomainEvent {
|
|
|
80
84
|
super('ANALYSIS_COMPLETED', summary);
|
|
81
85
|
this.validate();
|
|
82
86
|
}
|
|
87
|
+
|
|
88
|
+
validate() {
|
|
89
|
+
super.validate();
|
|
90
|
+
if (!this.payload) throw new ValidationException('Summary is required', { field: 'summary' });
|
|
91
|
+
}
|
|
83
92
|
}
|
|
84
93
|
|
|
85
94
|
class EventBus {
|
|
86
95
|
constructor() {
|
|
87
96
|
this.subscribers = new Map();
|
|
88
|
-
this.processedIds = new Set();
|
|
89
|
-
this.maxProcessed = 500;
|
|
90
97
|
}
|
|
91
98
|
|
|
92
99
|
subscribe(eventType, handler) {
|
|
@@ -106,25 +113,11 @@ class EventBus {
|
|
|
106
113
|
}
|
|
107
114
|
|
|
108
115
|
async publish(event) {
|
|
109
|
-
if (event?.id && this.processedIds.has(event.id)) {
|
|
110
|
-
return event;
|
|
111
|
-
}
|
|
112
116
|
const handlers = this.subscribers.get(event.type) || [];
|
|
113
117
|
const wildcardHandlers = this.subscribers.get('*') || [];
|
|
114
118
|
const allHandlers = [...handlers, ...wildcardHandlers];
|
|
115
119
|
|
|
116
120
|
await Promise.all(allHandlers.map(handler => handler(event)));
|
|
117
|
-
|
|
118
|
-
if (event?.id) {
|
|
119
|
-
this.processedIds.add(event.id);
|
|
120
|
-
if (this.processedIds.size > this.maxProcessed) {
|
|
121
|
-
const iter = this.processedIds.values();
|
|
122
|
-
for (let i = 0; i < 50 && this.processedIds.size > this.maxProcessed; i++) {
|
|
123
|
-
const next = iter.next();
|
|
124
|
-
if (!next.done) this.processedIds.delete(next.value);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
121
|
return event;
|
|
129
122
|
}
|
|
130
123
|
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom Exception Classes for AST Intelligence System
|
|
3
|
+
* Provides structured error handling with specific exception types
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
class BaseException extends Error {
|
|
7
|
+
constructor(message, code = 'INTERNAL_ERROR', statusCode = 500, context = {}) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.name = this.constructor.name;
|
|
10
|
+
this.code = code;
|
|
11
|
+
this.statusCode = statusCode;
|
|
12
|
+
this.timestamp = new Date().toISOString();
|
|
13
|
+
this.context = context;
|
|
14
|
+
|
|
15
|
+
if (Error.captureStackTrace) {
|
|
16
|
+
Error.captureStackTrace(this, this.constructor);
|
|
17
|
+
} else {
|
|
18
|
+
this.stack = (new Error()).stack;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
toJSON() {
|
|
23
|
+
return {
|
|
24
|
+
name: this.name,
|
|
25
|
+
message: this.message,
|
|
26
|
+
code: this.code,
|
|
27
|
+
statusCode: this.statusCode,
|
|
28
|
+
timestamp: this.timestamp,
|
|
29
|
+
context: this.context,
|
|
30
|
+
stack: this.stack
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
class ValidationException extends BaseException {
|
|
36
|
+
constructor(message, field = null, context = {}) {
|
|
37
|
+
super(message, 'VALIDATION_ERROR', 400, context);
|
|
38
|
+
this.field = field;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
class BadRequestException extends BaseException {
|
|
43
|
+
constructor(message, context = {}) {
|
|
44
|
+
super(message, 'BAD_REQUEST', 400, context);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
class NotFoundException extends BaseException {
|
|
49
|
+
constructor(resource = 'Resource', context = {}) {
|
|
50
|
+
super(`${resource} not found`, 'NOT_FOUND', 404, context);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
class UnauthorizedException extends BaseException {
|
|
55
|
+
constructor(message = 'Unauthorized access', context = {}) {
|
|
56
|
+
super(message, 'UNAUTHORIZED', 401, context);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
class ForbiddenException extends BaseException {
|
|
61
|
+
constructor(message = 'Forbidden access', context = {}) {
|
|
62
|
+
super(message, 'FORBIDDEN', 403, context);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
class ConflictException extends BaseException {
|
|
67
|
+
constructor(message, context = {}) {
|
|
68
|
+
super(message, 'CONFLICT', 409, context);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
class InternalServerException extends BaseException {
|
|
73
|
+
constructor(message = 'Internal server error', context = {}) {
|
|
74
|
+
super(message, 'INTERNAL_SERVER_ERROR', 500, context);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
module.exports = {
|
|
79
|
+
BaseException,
|
|
80
|
+
ValidationException,
|
|
81
|
+
BadRequestException,
|
|
82
|
+
NotFoundException,
|
|
83
|
+
UnauthorizedException,
|
|
84
|
+
ForbiddenException,
|
|
85
|
+
ConflictException,
|
|
86
|
+
InternalServerException
|
|
87
|
+
};
|
package/scripts/hooks-system/infrastructure/ast/android/analyzers/AndroidAnalysisOrchestrator.js
CHANGED
|
@@ -40,9 +40,8 @@ class AndroidAnalysisOrchestrator {
|
|
|
40
40
|
return 0.6745 * (x - med) / madValue;
|
|
41
41
|
};
|
|
42
42
|
|
|
43
|
-
const
|
|
44
|
-
const
|
|
45
|
-
const pExtreme = env.getNumber('AST_GODCLASS_P_EXTREME', 97);
|
|
43
|
+
const pOutlier = Number(process.env.AST_GODCLASS_P_OUTLIER || 90);
|
|
44
|
+
const pExtreme = Number(process.env.AST_GODCLASS_P_EXTREME || 97);
|
|
46
45
|
|
|
47
46
|
const methods = this.godClassCandidates.map(c => c.methodsCount);
|
|
48
47
|
const props = this.godClassCandidates.map(c => c.propertiesCount);
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
const { Project, Node, SyntaxKind, ScriptTarget, ModuleKind } = require("ts-morph");
|
|
3
3
|
const path = require("path");
|
|
4
4
|
const fs = require("fs");
|
|
5
|
-
const env = require("../../config/env");
|
|
6
5
|
|
|
7
6
|
let SeverityEvaluator = null;
|
|
8
7
|
let severityEvaluatorInstance = null;
|
|
@@ -20,7 +19,7 @@ function getSeverityEvaluator() {
|
|
|
20
19
|
return severityEvaluatorInstance;
|
|
21
20
|
}
|
|
22
21
|
|
|
23
|
-
let INTELLIGENT_SEVERITY_ENABLED = env.
|
|
22
|
+
let INTELLIGENT_SEVERITY_ENABLED = process.env.INTELLIGENT_SEVERITY === 'true';
|
|
24
23
|
|
|
25
24
|
/**
|
|
26
25
|
* Get repository root directory (portable - dynamic detection)
|
|
@@ -180,18 +179,18 @@ function pushFinding(ruleId, severity, sf, node, message, findings, metrics = {}
|
|
|
180
179
|
let mappedSeverity = mapToLevel(severity);
|
|
181
180
|
const isCleanLayerMarkerRule = ruleId === 'backend.clean.domain' || ruleId === 'backend.clean.application' || ruleId === 'backend.clean.infrastructure' || ruleId === 'backend.clean.presentation';
|
|
182
181
|
let isStrictCriticalRule = false;
|
|
183
|
-
if (env.
|
|
182
|
+
if (process.env.AUDIT_STRICT === '1' && !isCleanLayerMarkerRule) {
|
|
184
183
|
const defaultStrictCriticalRegex = '(solid\\.|architecture\\.|clean\\.|cqrs\\.|tdd\\.|bdd\\.|security\\.|error\\.|testing\\.|performance\\.|metrics\\.|observability\\.|validation\\.|i18n\\.|accessibility\\.|naming\\.)';
|
|
185
184
|
const defaultStrictCriticalRegexLibrary = '(solid\\.|architecture\\.|clean\\.|cqrs\\.|tdd\\.|bdd\\.|security\\.|error\\.|testing\\.|validation\\.|naming\\.)';
|
|
186
|
-
const strictRegexSource = env.
|
|
187
|
-
env.
|
|
188
|
-
? env.
|
|
185
|
+
const strictRegexSource = process.env.AST_STRICT_CRITICAL_RULES_REGEX ||
|
|
186
|
+
(process.env.AUDIT_LIBRARY === 'true'
|
|
187
|
+
? (process.env.AST_STRICT_CRITICAL_RULES_REGEX_LIBRARY || defaultStrictCriticalRegexLibrary)
|
|
189
188
|
: defaultStrictCriticalRegex);
|
|
190
189
|
let strictRegex;
|
|
191
190
|
try {
|
|
192
191
|
strictRegex = new RegExp(strictRegexSource, 'i');
|
|
193
192
|
} catch {
|
|
194
|
-
strictRegex = new RegExp(env.
|
|
193
|
+
strictRegex = new RegExp(process.env.AUDIT_LIBRARY === 'true' ? defaultStrictCriticalRegexLibrary : defaultStrictCriticalRegex, 'i');
|
|
195
194
|
}
|
|
196
195
|
isStrictCriticalRule = strictRegex.test(ruleId);
|
|
197
196
|
if (isStrictCriticalRule) {
|
|
@@ -242,18 +241,18 @@ function pushFileFinding(ruleId, severity, filePath, line, column, message, find
|
|
|
242
241
|
let mappedSeverity = mapToLevel(severity);
|
|
243
242
|
const isCleanLayerMarkerRule = ruleId === 'backend.clean.domain' || ruleId === 'backend.clean.application' || ruleId === 'backend.clean.infrastructure' || ruleId === 'backend.clean.presentation';
|
|
244
243
|
let isStrictCriticalRule = false;
|
|
245
|
-
if (env.
|
|
244
|
+
if (process.env.AUDIT_STRICT === '1' && !isCleanLayerMarkerRule) {
|
|
246
245
|
const defaultStrictCriticalRegex = '(solid\\.|architecture\\.|clean\\.|cqrs\\.|tdd\\.|bdd\\.|security\\.|error\\.|testing\\.|performance\\.|metrics\\.|observability\\.|validation\\.|i18n\\.|accessibility\\.|naming\\.)';
|
|
247
246
|
const defaultStrictCriticalRegexLibrary = '(solid\\.|architecture\\.|clean\\.|cqrs\\.|tdd\\.|bdd\\.|security\\.|error\\.|testing\\.|validation\\.|naming\\.)';
|
|
248
|
-
const strictRegexSource = env.
|
|
249
|
-
env.
|
|
250
|
-
? env.
|
|
247
|
+
const strictRegexSource = process.env.AST_STRICT_CRITICAL_RULES_REGEX ||
|
|
248
|
+
(process.env.AUDIT_LIBRARY === 'true'
|
|
249
|
+
? (process.env.AST_STRICT_CRITICAL_RULES_REGEX_LIBRARY || defaultStrictCriticalRegexLibrary)
|
|
251
250
|
: defaultStrictCriticalRegex);
|
|
252
251
|
let strictRegex;
|
|
253
252
|
try {
|
|
254
253
|
strictRegex = new RegExp(strictRegexSource, 'i');
|
|
255
254
|
} catch {
|
|
256
|
-
strictRegex = new RegExp(env.
|
|
255
|
+
strictRegex = new RegExp(process.env.AUDIT_LIBRARY === 'true' ? defaultStrictCriticalRegexLibrary : defaultStrictCriticalRegex, 'i');
|
|
257
256
|
}
|
|
258
257
|
isStrictCriticalRule = strictRegex.test(ruleId);
|
|
259
258
|
if (isStrictCriticalRule) {
|
|
@@ -333,6 +332,15 @@ function mapToLevel(severity) {
|
|
|
333
332
|
function platformOf(filePath) {
|
|
334
333
|
const p = filePath.replace(/\\/g, "/");
|
|
335
334
|
|
|
335
|
+
if (p.includes("/infrastructure/ast/") && process.env.AUDIT_LIBRARY !== 'true') return null;
|
|
336
|
+
|
|
337
|
+
if (process.env.AUDIT_LIBRARY === 'true') {
|
|
338
|
+
if (p.includes("/infrastructure/ast/backend/") || p.includes("/scripts/hooks-system/infrastructure/ast/backend/")) return "backend";
|
|
339
|
+
if (p.includes("/infrastructure/ast/frontend/") || p.includes("/scripts/hooks-system/infrastructure/ast/frontend/")) return "frontend";
|
|
340
|
+
if (p.includes("/infrastructure/ast/android/") || p.includes("/scripts/hooks-system/infrastructure/ast/android/")) return "android";
|
|
341
|
+
if (p.includes("/infrastructure/ast/ios/") || p.includes("/scripts/hooks-system/infrastructure/ast/ios/")) return "ios";
|
|
342
|
+
}
|
|
343
|
+
|
|
336
344
|
if (p.includes("/apps/backend/") || p.includes("apps/backend/")) return "backend";
|
|
337
345
|
if (p.includes("/apps/admin/") || p.includes("/admin-dashboard/")) return "frontend";
|
|
338
346
|
if (p.includes("/apps/mobile-ios/") || p.includes("/apps/ios/")) return "ios";
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
const path = require("path");
|
|
3
3
|
const fs = require("fs");
|
|
4
|
-
const env = require("../../config/env");
|
|
5
4
|
|
|
6
5
|
const astModulesPath = __dirname;
|
|
7
6
|
const { createProject, platformOf, mapToLevel } = require(path.join(astModulesPath, "ast-core"));
|
|
@@ -28,7 +27,13 @@ async function runASTIntelligence() {
|
|
|
28
27
|
const { getRepoRoot } = require('./ast-core');
|
|
29
28
|
const root = getRepoRoot();
|
|
30
29
|
|
|
31
|
-
const
|
|
30
|
+
const isLibraryAudit = process.env.AUDIT_LIBRARY === 'true';
|
|
31
|
+
|
|
32
|
+
const allFiles = listSourceFiles(root).filter(f => {
|
|
33
|
+
const p = String(f || '').replace(/\\/g, '/');
|
|
34
|
+
if (!isLibraryAudit && p.includes('/infrastructure/ast/')) return false;
|
|
35
|
+
return true;
|
|
36
|
+
});
|
|
32
37
|
|
|
33
38
|
const project = createProject(allFiles);
|
|
34
39
|
const findings = [];
|
|
@@ -70,9 +75,9 @@ async function runASTIntelligence() {
|
|
|
70
75
|
}
|
|
71
76
|
|
|
72
77
|
function runProjectHardcodedThresholdAudit(root, allFiles, findings) {
|
|
73
|
-
if (env.
|
|
78
|
+
if (process.env.AST_INSIGHTS !== '1') return;
|
|
74
79
|
|
|
75
|
-
const maxFindings = env.
|
|
80
|
+
const maxFindings = Number(process.env.AST_INSIGHTS_PROJECT_MAX || 200);
|
|
76
81
|
if (!Number.isFinite(maxFindings) || maxFindings <= 0) return;
|
|
77
82
|
|
|
78
83
|
const isExcludedPath = (filePath) => {
|
|
@@ -155,7 +160,7 @@ function runProjectHardcodedThresholdAudit(root, allFiles, findings) {
|
|
|
155
160
|
}
|
|
156
161
|
|
|
157
162
|
function runHardcodedThresholdAudit(root, findings) {
|
|
158
|
-
if (env.
|
|
163
|
+
if (process.env.AST_INSIGHTS !== '1') return;
|
|
159
164
|
|
|
160
165
|
const ruleDirs = [
|
|
161
166
|
path.join(root, 'infrastructure', 'ast'),
|
|
@@ -312,7 +317,7 @@ async function runPlatformAnalysis(project, findings, context) {
|
|
|
312
317
|
}
|
|
313
318
|
} catch (error) {
|
|
314
319
|
console.error(`[ERROR] Error processing platform ${platform}:`, error.message);
|
|
315
|
-
if (env.
|
|
320
|
+
if (process.env.DEBUG_AST) {
|
|
316
321
|
console.error(error.stack);
|
|
317
322
|
}
|
|
318
323
|
}
|
|
@@ -371,7 +376,7 @@ function generateOutput(findings, context, project, root) {
|
|
|
371
376
|
* Save detailed JSON report
|
|
372
377
|
*/
|
|
373
378
|
function saveDetailedReport(findings, levelTotals, platformTotals, project, root) {
|
|
374
|
-
const outDir = env.
|
|
379
|
+
const outDir = process.env.AUDIT_TMP || path.join(root, ".audit_tmp");
|
|
375
380
|
try {
|
|
376
381
|
fs.mkdirSync(outDir, { recursive: true });
|
|
377
382
|
|
|
@@ -527,7 +532,7 @@ function checkForMigrations(root) {
|
|
|
527
532
|
* List source files recursively
|
|
528
533
|
*/
|
|
529
534
|
function listSourceFiles(root) {
|
|
530
|
-
if (env.
|
|
535
|
+
if (process.env.STAGING_ONLY_MODE === "1") {
|
|
531
536
|
const { execSync } = require("child_process");
|
|
532
537
|
try {
|
|
533
538
|
const allStaged = execSync("git diff --cached --name-only --diff-filter=ACM", {
|
|
@@ -595,6 +600,11 @@ function listSourceFiles(root) {
|
|
|
595
600
|
function shouldIgnore(file) {
|
|
596
601
|
const p = file.replace(/\\/g, "/");
|
|
597
602
|
if (p.includes("node_modules/")) return true;
|
|
603
|
+
|
|
604
|
+
const isLibraryAudit = process.env.AUDIT_LIBRARY === 'true';
|
|
605
|
+
|
|
606
|
+
if (!isLibraryAudit && p.includes("scripts/hooks-system/")) return true;
|
|
607
|
+
if (!isLibraryAudit && p.includes("/infrastructure/ast/")) return true;
|
|
598
608
|
if (p.includes("/.cursor/")) return true;
|
|
599
609
|
if (/\.bak/i.test(p)) return true;
|
|
600
610
|
if (p.includes("/.next/")) return true;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
-
const env = require('../../../../config/env');
|
|
4
3
|
|
|
5
4
|
class BackendPatternDetector {
|
|
6
5
|
constructor(projectRoot) {
|
|
@@ -12,7 +11,7 @@ class BackendPatternDetector {
|
|
|
12
11
|
const fullPath = path.join(this.projectRoot, relativePath);
|
|
13
12
|
return fs.readFileSync(fullPath, 'utf-8');
|
|
14
13
|
} catch (error) {
|
|
15
|
-
if (env.
|
|
14
|
+
if (process.env.DEBUG) {
|
|
16
15
|
console.debug(`[BackendPatternDetector] Failed to read file ${relativePath}: ${error.message}`);
|
|
17
16
|
}
|
|
18
17
|
return '';
|