(projectRoot)
| 646 | }).length; |
| 647 | } |
| 648 | |
| 649 | function readHookValue(projectRoot) { |
| 650 | const telemetryDir = path.join(projectRoot, '.planning', 'telemetry'); |
| 651 | const today = new Date().toISOString().slice(0, 10); |
| 652 | const errors = tailJsonl(path.join(telemetryDir, 'hook-errors.jsonl'), 200); |
| 653 | const timings = tailJsonl(path.join(telemetryDir, 'hook-timing.jsonl'), 200); |
| 654 | const audit = tailJsonl(path.join(telemetryDir, 'audit.jsonl'), 200); |
| 655 | |
| 656 | return { |
| 657 | circuitBreakerTrips: timings.filter((entry) => entry.hook === 'circuit-breaker' && entry.metric === 'trips').length + |
| 658 | audit.filter((entry) => /circuit[-_]breaker/i.test(String(entry.event || entry.hook || ''))).length, |
| 659 | qualityGateViolations: errors.filter((entry) => entry.hook === 'quality-gate').length + |
| 660 | timings.filter((entry) => entry.hook === 'quality-gate' && entry.metric === 'violations').length, |
| 661 | protectFileBlocks: errors.filter((entry) => entry.hook === 'protect-files').length, |
| 662 | externalGateActions: errors.filter((entry) => entry.hook === 'external-action-gate').length, |
| 663 | hookFiresToday: timings.filter((entry) => String(eventTimestamp(entry) || '').startsWith(today)).length, |
| 664 | }; |
| 665 | } |
| 666 | |
| 667 | function countHooksInConfig(config) { |
no test coverage detected