pumuki-ast-hooks 5.5.12 → 5.5.15
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/bin/install.js +0 -0
- package/package.json +2 -3
- package/scripts/hooks-system/.audit-reports/auto-recovery.log +1 -0
- package/scripts/hooks-system/.audit-reports/install-wizard.log +4 -0
- package/scripts/hooks-system/.audit_tmp/hook-metrics.jsonl +24 -0
- package/scripts/hooks-system/application/services/PlatformDetectionService.js +5 -1
- package/scripts/hooks-system/application/services/RealtimeGuardService.js +1 -0
- package/scripts/hooks-system/application/services/guard/EvidenceManager.js +33 -8
- package/scripts/hooks-system/application/services/installation/ConfigurationGeneratorService.js +5 -0
- package/scripts/hooks-system/application/services/installation/InstallService.js +42 -0
- package/scripts/hooks-system/application/services/monitoring/EvidenceMonitorService.js +1 -3
- package/scripts/hooks-system/bin/cli.js +19 -1
- package/scripts/hooks-system/bin/evidence-guard +110 -0
- package/scripts/hooks-system/bin/update-evidence.sh +2 -2
- package/scripts/hooks-system/infrastructure/ast/ast-core.js +1 -1
- package/scripts/hooks-system/infrastructure/ast/ast-intelligence.js +20 -6
- package/scripts/hooks-system/infrastructure/daemons/evidence-guard.js +155 -0
- package/scripts/hooks-system/infrastructure/mcp/ast-intelligence-automation.js +1 -3
- package/scripts/hooks-system/infrastructure/orchestration/intelligent-audit.js +21 -5
- package/scripts/hooks-system/infrastructure/shell/orchestrators/audit-orchestrator.sh +0 -25
- package/scripts/hooks-system/infrastructure/utils/timestamp-helper.sh +12 -4
- package/scripts/hooks-system/infrastructure/watchdog/__tests__/.audit-reports/token-monitor.log +3 -0
package/bin/install.js
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pumuki-ast-hooks",
|
|
3
|
-
"version": "5.5.
|
|
3
|
+
"version": "5.5.15",
|
|
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,7 +116,6 @@
|
|
|
116
116
|
},
|
|
117
117
|
"exports": {
|
|
118
118
|
".": "./index.js",
|
|
119
|
-
"./package.json": "./package.json",
|
|
120
119
|
"./ast": "./scripts/hooks-system/infrastructure/ast/ast-intelligence.js",
|
|
121
120
|
"./domain": "./scripts/hooks-system/domain/index.js",
|
|
122
121
|
"./application": "./scripts/hooks-system/application/index.js",
|
|
@@ -124,4 +123,4 @@
|
|
|
124
123
|
"./skills": "./skills/skill-rules.json",
|
|
125
124
|
"./hooks": "./hooks/index.js"
|
|
126
125
|
}
|
|
127
|
-
}
|
|
126
|
+
}
|
|
@@ -6,3 +6,4 @@
|
|
|
6
6
|
{"timestamp":"2026-01-03T13:47:40.470Z","level":"info","component":"AutoRecovery","event":"NotificationCenterService shutdown","data":{"totalEnqueued":0,"totalSent":0,"totalDeduplicated":0,"totalCooldownSkipped":0,"totalFailed":0,"totalRetries":0,"queueSize":0,"deduplication":{"size":0},"cooldowns":{"activeCooldowns":0}},"context":{}}
|
|
7
7
|
{"timestamp":"2026-01-03T13:53:08.976Z","level":"info","component":"AutoRecovery","event":"NotificationCenterService shutdown","data":{"totalEnqueued":0,"totalSent":0,"totalDeduplicated":0,"totalCooldownSkipped":0,"totalFailed":0,"totalRetries":0,"queueSize":0,"deduplication":{"size":0},"cooldowns":{"activeCooldowns":0}},"context":{}}
|
|
8
8
|
{"timestamp":"2026-01-03T14:05:35.588Z","level":"info","component":"AutoRecovery","event":"NotificationCenterService shutdown","data":{"totalEnqueued":0,"totalSent":0,"totalDeduplicated":0,"totalCooldownSkipped":0,"totalFailed":0,"totalRetries":0,"queueSize":0,"deduplication":{"size":0},"cooldowns":{"activeCooldowns":0}},"context":{}}
|
|
9
|
+
{"timestamp":"2026-01-04T07:12:12.600Z","level":"info","component":"AutoRecovery","event":"NotificationCenterService shutdown","data":{"totalEnqueued":0,"totalSent":0,"totalDeduplicated":0,"totalCooldownSkipped":0,"totalFailed":0,"totalRetries":0,"queueSize":0,"deduplication":{"size":0},"cooldowns":{"activeCooldowns":0}},"context":{}}
|
|
@@ -30,3 +30,7 @@
|
|
|
30
30
|
{"timestamp":"2026-01-03T14:05:35.955Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_CONFIG_EXISTS","data":{"configPath":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system/.hook-system/config.json"},"context":{}}
|
|
31
31
|
{"timestamp":"2026-01-03T14:05:35.955Z","level":"error","component":"InstallWizard","event":"INSTALL_WIZARD_SYMLINK_FAILED","data":{"error":"EEXIST: file already exists, symlink '/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system/scripts/hooks-system/bin/guard-supervisor.js' -> '/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system/.git/hooks/guard-supervisor'"},"context":{}}
|
|
32
32
|
{"timestamp":"2026-01-03T14:05:35.955Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_COMPLETED","data":{},"context":{}}
|
|
33
|
+
{"timestamp":"2026-01-04T07:12:12.823Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_START","data":{"repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"},"context":{}}
|
|
34
|
+
{"timestamp":"2026-01-04T07:12:12.834Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_CONFIG_EXISTS","data":{"configPath":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system/.hook-system/config.json"},"context":{}}
|
|
35
|
+
{"timestamp":"2026-01-04T07:12:12.835Z","level":"error","component":"InstallWizard","event":"INSTALL_WIZARD_SYMLINK_FAILED","data":{"error":"EEXIST: file already exists, symlink '/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system/scripts/hooks-system/bin/guard-supervisor.js' -> '/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system/.git/hooks/guard-supervisor'"},"context":{}}
|
|
36
|
+
{"timestamp":"2026-01-04T07:12:12.835Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_COMPLETED","data":{},"context":{}}
|
|
@@ -94,3 +94,27 @@
|
|
|
94
94
|
{"timestamp":1767449135588,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
95
95
|
{"timestamp":1767449135588,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
96
96
|
{"timestamp":1767449135588,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
97
|
+
{"timestamp":1767510732597,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
98
|
+
{"timestamp":1767510732599,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
99
|
+
{"timestamp":1767510732599,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
100
|
+
{"timestamp":1767510732599,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
101
|
+
{"timestamp":1767510732599,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
102
|
+
{"timestamp":1767510732599,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
103
|
+
{"timestamp":1767510732599,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
104
|
+
{"timestamp":1767510732599,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
105
|
+
{"timestamp":1767510732599,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
106
|
+
{"timestamp":1767510732599,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
107
|
+
{"timestamp":1767510732599,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
108
|
+
{"timestamp":1767510732599,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
109
|
+
{"timestamp":1767510732599,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
110
|
+
{"timestamp":1767510732599,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
111
|
+
{"timestamp":1767510732599,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
112
|
+
{"timestamp":1767510732599,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
113
|
+
{"timestamp":1767510732599,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
114
|
+
{"timestamp":1767510732599,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
115
|
+
{"timestamp":1767510732599,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
116
|
+
{"timestamp":1767510732599,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
117
|
+
{"timestamp":1767510732600,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
118
|
+
{"timestamp":1767510732600,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
119
|
+
{"timestamp":1767510732600,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
120
|
+
{"timestamp":1767510732600,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
@@ -116,7 +116,11 @@ class PlatformDetectionService {
|
|
|
116
116
|
_detectPlatformUncached(filePath) {
|
|
117
117
|
const lowerPath = filePath.toLowerCase();
|
|
118
118
|
|
|
119
|
-
if (lowerPath.includes('
|
|
119
|
+
if (lowerPath.includes('scripts/hooks-system/')) {
|
|
120
|
+
return 'other';
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (lowerPath.includes('apps/backend/') || lowerPath.includes('/services/') || lowerPath.includes('services/') || lowerPath.includes('/functions/') || lowerPath.includes('functions/')) {
|
|
120
124
|
return 'backend';
|
|
121
125
|
}
|
|
122
126
|
if (lowerPath.includes('apps/web-app/') || lowerPath.includes('apps/admin')) {
|
|
@@ -2,6 +2,10 @@ const fs = require('fs');
|
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const { recordMetric } = require('../../../infrastructure/telemetry/metrics-logger');
|
|
4
4
|
const env = require('../../../config/env.js');
|
|
5
|
+
const { execFile } = require('child_process');
|
|
6
|
+
const { promisify } = require('util');
|
|
7
|
+
|
|
8
|
+
const execFileAsync = promisify(execFile);
|
|
5
9
|
|
|
6
10
|
class EvidenceManager {
|
|
7
11
|
constructor(evidencePath, notifier, auditLogger, delegate = null) {
|
|
@@ -9,7 +13,7 @@ class EvidenceManager {
|
|
|
9
13
|
this.notifier = notifier;
|
|
10
14
|
this.auditLogger = auditLogger;
|
|
11
15
|
this.delegate = delegate;
|
|
12
|
-
this.staleThresholdMs = env.getNumber('HOOK_GUARD_EVIDENCE_STALE_THRESHOLD',
|
|
16
|
+
this.staleThresholdMs = env.getNumber('HOOK_GUARD_EVIDENCE_STALE_THRESHOLD', 180000);
|
|
13
17
|
this.reminderIntervalMs = env.getNumber('HOOK_GUARD_EVIDENCE_REMINDER_INTERVAL', 60000);
|
|
14
18
|
this.inactivityGraceMs = env.getNumber('HOOK_GUARD_INACTIVITY_GRACE_MS', 120000);
|
|
15
19
|
this.pollIntervalMs = env.getNumber('HOOK_GUARD_EVIDENCE_POLL_INTERVAL', 30000);
|
|
@@ -54,10 +58,10 @@ class EvidenceManager {
|
|
|
54
58
|
}
|
|
55
59
|
const raw = fs.readFileSync(this.evidencePath, 'utf8');
|
|
56
60
|
const json = JSON.parse(raw);
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
const ms =
|
|
60
|
-
if (
|
|
61
|
+
const ts = json?.timestamp;
|
|
62
|
+
if (!ts) return null;
|
|
63
|
+
const ms = new Date(ts).getTime();
|
|
64
|
+
if (Number.isNaN(ms)) return null;
|
|
61
65
|
return ms;
|
|
62
66
|
} catch (error) {
|
|
63
67
|
const msg = error && error.message ? error.message : String(error);
|
|
@@ -127,7 +131,7 @@ class EvidenceManager {
|
|
|
127
131
|
}
|
|
128
132
|
|
|
129
133
|
async attemptAutoRefresh(reason = 'manual') {
|
|
130
|
-
if (!env.getBool('HOOK_GUARD_AUTO_REFRESH',
|
|
134
|
+
if (!env.getBool('HOOK_GUARD_AUTO_REFRESH', true)) return;
|
|
131
135
|
|
|
132
136
|
const updateScriptCandidates = [
|
|
133
137
|
path.join(process.cwd(), 'scripts/hooks-system/bin/update-evidence.sh'),
|
|
@@ -165,8 +169,29 @@ class EvidenceManager {
|
|
|
165
169
|
}
|
|
166
170
|
|
|
167
171
|
async runDirectEvidenceRefresh(_reason) {
|
|
168
|
-
|
|
169
|
-
|
|
172
|
+
const updateScriptCandidates = [
|
|
173
|
+
path.join(process.cwd(), 'scripts/hooks-system/bin/update-evidence.sh'),
|
|
174
|
+
path.join(process.cwd(), 'node_modules/@pumuki/ast-intelligence-hooks/scripts/hooks-system/bin/update-evidence.sh'),
|
|
175
|
+
path.join(process.cwd(), 'node_modules/pumuki-ast-hooks/scripts/hooks-system/bin/update-evidence.sh')
|
|
176
|
+
];
|
|
177
|
+
|
|
178
|
+
const updateScript = updateScriptCandidates.find(p => fs.existsSync(p));
|
|
179
|
+
if (!updateScript) return;
|
|
180
|
+
|
|
181
|
+
try {
|
|
182
|
+
await execFileAsync('bash', [updateScript, '--auto'], {
|
|
183
|
+
cwd: process.cwd(),
|
|
184
|
+
env: {
|
|
185
|
+
...process.env,
|
|
186
|
+
AUTO_EVIDENCE_TRIGGER: 'auto',
|
|
187
|
+
AUTO_EVIDENCE_REASON: 'guard.auto_refresh',
|
|
188
|
+
AUTO_EVIDENCE_SUMMARY: 'auto-refresh'
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
} catch (error) {
|
|
192
|
+
const msg = error && error.message ? error.message : String(error);
|
|
193
|
+
this.notifier.appendDebugLog(`EVIDENCE_AUTO_REFRESH_ERROR|${msg}`);
|
|
194
|
+
}
|
|
170
195
|
}
|
|
171
196
|
|
|
172
197
|
updateUserActivity() {
|
package/scripts/hooks-system/application/services/installation/ConfigurationGeneratorService.js
CHANGED
|
@@ -110,6 +110,11 @@ class ConfigurationGeneratorService {
|
|
|
110
110
|
// Add helper scripts
|
|
111
111
|
packageJson.scripts['ast:refresh'] = 'node scripts/hooks-system/bin/update-evidence.sh';
|
|
112
112
|
packageJson.scripts['ast:audit'] = 'node scripts/hooks-system/infrastructure/ast/ast-intelligence.js';
|
|
113
|
+
packageJson.scripts['ast:guard:start'] = 'bash scripts/hooks-system/bin/evidence-guard start';
|
|
114
|
+
packageJson.scripts['ast:guard:stop'] = 'bash scripts/hooks-system/bin/evidence-guard stop';
|
|
115
|
+
packageJson.scripts['ast:guard:restart'] = 'bash scripts/hooks-system/bin/evidence-guard restart';
|
|
116
|
+
packageJson.scripts['ast:guard:status'] = 'bash scripts/hooks-system/bin/evidence-guard status';
|
|
117
|
+
packageJson.scripts['ast:guard:logs'] = 'bash scripts/hooks-system/bin/evidence-guard logs';
|
|
113
118
|
|
|
114
119
|
fs.writeFileSync(projectPackageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
115
120
|
this.logSuccess('npm scripts added');
|
|
@@ -123,10 +123,48 @@ class InstallService {
|
|
|
123
123
|
this.logStep('8/8', 'Adding npm scripts to package.json...');
|
|
124
124
|
this.configGenerator.addNpmScripts();
|
|
125
125
|
|
|
126
|
+
this.logStep('8.5/8', 'Starting evidence guard daemon...');
|
|
127
|
+
this.startEvidenceGuard();
|
|
128
|
+
|
|
126
129
|
this.logger.info('INSTALLATION_COMPLETED_SUCCESSFULLY');
|
|
127
130
|
this.printFooter();
|
|
128
131
|
}
|
|
129
132
|
|
|
133
|
+
startEvidenceGuard() {
|
|
134
|
+
const { spawn } = require('child_process');
|
|
135
|
+
const guardScript = path.join(this.targetRoot, 'scripts/hooks-system/bin/evidence-guard');
|
|
136
|
+
|
|
137
|
+
if (!fs.existsSync(guardScript)) {
|
|
138
|
+
this.logWarning('Evidence guard script not found, skipping daemon start');
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
try {
|
|
143
|
+
const child = spawn('bash', [guardScript, 'start'], {
|
|
144
|
+
cwd: this.targetRoot,
|
|
145
|
+
stdio: 'pipe',
|
|
146
|
+
detached: false
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
let output = '';
|
|
150
|
+
child.stdout.on('data', (data) => { output += data.toString(); });
|
|
151
|
+
child.stderr.on('data', (data) => { output += data.toString(); });
|
|
152
|
+
|
|
153
|
+
child.on('close', (code) => {
|
|
154
|
+
if (code === 0) {
|
|
155
|
+
this.logSuccess('Evidence guard daemon started');
|
|
156
|
+
} else {
|
|
157
|
+
this.logWarning('Failed to start evidence guard daemon');
|
|
158
|
+
if (output) {
|
|
159
|
+
console.log(output);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
} catch (error) {
|
|
164
|
+
this.logWarning(`Failed to start evidence guard: ${error.message}`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
130
168
|
printHeader() {
|
|
131
169
|
const versionPadded = `v${this.version}`.padStart(24).padEnd(48);
|
|
132
170
|
process.stdout.write(`${COLORS.blue}
|
|
@@ -141,6 +179,10 @@ ${COLORS.reset}\n`);
|
|
|
141
179
|
process.stdout.write(`
|
|
142
180
|
${COLORS.green}✨ Installation Complete! ✨${COLORS.reset}
|
|
143
181
|
|
|
182
|
+
${COLORS.cyan}Evidence Guard Daemon:${COLORS.reset}
|
|
183
|
+
- Auto-refresh is now running in background (every 180 seconds)
|
|
184
|
+
- Manage with: ${COLORS.yellow}npm run ast:guard:{start|stop|status|logs}${COLORS.reset}
|
|
185
|
+
|
|
144
186
|
${COLORS.cyan}Next Steps:${COLORS.reset}
|
|
145
187
|
1. Review generated configuration in ${COLORS.yellow}scripts/hooks-system/config/project.config.json${COLORS.reset}
|
|
146
188
|
2. Run ${COLORS.yellow}./manage-library.sh verify${COLORS.reset} to check installation
|
|
@@ -89,9 +89,7 @@ class EvidenceMonitorService {
|
|
|
89
89
|
try {
|
|
90
90
|
const raw = this.fs.readFileSync(this.evidencePath, 'utf8');
|
|
91
91
|
const data = JSON.parse(raw);
|
|
92
|
-
const
|
|
93
|
-
const severityTimestamp = new Date(data?.severity_metrics?.last_updated).getTime();
|
|
94
|
-
const timestamp = [rootTimestamp, severityTimestamp].filter(Number.isFinite).reduce((max, v) => Math.max(max, v), NaN);
|
|
92
|
+
const timestamp = new Date(data.timestamp).getTime();
|
|
95
93
|
if (!Number.isFinite(timestamp)) {
|
|
96
94
|
this.notify({
|
|
97
95
|
message: 'Evidence timestamp is invalid.',
|
|
@@ -16,6 +16,24 @@ const args = process.argv.slice(3);
|
|
|
16
16
|
|
|
17
17
|
const HOOKS_ROOT = path.join(__dirname, '..');
|
|
18
18
|
|
|
19
|
+
function formatLocalTimestamp(date = new Date()) {
|
|
20
|
+
const year = date.getFullYear();
|
|
21
|
+
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
22
|
+
const day = String(date.getDate()).padStart(2, '0');
|
|
23
|
+
const hours = String(date.getHours()).padStart(2, '0');
|
|
24
|
+
const minutes = String(date.getMinutes()).padStart(2, '0');
|
|
25
|
+
const seconds = String(date.getSeconds()).padStart(2, '0');
|
|
26
|
+
const milliseconds = String(date.getMilliseconds()).padStart(3, '0');
|
|
27
|
+
|
|
28
|
+
const offsetMinutes = date.getTimezoneOffset();
|
|
29
|
+
const sign = offsetMinutes <= 0 ? '+' : '-';
|
|
30
|
+
const absolute = Math.abs(offsetMinutes);
|
|
31
|
+
const offsetHours = String(Math.floor(absolute / 60)).padStart(2, '0');
|
|
32
|
+
const offsetMins = String(absolute % 60).padStart(2, '0');
|
|
33
|
+
|
|
34
|
+
return `${year}-${month}-${day}T${hours}:${minutes}:${seconds}.${milliseconds}${sign}${offsetHours}:${offsetMins}`;
|
|
35
|
+
}
|
|
36
|
+
|
|
19
37
|
function resolveRepoRoot() {
|
|
20
38
|
try {
|
|
21
39
|
const output = execSync('git rev-parse --show-toplevel', { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
|
|
@@ -140,7 +158,7 @@ const commands = {
|
|
|
140
158
|
|
|
141
159
|
const next = {
|
|
142
160
|
...existing,
|
|
143
|
-
timestamp:
|
|
161
|
+
timestamp: formatLocalTimestamp(),
|
|
144
162
|
trigger: process.env.AUTO_EVIDENCE_TRIGGER ?? existing.trigger,
|
|
145
163
|
reason: process.env.AUTO_EVIDENCE_REASON ?? existing.reason,
|
|
146
164
|
summary: process.env.AUTO_EVIDENCE_SUMMARY ?? existing.summary,
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
4
|
+
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
|
|
5
|
+
GUARD_SCRIPT="$SCRIPT_DIR/../infrastructure/daemons/evidence-guard.js"
|
|
6
|
+
PID_FILE="$PROJECT_ROOT/.evidence-guard.pid"
|
|
7
|
+
LOG_FILE="$PROJECT_ROOT/.evidence-guard.log"
|
|
8
|
+
|
|
9
|
+
command="${1:-status}"
|
|
10
|
+
|
|
11
|
+
case "$command" in
|
|
12
|
+
start)
|
|
13
|
+
if [ -f "$PID_FILE" ]; then
|
|
14
|
+
PID=$(cat "$PID_FILE")
|
|
15
|
+
if kill -0 "$PID" 2>/dev/null; then
|
|
16
|
+
echo "Evidence guard is already running (PID: $PID)"
|
|
17
|
+
exit 0
|
|
18
|
+
else
|
|
19
|
+
rm -f "$PID_FILE"
|
|
20
|
+
fi
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
echo "Starting evidence guard..."
|
|
24
|
+
nohup node "$GUARD_SCRIPT" > "$LOG_FILE" 2>&1 &
|
|
25
|
+
sleep 1
|
|
26
|
+
|
|
27
|
+
if [ -f "$PID_FILE" ]; then
|
|
28
|
+
PID=$(cat "$PID_FILE")
|
|
29
|
+
echo "Evidence guard started (PID: $PID)"
|
|
30
|
+
echo "Log file: $LOG_FILE"
|
|
31
|
+
else
|
|
32
|
+
echo "Failed to start evidence guard"
|
|
33
|
+
exit 1
|
|
34
|
+
fi
|
|
35
|
+
;;
|
|
36
|
+
|
|
37
|
+
stop)
|
|
38
|
+
if [ ! -f "$PID_FILE" ]; then
|
|
39
|
+
echo "Evidence guard is not running"
|
|
40
|
+
exit 0
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
PID=$(cat "$PID_FILE")
|
|
44
|
+
if kill -0 "$PID" 2>/dev/null; then
|
|
45
|
+
echo "Stopping evidence guard (PID: $PID)..."
|
|
46
|
+
kill "$PID"
|
|
47
|
+
sleep 1
|
|
48
|
+
|
|
49
|
+
if kill -0 "$PID" 2>/dev/null; then
|
|
50
|
+
echo "Force killing evidence guard..."
|
|
51
|
+
kill -9 "$PID"
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
rm -f "$PID_FILE"
|
|
55
|
+
echo "Evidence guard stopped"
|
|
56
|
+
else
|
|
57
|
+
echo "Evidence guard is not running (stale PID file)"
|
|
58
|
+
rm -f "$PID_FILE"
|
|
59
|
+
fi
|
|
60
|
+
;;
|
|
61
|
+
|
|
62
|
+
restart)
|
|
63
|
+
"$0" stop
|
|
64
|
+
sleep 1
|
|
65
|
+
"$0" start
|
|
66
|
+
;;
|
|
67
|
+
|
|
68
|
+
status)
|
|
69
|
+
if [ ! -f "$PID_FILE" ]; then
|
|
70
|
+
echo "Evidence guard is not running"
|
|
71
|
+
exit 1
|
|
72
|
+
fi
|
|
73
|
+
|
|
74
|
+
PID=$(cat "$PID_FILE")
|
|
75
|
+
if kill -0 "$PID" 2>/dev/null; then
|
|
76
|
+
echo "Evidence guard is running (PID: $PID)"
|
|
77
|
+
if [ -f "$LOG_FILE" ]; then
|
|
78
|
+
echo ""
|
|
79
|
+
echo "Recent activity:"
|
|
80
|
+
tail -n 5 "$LOG_FILE"
|
|
81
|
+
fi
|
|
82
|
+
exit 0
|
|
83
|
+
else
|
|
84
|
+
echo "Evidence guard is not running (stale PID file)"
|
|
85
|
+
rm -f "$PID_FILE"
|
|
86
|
+
exit 1
|
|
87
|
+
fi
|
|
88
|
+
;;
|
|
89
|
+
|
|
90
|
+
logs)
|
|
91
|
+
if [ -f "$LOG_FILE" ]; then
|
|
92
|
+
tail -f "$LOG_FILE"
|
|
93
|
+
else
|
|
94
|
+
echo "No log file found"
|
|
95
|
+
exit 1
|
|
96
|
+
fi
|
|
97
|
+
;;
|
|
98
|
+
|
|
99
|
+
*)
|
|
100
|
+
echo "Usage: $0 {start|stop|restart|status|logs}"
|
|
101
|
+
echo ""
|
|
102
|
+
echo "Commands:"
|
|
103
|
+
echo " start - Start the evidence guard daemon"
|
|
104
|
+
echo " stop - Stop the evidence guard daemon"
|
|
105
|
+
echo " restart - Restart the evidence guard daemon"
|
|
106
|
+
echo " status - Check if the daemon is running"
|
|
107
|
+
echo " logs - Tail the daemon logs"
|
|
108
|
+
exit 1
|
|
109
|
+
;;
|
|
110
|
+
esac
|
|
@@ -14,9 +14,9 @@ for arg in "$@"; do
|
|
|
14
14
|
fi
|
|
15
15
|
done
|
|
16
16
|
|
|
17
|
-
CLI="$REPO_ROOT/
|
|
17
|
+
CLI="$REPO_ROOT/scripts/hooks-system/bin/cli.js"
|
|
18
18
|
if [[ ! -f "$CLI" ]]; then
|
|
19
|
-
CLI="$REPO_ROOT/scripts/hooks-system/bin/cli.js"
|
|
19
|
+
CLI="$REPO_ROOT/node_modules/pumuki-ast-hooks/scripts/hooks-system/bin/cli.js"
|
|
20
20
|
fi
|
|
21
21
|
|
|
22
22
|
if [[ ! -f "$CLI" ]]; then
|
|
@@ -339,7 +339,7 @@ function platformOf(filePath) {
|
|
|
339
339
|
if (p.includes("/apps/mobile-android/") || p.includes("/apps/android/")) return "android";
|
|
340
340
|
|
|
341
341
|
if (p.includes("/landing-page/") || p.includes("landing-page/")) return "frontend";
|
|
342
|
-
if (p.includes("/scripts/hooks-system/") || p.includes("scripts/hooks-system/")) return
|
|
342
|
+
if (p.includes("/scripts/hooks-system/") || p.includes("scripts/hooks-system/")) return null;
|
|
343
343
|
if (p.includes("/packages/ast-hooks/") || p.includes("packages/ast-hooks/")) return "backend";
|
|
344
344
|
|
|
345
345
|
if (p.endsWith(".swift")) return "ios";
|
|
@@ -3,6 +3,24 @@ const path = require("path");
|
|
|
3
3
|
const fs = require("fs");
|
|
4
4
|
const env = require("../../config/env.js");
|
|
5
5
|
|
|
6
|
+
function formatLocalTimestamp(date = new Date()) {
|
|
7
|
+
const year = date.getFullYear();
|
|
8
|
+
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
9
|
+
const day = String(date.getDate()).padStart(2, '0');
|
|
10
|
+
const hours = String(date.getHours()).padStart(2, '0');
|
|
11
|
+
const minutes = String(date.getMinutes()).padStart(2, '0');
|
|
12
|
+
const seconds = String(date.getSeconds()).padStart(2, '0');
|
|
13
|
+
const milliseconds = String(date.getMilliseconds()).padStart(3, '0');
|
|
14
|
+
|
|
15
|
+
const offsetMinutes = date.getTimezoneOffset();
|
|
16
|
+
const sign = offsetMinutes <= 0 ? '+' : '-';
|
|
17
|
+
const absolute = Math.abs(offsetMinutes);
|
|
18
|
+
const offsetHours = String(Math.floor(absolute / 60)).padStart(2, '0');
|
|
19
|
+
const offsetMins = String(absolute % 60).padStart(2, '0');
|
|
20
|
+
|
|
21
|
+
return `${year}-${month}-${day}T${hours}:${minutes}:${seconds}.${milliseconds}${sign}${offsetHours}:${offsetMins}`;
|
|
22
|
+
}
|
|
23
|
+
|
|
6
24
|
const astModulesPath = __dirname;
|
|
7
25
|
const { createProject, platformOf, mapToLevel } = require(path.join(astModulesPath, "ast-core"));
|
|
8
26
|
const { MacOSNotificationAdapter } = require(path.join(__dirname, '../adapters/MacOSNotificationAdapter'));
|
|
@@ -474,7 +492,7 @@ function saveDetailedReport(findings, levelTotals, platformTotals, project, root
|
|
|
474
492
|
findings,
|
|
475
493
|
metadata: {
|
|
476
494
|
totalFiles: project.getSourceFiles().length,
|
|
477
|
-
timestamp:
|
|
495
|
+
timestamp: formatLocalTimestamp(),
|
|
478
496
|
root,
|
|
479
497
|
stagingOnlyMode: !!(context && context.stagingOnlyMode),
|
|
480
498
|
stagedFiles: Array.isArray(context && context.stagedFiles) ? context.stagedFiles : [],
|
|
@@ -503,12 +521,8 @@ function updateAIEvidenceMetrics(findings, levelTotals, root) {
|
|
|
503
521
|
try {
|
|
504
522
|
const evidence = JSON.parse(fs.readFileSync(evidencePath, 'utf8'));
|
|
505
523
|
|
|
506
|
-
const now = new Date().toISOString();
|
|
507
|
-
|
|
508
|
-
evidence.timestamp = now;
|
|
509
|
-
|
|
510
524
|
evidence.severity_metrics = {
|
|
511
|
-
last_updated:
|
|
525
|
+
last_updated: formatLocalTimestamp(),
|
|
512
526
|
total_violations: findings.length,
|
|
513
527
|
by_severity: {
|
|
514
528
|
CRITICAL: levelTotals.CRITICAL || 0,
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { spawn } = require('child_process');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
|
|
7
|
+
const REFRESH_INTERVAL_MS = 180000;
|
|
8
|
+
const EVIDENCE_FILE = '.AI_EVIDENCE.json';
|
|
9
|
+
const PID_FILE = '.evidence-guard.pid';
|
|
10
|
+
|
|
11
|
+
class EvidenceGuard {
|
|
12
|
+
constructor() {
|
|
13
|
+
this.projectRoot = this.findProjectRoot();
|
|
14
|
+
this.pidFile = path.join(this.projectRoot, PID_FILE);
|
|
15
|
+
this.evidenceFile = path.join(this.projectRoot, EVIDENCE_FILE);
|
|
16
|
+
this.updateScript = this.findUpdateScript();
|
|
17
|
+
this.isRunning = false;
|
|
18
|
+
this.intervalId = null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
findProjectRoot() {
|
|
22
|
+
let currentDir = process.cwd();
|
|
23
|
+
while (currentDir !== '/') {
|
|
24
|
+
if (fs.existsSync(path.join(currentDir, 'package.json'))) {
|
|
25
|
+
return currentDir;
|
|
26
|
+
}
|
|
27
|
+
currentDir = path.dirname(currentDir);
|
|
28
|
+
}
|
|
29
|
+
return process.cwd();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
findUpdateScript() {
|
|
33
|
+
const possiblePaths = [
|
|
34
|
+
path.join(this.projectRoot, 'scripts/hooks-system/bin/update-evidence.sh'),
|
|
35
|
+
path.join(this.projectRoot, 'node_modules/pumuki-ast-hooks/scripts/hooks-system/bin/update-evidence.sh'),
|
|
36
|
+
path.join(__dirname, '../../bin/update-evidence.sh')
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
for (const scriptPath of possiblePaths) {
|
|
40
|
+
if (fs.existsSync(scriptPath)) {
|
|
41
|
+
return scriptPath;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
throw new Error('update-evidence.sh not found');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
writePidFile() {
|
|
49
|
+
try {
|
|
50
|
+
fs.writeFileSync(this.pidFile, process.pid.toString(), 'utf8');
|
|
51
|
+
} catch (error) {
|
|
52
|
+
console.error('[EvidenceGuard] Failed to write PID file:', error.message);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
removePidFile() {
|
|
57
|
+
try {
|
|
58
|
+
if (fs.existsSync(this.pidFile)) {
|
|
59
|
+
fs.unlinkSync(this.pidFile);
|
|
60
|
+
}
|
|
61
|
+
} catch (error) {
|
|
62
|
+
console.error('[EvidenceGuard] Failed to remove PID file:', error.message);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
isAlreadyRunning() {
|
|
67
|
+
if (!fs.existsSync(this.pidFile)) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
const pid = parseInt(fs.readFileSync(this.pidFile, 'utf8').trim(), 10);
|
|
73
|
+
process.kill(pid, 0);
|
|
74
|
+
return true;
|
|
75
|
+
} catch (error) {
|
|
76
|
+
this.removePidFile();
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async refreshEvidence() {
|
|
82
|
+
return new Promise((resolve) => {
|
|
83
|
+
const child = spawn('bash', [this.updateScript, '--auto'], {
|
|
84
|
+
cwd: this.projectRoot,
|
|
85
|
+
stdio: 'ignore',
|
|
86
|
+
detached: false
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
child.on('close', (code) => {
|
|
90
|
+
if (code === 0) {
|
|
91
|
+
console.log(`[EvidenceGuard] Evidence refreshed at ${new Date().toISOString()}`);
|
|
92
|
+
} else {
|
|
93
|
+
console.error(`[EvidenceGuard] Refresh failed with code ${code}`);
|
|
94
|
+
}
|
|
95
|
+
resolve();
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
child.on('error', (error) => {
|
|
99
|
+
console.error('[EvidenceGuard] Refresh error:', error.message);
|
|
100
|
+
resolve();
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async start() {
|
|
106
|
+
if (this.isAlreadyRunning()) {
|
|
107
|
+
console.log('[EvidenceGuard] Already running');
|
|
108
|
+
process.exit(0);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
this.writePidFile();
|
|
112
|
+
this.isRunning = true;
|
|
113
|
+
|
|
114
|
+
console.log('[EvidenceGuard] Started');
|
|
115
|
+
console.log(`[EvidenceGuard] Project root: ${this.projectRoot}`);
|
|
116
|
+
console.log(`[EvidenceGuard] Refresh interval: ${REFRESH_INTERVAL_MS / 1000}s`);
|
|
117
|
+
|
|
118
|
+
await this.refreshEvidence();
|
|
119
|
+
|
|
120
|
+
this.intervalId = setInterval(async () => {
|
|
121
|
+
if (this.isRunning) {
|
|
122
|
+
await this.refreshEvidence();
|
|
123
|
+
}
|
|
124
|
+
}, REFRESH_INTERVAL_MS);
|
|
125
|
+
|
|
126
|
+
process.on('SIGTERM', () => this.stop());
|
|
127
|
+
process.on('SIGINT', () => this.stop());
|
|
128
|
+
process.on('exit', () => this.cleanup());
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
stop() {
|
|
132
|
+
console.log('[EvidenceGuard] Stopping...');
|
|
133
|
+
this.isRunning = false;
|
|
134
|
+
if (this.intervalId) {
|
|
135
|
+
clearInterval(this.intervalId);
|
|
136
|
+
this.intervalId = null;
|
|
137
|
+
}
|
|
138
|
+
this.cleanup();
|
|
139
|
+
process.exit(0);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
cleanup() {
|
|
143
|
+
this.removePidFile();
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (require.main === module) {
|
|
148
|
+
const guard = new EvidenceGuard();
|
|
149
|
+
guard.start().catch((error) => {
|
|
150
|
+
console.error('[EvidenceGuard] Fatal error:', error);
|
|
151
|
+
process.exit(1);
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
module.exports = EvidenceGuard;
|
|
@@ -761,8 +761,6 @@ async function validateAndFix(params) {
|
|
|
761
761
|
const McpProtocolHandler = require('./services/McpProtocolHandler');
|
|
762
762
|
const protocolHandler = new McpProtocolHandler(process.stdin, process.stdout);
|
|
763
763
|
|
|
764
|
-
const SERVER_NAME = (process.env.MCP_SERVER_NAME || '').trim() || 'ast-intelligence-automation';
|
|
765
|
-
|
|
766
764
|
async function handleMcpMessage(message) {
|
|
767
765
|
try {
|
|
768
766
|
const request = JSON.parse(message);
|
|
@@ -790,7 +788,7 @@ async function handleMcpMessage(message) {
|
|
|
790
788
|
}
|
|
791
789
|
},
|
|
792
790
|
serverInfo: {
|
|
793
|
-
name:
|
|
791
|
+
name: 'ast-intelligence-automation',
|
|
794
792
|
version: '3.0.0',
|
|
795
793
|
description: 'Autonomous AST Intelligence + Git Flow Automation'
|
|
796
794
|
}
|
|
@@ -10,6 +10,24 @@ const { toErrorMessage } = require('../utils/error-utils');
|
|
|
10
10
|
const fs = require('fs');
|
|
11
11
|
const path = require('path');
|
|
12
12
|
|
|
13
|
+
function formatLocalTimestamp(date = new Date()) {
|
|
14
|
+
const year = date.getFullYear();
|
|
15
|
+
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
16
|
+
const day = String(date.getDate()).padStart(2, '0');
|
|
17
|
+
const hours = String(date.getHours()).padStart(2, '0');
|
|
18
|
+
const minutes = String(date.getMinutes()).padStart(2, '0');
|
|
19
|
+
const seconds = String(date.getSeconds()).padStart(2, '0');
|
|
20
|
+
const milliseconds = String(date.getMilliseconds()).padStart(3, '0');
|
|
21
|
+
|
|
22
|
+
const offsetMinutes = date.getTimezoneOffset();
|
|
23
|
+
const sign = offsetMinutes <= 0 ? '+' : '-';
|
|
24
|
+
const absolute = Math.abs(offsetMinutes);
|
|
25
|
+
const offsetHours = String(Math.floor(absolute / 60)).padStart(2, '0');
|
|
26
|
+
const offsetMins = String(absolute % 60).padStart(2, '0');
|
|
27
|
+
|
|
28
|
+
return `${year}-${month}-${day}T${hours}:${minutes}:${seconds}.${milliseconds}${sign}${offsetHours}:${offsetMins}`;
|
|
29
|
+
}
|
|
30
|
+
|
|
13
31
|
function resolveAuditTmpDir() {
|
|
14
32
|
const configured = (env.get('AUDIT_TMP', '') || '').trim();
|
|
15
33
|
if (configured.length > 0) {
|
|
@@ -147,7 +165,7 @@ function saveEnhancedViolations(violations) {
|
|
|
147
165
|
const outputPath = path.join(resolveAuditTmpDir(), 'ast-summary-enhanced.json');
|
|
148
166
|
|
|
149
167
|
const enhanced = {
|
|
150
|
-
timestamp:
|
|
168
|
+
timestamp: formatLocalTimestamp(),
|
|
151
169
|
generator: 'AST Intelligence v2.0 with Severity Evaluation',
|
|
152
170
|
intelligentEvaluation: true,
|
|
153
171
|
totalViolations: violations.length,
|
|
@@ -180,10 +198,8 @@ function updateAIEvidence(violations, gateResult, tokenUsage) {
|
|
|
180
198
|
try {
|
|
181
199
|
const evidence = JSON.parse(fs.readFileSync(evidencePath, 'utf8'));
|
|
182
200
|
|
|
183
|
-
evidence.timestamp = new Date().toISOString();
|
|
184
|
-
|
|
185
201
|
evidence.severity_metrics = {
|
|
186
|
-
last_updated:
|
|
202
|
+
last_updated: formatLocalTimestamp(),
|
|
187
203
|
total_violations: violations.length,
|
|
188
204
|
by_severity: {
|
|
189
205
|
CRITICAL: violations.filter(v => v.severity === 'CRITICAL').length,
|
|
@@ -255,7 +271,7 @@ function updateAIEvidence(violations, gateResult, tokenUsage) {
|
|
|
255
271
|
const nextGate = {
|
|
256
272
|
status: gateResult.passed ? 'ALLOWED' : 'BLOCKED',
|
|
257
273
|
scope: gateScope === 'repo' || gateScope === 'repository' ? 'repo' : 'staging',
|
|
258
|
-
last_check:
|
|
274
|
+
last_check: formatLocalTimestamp(),
|
|
259
275
|
violations: blockingViolations.map(v => ({
|
|
260
276
|
file: v.filePath || v.file || 'unknown',
|
|
261
277
|
line: v.line || null,
|
|
@@ -771,13 +771,6 @@ summarize_all() {
|
|
|
771
771
|
print_final_signature
|
|
772
772
|
exit 0
|
|
773
773
|
fi
|
|
774
|
-
|
|
775
|
-
local is_revert_in_progress=0
|
|
776
|
-
if [[ "${AST_ALLOW_REVERT:-1}" == "1" ]] && command -v git >/dev/null 2>&1; then
|
|
777
|
-
if git rev-parse -q --verify REVERT_HEAD >/dev/null 2>&1; then
|
|
778
|
-
is_revert_in_progress=1
|
|
779
|
-
fi
|
|
780
|
-
fi
|
|
781
774
|
local gate_crit gate_high gate_med gate_low gate_es
|
|
782
775
|
|
|
783
776
|
# Decide gate values based on mode
|
|
@@ -802,15 +795,6 @@ summarize_all() {
|
|
|
802
795
|
# Block on ANY violation (CRITICAL + HIGH + MEDIUM + LOW)
|
|
803
796
|
if (( gate_crit > 0 || gate_high > 0 || gate_med > 0 || gate_low > 0 || gate_es > 0 )); then
|
|
804
797
|
printf "\n"
|
|
805
|
-
if (( is_revert_in_progress == 1 )); then
|
|
806
|
-
printf "%b[REVERT MODE - COMMIT ALLOWED]%b\n" "$YELLOW" "$NC"
|
|
807
|
-
printf " Detected git revert in progress (REVERT_HEAD).\n"
|
|
808
|
-
printf " Skipping quality gate blocking for pre-existing violations.\n"
|
|
809
|
-
printf " Tip: set AST_ALLOW_REVERT=0 to enforce gates during revert.\n"
|
|
810
|
-
printf "\n"
|
|
811
|
-
print_final_signature
|
|
812
|
-
exit 0
|
|
813
|
-
fi
|
|
814
798
|
if [[ "${BLOCK_ON_REPO_VIOLATIONS:-0}" == "1" ]]; then
|
|
815
799
|
printf "%b[COMMIT BLOCKED - STRICT REPO+STAGING]%b\n" "$RED" "$NC"
|
|
816
800
|
printf " CRITICAL violations (repository): %s\n" "$gate_crit"
|
|
@@ -835,15 +819,6 @@ summarize_all() {
|
|
|
835
819
|
# Standard mode: Block only on CRITICAL/HIGH IN STAGING
|
|
836
820
|
if (( gate_crit > 0 || gate_high > 0 )); then
|
|
837
821
|
printf "\n"
|
|
838
|
-
if (( is_revert_in_progress == 1 )); then
|
|
839
|
-
printf "%b[REVERT MODE - COMMIT ALLOWED]%b\n" "$YELLOW" "$NC"
|
|
840
|
-
printf " Detected git revert in progress (REVERT_HEAD).\n"
|
|
841
|
-
printf " Skipping quality gate blocking for pre-existing violations.\n"
|
|
842
|
-
printf " Tip: set AST_ALLOW_REVERT=0 to enforce gates during revert.\n"
|
|
843
|
-
printf "\n"
|
|
844
|
-
print_final_signature
|
|
845
|
-
exit 0
|
|
846
|
-
fi
|
|
847
822
|
printf "%b[COMMIT BLOCKED - CRITICAL/HIGH]%b\n" "$RED" "$NC"
|
|
848
823
|
printf " CRITICAL violations in staging: %s\n" "$gate_crit"
|
|
849
824
|
printf " HIGH violations in staging: %s\n" "$gate_high"
|
|
@@ -11,7 +11,9 @@
|
|
|
11
11
|
# Get current timestamp in ISO 8601 with milliseconds
|
|
12
12
|
# Returns: 2025-11-06T10:45:23.123Z
|
|
13
13
|
get_current_timestamp() {
|
|
14
|
-
|
|
14
|
+
local raw
|
|
15
|
+
raw=$(date +"%Y-%m-%dT%H:%M:%S.000%z")
|
|
16
|
+
echo "$raw" | sed -E 's/([+-][0-9]{2})([0-9]{2})$/\1:\2/'
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
# Get current timestamp in epoch seconds
|
|
@@ -26,10 +28,16 @@ iso_to_epoch() {
|
|
|
26
28
|
local timestamp="$1"
|
|
27
29
|
|
|
28
30
|
# Strip milliseconds if present (2025-11-06T10:45:23.123Z → 2025-11-06T10:45:23Z)
|
|
29
|
-
local clean_ts
|
|
31
|
+
local clean_ts
|
|
32
|
+
clean_ts=$(echo "$timestamp" | sed -E 's/\.[0-9]+Z$/Z/')
|
|
30
33
|
|
|
31
|
-
|
|
32
|
-
|
|
34
|
+
if echo "$clean_ts" | grep -qE 'Z$'; then
|
|
35
|
+
TZ=UTC date -j -f "%Y-%m-%dT%H:%M:%SZ" "$clean_ts" +%s 2>/dev/null || echo "0"
|
|
36
|
+
return 0
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
clean_ts=$(echo "$timestamp" | sed -E 's/\.[0-9]+([+-][0-9]{2}):([0-9]{2})$/\1\2/' | sed -E 's/([+-][0-9]{2}):([0-9]{2})$/\1\2/')
|
|
40
|
+
date -j -f "%Y-%m-%dT%H:%M:%S%z" "$clean_ts" +%s 2>/dev/null || echo "0"
|
|
33
41
|
}
|
|
34
42
|
|
|
35
43
|
# Get age of timestamp in seconds
|
package/scripts/hooks-system/infrastructure/watchdog/__tests__/.audit-reports/token-monitor.log
CHANGED
|
@@ -37,3 +37,6 @@
|
|
|
37
37
|
{"timestamp":"2026-01-03T14:05:38.098Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"ok","percentUsed":10,"tokensUsed":100000,"maxTokens":1000000,"source":"realtime","stale":false},"context":{"message":"Result level=ok percent=10% used=100000/1000000 source=realtime"}}
|
|
38
38
|
{"timestamp":"2026-01-03T14:05:38.102Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"warning","percentUsed":91,"tokensUsed":910000,"maxTokens":1000000,"source":"fallback","stale":false},"context":{"message":"Result level=warning percent=91% used=910000/1000000 source=fallback"}}
|
|
39
39
|
{"timestamp":"2026-01-03T14:05:38.103Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"critical","percentUsed":98,"tokensUsed":980000,"maxTokens":1000000,"source":"realtime","stale":true},"context":{"message":"Result level=critical percent=98% used=980000/1000000 source=realtime (stale)"}}
|
|
40
|
+
{"timestamp":"2026-01-04T07:12:14.852Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"ok","percentUsed":10,"tokensUsed":100000,"maxTokens":1000000,"source":"realtime","stale":false},"context":{"message":"Result level=ok percent=10% used=100000/1000000 source=realtime"}}
|
|
41
|
+
{"timestamp":"2026-01-04T07:12:14.855Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"warning","percentUsed":91,"tokensUsed":910000,"maxTokens":1000000,"source":"fallback","stale":false},"context":{"message":"Result level=warning percent=91% used=910000/1000000 source=fallback"}}
|
|
42
|
+
{"timestamp":"2026-01-04T07:12:14.856Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"critical","percentUsed":98,"tokensUsed":980000,"maxTokens":1000000,"source":"realtime","stale":true},"context":{"message":"Result level=critical percent=98% used=980000/1000000 source=realtime (stale)"}}
|