pumuki-ast-hooks 5.3.17 → 5.3.19

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.
@@ -10,7 +10,7 @@
10
10
  ---
11
11
 
12
12
  ## 📊 Resumen Ejecutivo
13
- - **Estado actual:** ⚠️ Acción requerida (217 críticas, 1 alta, 117 medias, 211 bajas)
13
+ - **Estado actual:** ⚠️ Acción requerida (91 críticas, 0 altas, 30 medias, 14 bajas)
14
14
  - **Branch:** `fix/audit-staged-severity-case-insensitive`
15
15
  - **Fecha de inicio:** 30/12/2025 — **ETA general:** 15/01/2026
16
16
  - **Objetivo:** Reducir a 0 las CRÍTICAS/HIGH y bajar el total < 20 antes de permitir commits sin bypass.
@@ -35,7 +35,7 @@ gantt
35
35
  Auditoría de seguridad : crit3, after crit2, 3d
36
36
  Métricas Prometheus : crit4, after crit3, 2d
37
37
  Patrones de confiabilidad : crit5, after crit4, 2d
38
-
38
+
39
39
  section Fase 2: HIGH + MEDIUM
40
40
  Corrección HIGH : high1, after crit5, 1d
41
41
  Refactorización MEDIUM : med1, after high1, 5d
@@ -46,50 +46,48 @@ gantt
46
46
 
47
47
  ---
48
48
 
49
- ## 🔴 Fase 1: Violaciones CRÍTICAS (217)
49
+ ## 🔴 Fase 1: Violaciones CRÍTICAS (91)
50
50
  | Estado | Violación | Cant. | Responsable | DOD (Definition of Done) | Doc |
51
51
  |--------|-----------|-------|-------------|--------------------------|-----|
52
- | | backend.error.custom_exceptions | 105 | BE | CustomError base + reemplazo de `Error` genérico en BE; tests pasando | [Guía de excepciones](../docs/error-handling.md) |
53
- | 🚧 | backend.config.missing_env_separation | 80 | BE | Config por entorno (dev/stg/prod), sin secretos hardcode | [Config entornos](../docs/env-configuration.md) |
54
- | ⏳ | backend.security.missing_audit_logging | 69 | BE | Audit trail en operaciones sensibles + logs estructurados | [Audit logging](../docs/security-auditing.md) |
55
- | ⏳ | backend.metrics.missing_prometheus | 64 | BE | Endpoints /metrics, instrumentación clave y dashboard base | [Prometheus](../docs/metrics-monitoring.md) |
56
- | ⏳ | backend.reliability.missing_bulkhead | 40 | BE | Limitadores/aislamiento en puntos críticos + pruebas de carga | [Reliability](../docs/reliability-patterns.md) |
52
+ | 🚧 | backend.observability.missing_prometheus | 45 | BE | Añadir métricas Prometheus a todos los servicios críticos; endpoints /metrics funcionando | [Prometheus](../docs/metrics-monitoring.md) |
53
+ | | backend.config.missing_env_separation | 27 | BE | Config por entorno (dev/stg/prod), sin secretos hardcode | [Config entornos](../docs/env-configuration.md) |
54
+ | ⏳ | backend.security.missing_audit_logging | 23 | BE | Audit trail en operaciones sensibles + logs estructurados | [Audit logging](../docs/security-auditing.md) |
55
+ | ⏳ | backend.error.custom_exceptions | 16 | BE | CustomError base + reemplazo de `Error` genérico en BE; tests pasando | [Guía de excepciones](../docs/error-handling.md) |
56
+ | ⏳ | backend.reliability.missing_bulkhead | 10 | BE | Limitadores/aislamiento en puntos críticos + pruebas de carga | [Reliability](../docs/reliability-patterns.md) |
57
+ | ⏳ | backend.event.emitter | 4 | BE | try/catch en manejadores de eventos; manejo de errores robusto | [Eventos](../docs/event-handling.md) |
58
+ | ⏳ | backend.observability.missing_alerting | 3 | SRE | Alertas en métricas críticas; umbrales definidos | [Alerting](../docs/alerting-system.md) |
59
+ | ⏳ | backend.config.missing_validation | 1 | BE | Validación de configuración al inicio | [Config validation](../docs/config-validation.md) |
60
+ | ⏳ | backend.config.missing_env_validation | 1 | BE | Validación de variables de entorno requeridas | [Env validation](../docs/env-validation.md) |
61
+ | ⏳ | backend.database.raw_sql | 1 | BE | Uso de ORM en lugar de raw SQL | [Database](../docs/database-layer.md) |
57
62
 
58
63
  ---
59
64
 
60
- ## 🟠 Fase 2: Violaciones HIGH + MEDIUM (118)
65
+ ## 🟠 Fase 2: Violaciones HIGH + MEDIUM (30)
61
66
  | Estado | Violación | Cant. | Responsable | DOD | Doc |
62
67
  |--------|-----------|-------|-------------|-----|-----|
63
- | | HIGH (1) | 1 | BE | Tipado estricto sin `any`; tests verdes | [Type safety](../docs/type-safety.md) |
64
- | ⏳ | backend.testing.mocks | 40 | QA/BE | Mocks revisados; cobertura > 80% en módulos afectados | [Testing](../docs/testing-strategies.md) |
65
- | ⏳ | backend.event.handler | 26 | BE | Handlers idempotentes + tests de eventos | [Eventos](../docs/event-handling.md) |
66
- | ⏳ | backend.observability.missing_prometheus | 24 | BE | Métricas por handler; dashboards mínimos | [Observabilidad](../docs/observability.md) |
67
- | ⏳ | backend.auth.missing_cors | 17 | BE | Política CORS por entorno; tests e2e básicos | [CORS](../docs/cors-configuration.md) |
68
- | ⏳ | backend.observability.missing_alerting | 10 | SRE | Alertas en métricas críticas; umbrales definidos | [Alerting](../docs/alerting-system.md) |
68
+ | | HIGH | 0 | BE | No aplica (repo JS puro sin TS); se documenta enfoque de seguridad de tipos | [Type safety](../docs/type-safety.md) |
69
+ | ⏳ | MEDIUM | 30 | BE | Resolver violaciones de complejidad media restantes | [Medium violations](../docs/medium-violations.md) |
69
70
 
70
71
  ---
71
72
 
72
- ## 🔵 Fase 3: Violaciones LOW (211)
73
+ ## 🔵 Fase 3: Violaciones LOW (14)
73
74
  | Estado | Violación | Cant. | Responsable | DOD | Doc |
74
75
  |--------|-----------|-------|-------------|-----|-----|
75
- | ⏳ | frontend.code_quality.comment | 4 | FE | Comentarios depurados; lint OK | [Code standards](../docs/code-standards.md) |
76
- | ⏳ | frontend.code_quality.magic_number | 4 | FE | Constantes declaradas; tests ajustados | [Constantes](../docs/constants-vs-magic-numbers.md) |
77
- | ⏳ | frontend.devops.hardcoded_feature_flag | 2 | FE/DevOps | Flags externalizados por entorno | [Feature flags](../docs/feature-flags.md) |
78
- | ⏳ | frontend.performance.code_splitting | 2 | FE | Split aplicado en rutas pesadas; bundle size reducido | [Perf FE](../docs/frontend-performance.md) |
79
- | ⏳ | frontend.performance.missing_code_splitting | 2 | FE | Lazy loading habilitado en vistas grandes | [Code splitting](../docs/code-splitting.md) |
76
+ | ⏳ | LOW | 14 | BE/FE | Resolver violaciones de baja prioridad restantes | [Low violations](../docs/low-violations.md) |
80
77
 
81
78
  ---
82
79
 
83
80
  ## 📈 Métricas de Progreso
84
81
  | Fase | Total | Completado | % |
85
82
  |------|-------|------------|---|
86
- | CRÍTICAS | 217 | 0 | 0% |
87
- | HIGH + MEDIUM | 118 | 0 | 0% |
88
- | LOW | 211 | 0 | 0% |
89
- | **TOTAL** | **546** | **0** | **0%** |
83
+ | CRÍTICAS | 91 | 0 | 0% |
84
+ | HIGH + MEDIUM | 30 | 0 | 0% |
85
+ | LOW | 14 | 0 | 0% |
86
+ | **TOTAL** | **135** | **0** | **0%** |
90
87
 
91
88
  **Riesgos actualizados:**
92
89
  1) Implementación de Prometheus podría requerir cambios de infra; 2) Revisión de seguridad depende de disponibilidad de equipo; 3) Refactorizaciones pueden impactar tiempos.
93
90
 
94
91
  **Comentarios/Notas colaborativas:**
95
92
  - Añade comentarios bajo cada tabla al cerrar tareas (usa la leyenda para actualizar estados).
93
+ - Progreso en métricas Prometheus: añadidas a 27 servicios, pero 45 violaciones restantes indican necesidad de más instrumentación.
@@ -0,0 +1,51 @@
1
+ # Alerting system (hook-system)
2
+
3
+ This repo does not expose its own HTTP server; metrics are published via `/metrics` in `metrics-server.js`, reading `.audit_tmp/hook-metrics.jsonl`. Alerts rely on `recordMetric` events from critical services (guards, scheduler).
4
+
5
+ ## Key metrics
6
+ - `hook_events_total{hook="guard_auto_manager",status="lock_fail|start|stop"}`
7
+ - `hook_events_total{hook="realtime_guard",status="start|stop"}`
8
+ - `hook_events_total{hook="git_tree",status="dirty|clean"}`
9
+ - `hook_events_total{hook="token_monitor",status="start|fail"}`
10
+ - `hook_events_total{hook="gitflow_autosync",status="enabled|sync_success"}`
11
+ - `hook_events_total{hook="evidence",status="stale|auto_refresh_success"}`
12
+
13
+ ## Alert examples (Prometheus)
14
+ ```yaml
15
+ - alert: GuardLockFailure
16
+ expr: increase(hook_events_total{hook="guard_auto_manager",status="lock_fail"}[5m]) > 0
17
+ for: 5m
18
+ labels: { severity: critical }
19
+ annotations:
20
+ summary: "Guard auto manager could not acquire lock"
21
+ description: "Check duplicate instance or orphan PID file"
22
+
23
+ - alert: GitTreeDirtyPersistent
24
+ expr: increase(hook_events_total{hook="git_tree",status="dirty"}[15m]) >= 3
25
+ for: 0m
26
+ labels: { severity: warning }
27
+ annotations:
28
+ summary: "Repo dirty repeatedly"
29
+ description: "More than 3 dirty detections in 15m"
30
+
31
+ - alert: EvidenceStale
32
+ expr: increase(hook_events_total{hook="evidence",status="stale"}[30m]) > 0
33
+ for: 0m
34
+ labels: { severity: warning }
35
+ annotations:
36
+ summary: "Evidence is stale"
37
+ description: "Guard detected evidence outside SLA"
38
+
39
+ - alert: TokenMonitorFail
40
+ expr: increase(hook_events_total{hook="token_monitor",status="fail"}[10m]) > 0
41
+ for: 0m
42
+ labels: { severity: warning }
43
+ annotations:
44
+ summary: "Token monitor failed to start"
45
+ description: "Check script/token monitor availability"
46
+ ```
47
+
48
+ ## Operations
49
+ - Run `metrics-server.js` (port `HOOK_METRICS_PORT`, default 9464) to expose `/metrics`.
50
+ - Scrape Prometheus apuntando a `http://<host>:<port>/metrics`.
51
+ - Ajustar umbrales/ventanas según ruido y frecuencia de uso.
@@ -0,0 +1,36 @@
1
+ # Observability (Prometheus) - hook-system
2
+
3
+ The hook-system exposes plaintext metrics via `/metrics` (`infrastructure/telemetry/metrics-server.js`). Metrics are based on `hook_events_total` emitted by `recordMetric` from critical services (GuardAutoManager, RealtimeGuardService, HookSystemScheduler, etc.).
4
+
5
+ ## Exposure
6
+ - Run `metrics-server.js` (port `HOOK_METRICS_PORT`, default 9464).
7
+ - Data source: `.audit_tmp/hook-metrics.jsonl` (append-only).
8
+ - Endpoint: `http://<host>:<port>/metrics`.
9
+
10
+ ## Available metrics (main)
11
+ - `hook_events_total{hook="guard_auto_manager",status="lock_fail|start|stop"}`
12
+ - `hook_events_total{hook="realtime_guard",status="start|stop"}`
13
+ - `hook_events_total{hook="git_tree",status="dirty|clean"}`
14
+ - `hook_events_total{hook="token_monitor",status="start|fail"}`
15
+ - `hook_events_total{hook="gitflow_autosync",status="enabled|sync_success"}`
16
+ - `hook_events_total{hook="evidence",status="stale|auto_refresh_success"}`
17
+ - `hook_events_total{hook="autonomous-orchestrator",status="success|failure"}`
18
+
19
+ ## Prometheus scrape (example)
20
+ ```yaml
21
+ scrape_configs:
22
+ - job_name: 'hook-system'
23
+ metrics_path: /metrics
24
+ static_configs:
25
+ - targets: ['localhost:9464']
26
+ ```
27
+
28
+ ## Base dashboard (Grafana example)
29
+ - Panel 1: "Guard status" -> `increase(hook_events_total{hook="guard_auto_manager"}[5m])`
30
+ - Panel 2: "Git tree dirty" -> `increase(hook_events_total{hook="git_tree",status="dirty"}[15m])`
31
+ - Panel 3: "Evidence stale" -> `increase(hook_events_total{hook="evidence",status="stale"}[30m])`
32
+ - Panel 4: "Token monitor fails" -> `increase(hook_events_total{hook="token_monitor",status="fail"}[10m])`
33
+
34
+ ## Notes
35
+ - Adjust window sizes `[]` based on noise/usage.
36
+ - `.audit_tmp/hook-metrics.jsonl` can be rotated externally if it grows too much; `/metrics` recomputes from the current file.
@@ -0,0 +1,8 @@
1
+ # Type safety (hook-system)
2
+
3
+ The hook-system is 100% JavaScript (no TS build), so strict TypeScript “no-any” migration does not apply here. Type safety is enforced through:
4
+ - Unit/critical tests (guards, event bus, scheduler) and implicit contracts in services.
5
+ - Input validation in events (DomainEvent and derivatives) and defensive checks in services.
6
+ - No TS transpilation/bundle in this repo; CORS/AST analyses run on audited projects that may use TS.
7
+
8
+ For audited projects (outside this repo), use strict TS and avoid `any`; here we only document non-applicability.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pumuki-ast-hooks",
3
- "version": "5.3.17",
3
+ "version": "5.3.19",
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,4 +116,4 @@
116
116
  "./skills": "./skills/skill-rules.json",
117
117
  "./hooks": "./hooks/index.js"
118
118
  }
119
- }
119
+ }
@@ -12,5 +12,5 @@ Source: file
12
12
 
13
13
  ℹ️ Data is stale. Ensure guards are running and refreshing token usage.
14
14
 
15
- Last updated: 2025-12-30T08:25:20.984Z
15
+ Last updated: 2025-12-30T08:58:22.226Z
16
16
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
@@ -849,3 +849,14 @@
849
849
  {"timestamp":"2025-12-30T08:19:20.750Z","level":"debug","component":"NotificationCenter","event":"Notification enqueued","data":{"id":"aea6dbae-9f29-476f-aae0-eb0baed57b63","type":"token_ok"},"context":{}}
850
850
  {"timestamp":"2025-12-30T08:22:20.864Z","level":"debug","component":"NotificationCenter","event":"Notification enqueued","data":{"id":"9b5ff199-4e82-4c52-ac48-63c3f113bce8","type":"token_ok"},"context":{}}
851
851
  {"timestamp":"2025-12-30T08:25:20.986Z","level":"debug","component":"NotificationCenter","event":"Notification enqueued","data":{"id":"c997c7e1-df65-444b-9f83-256def74479f","type":"token_ok"},"context":{}}
852
+ {"timestamp":"2025-12-30T08:28:21.114Z","level":"debug","component":"NotificationCenter","event":"Notification enqueued","data":{"id":"c0ff8c81-b221-41e5-b794-47f531c4695c","type":"token_ok"},"context":{}}
853
+ {"timestamp":"2025-12-30T08:31:21.232Z","level":"debug","component":"NotificationCenter","event":"Notification enqueued","data":{"id":"f1fd65fe-8c97-4cf7-9e69-e78adcee7f6a","type":"token_ok"},"context":{}}
854
+ {"timestamp":"2025-12-30T08:34:21.331Z","level":"debug","component":"NotificationCenter","event":"Notification enqueued","data":{"id":"813aa1ac-d446-409a-9073-b8926977e1e3","type":"token_ok"},"context":{}}
855
+ {"timestamp":"2025-12-30T08:37:21.446Z","level":"debug","component":"NotificationCenter","event":"Notification enqueued","data":{"id":"3302369a-dfd0-412f-9371-0f42e2d38c43","type":"token_ok"},"context":{}}
856
+ {"timestamp":"2025-12-30T08:40:21.564Z","level":"debug","component":"NotificationCenter","event":"Notification enqueued","data":{"id":"99b37ef1-a097-4813-a549-f5397704155e","type":"token_ok"},"context":{}}
857
+ {"timestamp":"2025-12-30T08:43:21.675Z","level":"debug","component":"NotificationCenter","event":"Notification enqueued","data":{"id":"a4910417-b3c5-44cb-bbaf-17a058951161","type":"token_ok"},"context":{}}
858
+ {"timestamp":"2025-12-30T08:46:21.788Z","level":"debug","component":"NotificationCenter","event":"Notification enqueued","data":{"id":"d354de41-d835-44da-868f-0ee4b6f446b0","type":"token_ok"},"context":{}}
859
+ {"timestamp":"2025-12-30T08:49:21.901Z","level":"debug","component":"NotificationCenter","event":"Notification enqueued","data":{"id":"b8d841eb-439a-4ea8-b90f-25555315f26d","type":"token_ok"},"context":{}}
860
+ {"timestamp":"2025-12-30T08:52:22.017Z","level":"debug","component":"NotificationCenter","event":"Notification enqueued","data":{"id":"9c11c1b3-3816-4a02-b776-7298606a33f1","type":"token_ok"},"context":{}}
861
+ {"timestamp":"2025-12-30T08:55:22.116Z","level":"debug","component":"NotificationCenter","event":"Notification enqueued","data":{"id":"5440bbb5-a069-4be6-a84f-1a8e525e2ebe","type":"token_ok"},"context":{}}
862
+ {"timestamp":"2025-12-30T08:58:22.227Z","level":"debug","component":"NotificationCenter","event":"Notification enqueued","data":{"id":"22a08362-af10-4d6d-8e4d-011afe460c7d","type":"token_ok"},"context":{}}
@@ -2551,3 +2551,75 @@
2551
2551
  {"timestamp":"2025-12-30T08:25:20.975Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2552
2552
  {"timestamp":"2025-12-30T08:25:20.976Z","level":"debug","component":"TokenMonitor","event":"TOKEN_MONITOR_METRICS","data":{"timestamp":"2025-12-29T15:38:11.174Z","tokensUsed":0,"maxTokens":1000000,"percentUsed":0,"remainingTokens":1000000,"level":"ok","source":"file","stale":true,"untrusted":false},"context":{}}
2553
2553
  {"timestamp":"2025-12-30T08:25:20.986Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"ok","percentUsed":0,"tokensUsed":0,"maxTokens":1000000,"source":"file","stale":true,"untrusted":false},"context":{"message":"Result level=ok percent=0% used=0/1000000 source=file (stale)"}}
2554
+ {"timestamp":"2025-12-30T08:28:21.102Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2555
+ {"timestamp":"2025-12-30T08:28:21.104Z","level":"debug","component":"TokenMonitor","event":"TOKEN_MONITOR_METRICS","data":{"timestamp":"2025-12-29T15:38:11.174Z","tokensUsed":0,"maxTokens":1000000,"percentUsed":0,"remainingTokens":1000000,"level":"ok","source":"file","stale":true,"untrusted":false},"context":{}}
2556
+ {"timestamp":"2025-12-30T08:28:21.114Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"ok","percentUsed":0,"tokensUsed":0,"maxTokens":1000000,"source":"file","stale":true,"untrusted":false},"context":{"message":"Result level=ok percent=0% used=0/1000000 source=file (stale)"}}
2557
+ {"timestamp":"2025-12-30T08:31:21.222Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2558
+ {"timestamp":"2025-12-30T08:31:21.223Z","level":"debug","component":"TokenMonitor","event":"TOKEN_MONITOR_METRICS","data":{"timestamp":"2025-12-29T15:38:11.174Z","tokensUsed":0,"maxTokens":1000000,"percentUsed":0,"remainingTokens":1000000,"level":"ok","source":"file","stale":true,"untrusted":false},"context":{}}
2559
+ {"timestamp":"2025-12-30T08:31:21.232Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"ok","percentUsed":0,"tokensUsed":0,"maxTokens":1000000,"source":"file","stale":true,"untrusted":false},"context":{"message":"Result level=ok percent=0% used=0/1000000 source=file (stale)"}}
2560
+ {"timestamp":"2025-12-30T08:34:21.319Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2561
+ {"timestamp":"2025-12-30T08:34:21.321Z","level":"debug","component":"TokenMonitor","event":"TOKEN_MONITOR_METRICS","data":{"timestamp":"2025-12-29T15:38:11.174Z","tokensUsed":0,"maxTokens":1000000,"percentUsed":0,"remainingTokens":1000000,"level":"ok","source":"file","stale":true,"untrusted":false},"context":{}}
2562
+ {"timestamp":"2025-12-30T08:34:21.331Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"ok","percentUsed":0,"tokensUsed":0,"maxTokens":1000000,"source":"file","stale":true,"untrusted":false},"context":{"message":"Result level=ok percent=0% used=0/1000000 source=file (stale)"}}
2563
+ {"timestamp":"2025-12-30T08:37:21.435Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2564
+ {"timestamp":"2025-12-30T08:37:21.437Z","level":"debug","component":"TokenMonitor","event":"TOKEN_MONITOR_METRICS","data":{"timestamp":"2025-12-29T15:38:11.174Z","tokensUsed":0,"maxTokens":1000000,"percentUsed":0,"remainingTokens":1000000,"level":"ok","source":"file","stale":true,"untrusted":false},"context":{}}
2565
+ {"timestamp":"2025-12-30T08:37:21.447Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"ok","percentUsed":0,"tokensUsed":0,"maxTokens":1000000,"source":"file","stale":true,"untrusted":false},"context":{"message":"Result level=ok percent=0% used=0/1000000 source=file (stale)"}}
2566
+ {"timestamp":"2025-12-30T08:40:21.554Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2567
+ {"timestamp":"2025-12-30T08:40:21.555Z","level":"debug","component":"TokenMonitor","event":"TOKEN_MONITOR_METRICS","data":{"timestamp":"2025-12-29T15:38:11.174Z","tokensUsed":0,"maxTokens":1000000,"percentUsed":0,"remainingTokens":1000000,"level":"ok","source":"file","stale":true,"untrusted":false},"context":{}}
2568
+ {"timestamp":"2025-12-30T08:40:21.564Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"ok","percentUsed":0,"tokensUsed":0,"maxTokens":1000000,"source":"file","stale":true,"untrusted":false},"context":{"message":"Result level=ok percent=0% used=0/1000000 source=file (stale)"}}
2569
+ {"timestamp":"2025-12-30T08:43:21.664Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2570
+ {"timestamp":"2025-12-30T08:43:21.665Z","level":"debug","component":"TokenMonitor","event":"TOKEN_MONITOR_METRICS","data":{"timestamp":"2025-12-29T15:38:11.174Z","tokensUsed":0,"maxTokens":1000000,"percentUsed":0,"remainingTokens":1000000,"level":"ok","source":"file","stale":true,"untrusted":false},"context":{}}
2571
+ {"timestamp":"2025-12-30T08:43:21.676Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"ok","percentUsed":0,"tokensUsed":0,"maxTokens":1000000,"source":"file","stale":true,"untrusted":false},"context":{"message":"Result level=ok percent=0% used=0/1000000 source=file (stale)"}}
2572
+ {"timestamp":"2025-12-30T08:46:21.778Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2573
+ {"timestamp":"2025-12-30T08:46:21.779Z","level":"debug","component":"TokenMonitor","event":"TOKEN_MONITOR_METRICS","data":{"timestamp":"2025-12-29T15:38:11.174Z","tokensUsed":0,"maxTokens":1000000,"percentUsed":0,"remainingTokens":1000000,"level":"ok","source":"file","stale":true,"untrusted":false},"context":{}}
2574
+ {"timestamp":"2025-12-30T08:46:21.788Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"ok","percentUsed":0,"tokensUsed":0,"maxTokens":1000000,"source":"file","stale":true,"untrusted":false},"context":{"message":"Result level=ok percent=0% used=0/1000000 source=file (stale)"}}
2575
+ {"timestamp":"2025-12-30T08:49:21.891Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2576
+ {"timestamp":"2025-12-30T08:49:21.892Z","level":"debug","component":"TokenMonitor","event":"TOKEN_MONITOR_METRICS","data":{"timestamp":"2025-12-29T15:38:11.174Z","tokensUsed":0,"maxTokens":1000000,"percentUsed":0,"remainingTokens":1000000,"level":"ok","source":"file","stale":true,"untrusted":false},"context":{}}
2577
+ {"timestamp":"2025-12-30T08:49:21.901Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"ok","percentUsed":0,"tokensUsed":0,"maxTokens":1000000,"source":"file","stale":true,"untrusted":false},"context":{"message":"Result level=ok percent=0% used=0/1000000 source=file (stale)"}}
2578
+ {"timestamp":"2025-12-30T08:52:22.006Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2579
+ {"timestamp":"2025-12-30T08:52:22.008Z","level":"debug","component":"TokenMonitor","event":"TOKEN_MONITOR_METRICS","data":{"timestamp":"2025-12-29T15:38:11.174Z","tokensUsed":0,"maxTokens":1000000,"percentUsed":0,"remainingTokens":1000000,"level":"ok","source":"file","stale":true,"untrusted":false},"context":{}}
2580
+ {"timestamp":"2025-12-30T08:52:22.017Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"ok","percentUsed":0,"tokensUsed":0,"maxTokens":1000000,"source":"file","stale":true,"untrusted":false},"context":{"message":"Result level=ok percent=0% used=0/1000000 source=file (stale)"}}
2581
+ {"timestamp":"2025-12-30T08:55:22.104Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2582
+ {"timestamp":"2025-12-30T08:55:22.106Z","level":"debug","component":"TokenMonitor","event":"TOKEN_MONITOR_METRICS","data":{"timestamp":"2025-12-29T15:38:11.174Z","tokensUsed":0,"maxTokens":1000000,"percentUsed":0,"remainingTokens":1000000,"level":"ok","source":"file","stale":true,"untrusted":false},"context":{}}
2583
+ {"timestamp":"2025-12-30T08:55:22.117Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"ok","percentUsed":0,"tokensUsed":0,"maxTokens":1000000,"source":"file","stale":true,"untrusted":false},"context":{"message":"Result level=ok percent=0% used=0/1000000 source=file (stale)"}}
2584
+ {"timestamp":"2025-12-30T08:58:22.216Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2585
+ {"timestamp":"2025-12-30T08:58:22.217Z","level":"debug","component":"TokenMonitor","event":"TOKEN_MONITOR_METRICS","data":{"timestamp":"2025-12-29T15:38:11.174Z","tokensUsed":0,"maxTokens":1000000,"percentUsed":0,"remainingTokens":1000000,"level":"ok","source":"file","stale":true,"untrusted":false},"context":{}}
2586
+ {"timestamp":"2025-12-30T08:58:22.227Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"ok","percentUsed":0,"tokensUsed":0,"maxTokens":1000000,"source":"file","stale":true,"untrusted":false},"context":{"message":"Result level=ok percent=0% used=0/1000000 source=file (stale)"}}
2587
+ {"timestamp":"2025-12-30T09:01:22.338Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2588
+ {"timestamp":"2025-12-30T09:04:22.455Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2589
+ {"timestamp":"2025-12-30T09:07:22.567Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2590
+ {"timestamp":"2025-12-30T09:10:22.674Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2591
+ {"timestamp":"2025-12-30T09:13:22.769Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2592
+ {"timestamp":"2025-12-30T09:16:22.893Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2593
+ {"timestamp":"2025-12-30T09:19:23.006Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2594
+ {"timestamp":"2025-12-30T09:22:23.112Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2595
+ {"timestamp":"2025-12-30T09:25:23.225Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2596
+ {"timestamp":"2025-12-30T09:28:23.340Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2597
+ {"timestamp":"2025-12-30T09:31:23.437Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2598
+ {"timestamp":"2025-12-30T09:34:23.547Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2599
+ {"timestamp":"2025-12-30T09:37:23.640Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2600
+ {"timestamp":"2025-12-30T09:40:23.752Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2601
+ {"timestamp":"2025-12-30T09:43:23.845Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2602
+ {"timestamp":"2025-12-30T09:46:23.937Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2603
+ {"timestamp":"2025-12-30T09:49:24.042Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2604
+ {"timestamp":"2025-12-30T09:52:24.136Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2605
+ {"timestamp":"2025-12-30T09:55:24.231Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2606
+ {"timestamp":"2025-12-30T09:58:24.330Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2607
+ {"timestamp":"2025-12-30T10:01:24.438Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2608
+ {"timestamp":"2025-12-30T10:04:24.542Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2609
+ {"timestamp":"2025-12-30T10:07:24.654Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2610
+ {"timestamp":"2025-12-30T10:10:24.769Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2611
+ {"timestamp":"2025-12-30T10:13:24.886Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2612
+ {"timestamp":"2025-12-30T10:16:24.995Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2613
+ {"timestamp":"2025-12-30T10:19:25.098Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2614
+ {"timestamp":"2025-12-30T10:22:25.205Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2615
+ {"timestamp":"2025-12-30T10:25:25.296Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2616
+ {"timestamp":"2025-12-30T10:28:25.400Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2617
+ {"timestamp":"2025-12-30T10:31:25.497Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2618
+ {"timestamp":"2025-12-30T10:34:25.602Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2619
+ {"timestamp":"2025-12-30T10:37:25.690Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2620
+ {"timestamp":"2025-12-30T10:40:25.786Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2621
+ {"timestamp":"2025-12-30T10:43:25.876Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2622
+ {"timestamp":"2025-12-30T10:46:25.978Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2623
+ {"timestamp":"2025-12-30T10:49:26.076Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2624
+ {"timestamp":"2025-12-30T10:52:26.168Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
2625
+ {"timestamp":"2025-12-30T10:55:26.256Z","level":"debug","component":"TokenMonitor","event":"CURSOR_SERVICE_USING_FILE","data":{"usage":{"tokensUsed":0,"maxTokens":1000000,"percentUsed":72.36585,"timestamp":"2025-12-29T15:38:11.174Z","source":"file","untrusted":false}},"context":{}}
@@ -1,16 +1,53 @@
1
1
  const { execSync } = require('child_process');
2
2
 
3
+ // Import recordMetric for prometheus metrics
4
+ const { recordMetric } = require('../../../infrastructure/telemetry/metrics-logger');
5
+
3
6
  const extractFilePath = line => {
7
+ recordMetric({
8
+ hook: 'git_tree_state',
9
+ operation: 'extract_file_path',
10
+ status: 'started',
11
+ lineLength: line ? line.length : 0
12
+ });
13
+
4
14
  if (!line) {
15
+ recordMetric({
16
+ hook: 'git_tree_state',
17
+ operation: 'extract_file_path',
18
+ status: 'success',
19
+ result: ''
20
+ });
5
21
  return '';
6
22
  }
7
23
  if (line.startsWith('??')) {
8
- return line.slice(3).trim();
24
+ const result = line.slice(3).trim();
25
+ recordMetric({
26
+ hook: 'git_tree_state',
27
+ operation: 'extract_file_path',
28
+ status: 'success',
29
+ resultLength: result.length
30
+ });
31
+ return result;
9
32
  }
10
- return line.length > 3 ? line.slice(3).trim() : line.trim();
33
+ const result = line.length > 3 ? line.slice(3).trim() : line.trim();
34
+ recordMetric({
35
+ hook: 'git_tree_state',
36
+ operation: 'extract_file_path',
37
+ status: 'success',
38
+ resultLength: result.length
39
+ });
40
+ return result;
11
41
  };
12
42
 
13
43
  const buildStateFromStatus = (statusOutput = '') => {
44
+ recordMetric({
45
+ hook: 'git_tree_state',
46
+ operation: 'build_state_from_status',
47
+ status: 'started',
48
+ statusOutputLength: statusOutput ? statusOutput.length : 0
49
+ });
50
+
14
51
  const lines = statusOutput
15
52
  .split('\n')
16
53
  .map(entry => entry.replace(/\r$/, ''))
@@ -44,24 +81,51 @@ const buildStateFromStatus = (statusOutput = '') => {
44
81
 
45
82
  const uniqueSet = new Set([...stagedSet, ...workingSet]);
46
83
 
47
- return {
84
+ const result = {
48
85
  stagedFiles: Array.from(stagedSet),
49
86
  workingFiles: Array.from(workingSet),
50
87
  stagedCount: stagedSet.size,
51
88
  workingCount: workingSet.size,
52
89
  uniqueCount: uniqueSet.size
53
90
  };
91
+
92
+ recordMetric({
93
+ hook: 'git_tree_state',
94
+ operation: 'build_state_from_status',
95
+ status: 'success',
96
+ stagedCount: stagedSet.size,
97
+ workingCount: workingSet.size,
98
+ uniqueCount: uniqueSet.size
99
+ });
100
+
101
+ return result;
54
102
  };
55
103
 
56
104
  const getGitTreeState = ({ repoRoot = process.cwd() } = {}) => {
105
+ recordMetric({
106
+ hook: 'git_tree_state',
107
+ operation: 'get_git_tree_state',
108
+ status: 'started',
109
+ repoRoot: repoRoot.substring(0, 100)
110
+ });
111
+
57
112
  try {
58
113
  const statusOutput = execSync('git status --porcelain', {
59
114
  cwd: repoRoot,
60
115
  encoding: 'utf8'
61
116
  });
62
- return buildStateFromStatus(statusOutput);
117
+ const result = buildStateFromStatus(statusOutput);
118
+ recordMetric({
119
+ hook: 'git_tree_state',
120
+ operation: 'get_git_tree_state',
121
+ status: 'success',
122
+ stagedCount: result.stagedCount,
123
+ workingCount: result.workingCount,
124
+ uniqueCount: result.uniqueCount
125
+ });
126
+ return result;
63
127
  } catch (error) {
64
- return {
128
+ const result = {
65
129
  stagedFiles: [],
66
130
  workingFiles: [],
67
131
  stagedCount: 0,
@@ -69,37 +133,92 @@ const getGitTreeState = ({ repoRoot = process.cwd() } = {}) => {
69
133
  uniqueCount: 0,
70
134
  error: error.message
71
135
  };
136
+ recordMetric({
137
+ hook: 'git_tree_state',
138
+ operation: 'get_git_tree_state',
139
+ status: 'failed',
140
+ error: error.message
141
+ });
142
+ return result;
72
143
  }
73
144
  };
74
145
 
75
146
  const isTreeBeyondLimit = (state, limits) => {
147
+ recordMetric({
148
+ hook: 'git_tree_state',
149
+ operation: 'is_tree_beyond_limit',
150
+ status: 'started',
151
+ hasState: !!state,
152
+ limitsType: typeof limits
153
+ });
154
+
76
155
  if (!state) {
156
+ recordMetric({
157
+ hook: 'git_tree_state',
158
+ operation: 'is_tree_beyond_limit',
159
+ status: 'success',
160
+ result: false
161
+ });
77
162
  return false;
78
163
  }
79
-
164
+
80
165
  if (typeof limits === 'number') {
81
166
  const limit = limits;
82
167
  if (!Number.isFinite(limit) || limit <= 0) {
168
+ recordMetric({
169
+ hook: 'git_tree_state',
170
+ operation: 'is_tree_beyond_limit',
171
+ status: 'success',
172
+ result: false
173
+ });
83
174
  return false;
84
175
  }
85
- return (
176
+ const result = (
86
177
  state.stagedCount > limit ||
87
178
  state.workingCount > limit ||
88
179
  state.uniqueCount > limit
89
180
  );
181
+ recordMetric({
182
+ hook: 'git_tree_state',
183
+ operation: 'is_tree_beyond_limit',
184
+ status: 'success',
185
+ result: result
186
+ });
187
+ return result;
90
188
  }
91
-
189
+
92
190
  const { stagedLimit = 10, unstagedLimit = 15, totalLimit = 20 } = limits || {};
93
-
191
+
94
192
  const stagedExceeded = Number.isFinite(stagedLimit) && stagedLimit > 0 && state.stagedCount > stagedLimit;
95
193
  const unstagedExceeded = Number.isFinite(unstagedLimit) && unstagedLimit > 0 && state.workingCount > unstagedLimit;
96
194
  const totalExceeded = Number.isFinite(totalLimit) && totalLimit > 0 && state.uniqueCount > totalLimit;
97
-
98
- return stagedExceeded || unstagedExceeded || totalExceeded;
195
+
196
+ const result = stagedExceeded || unstagedExceeded || totalExceeded;
197
+ recordMetric({
198
+ hook: 'git_tree_state',
199
+ operation: 'is_tree_beyond_limit',
200
+ status: 'success',
201
+ result: result
202
+ });
203
+ return result;
99
204
  };
100
205
 
101
206
  const summarizeTreeState = (state, limits) => {
207
+ recordMetric({
208
+ hook: 'git_tree_state',
209
+ operation: 'summarize_tree_state',
210
+ status: 'started',
211
+ hasState: !!state,
212
+ limitsType: typeof limits
213
+ });
214
+
102
215
  if (!state) {
216
+ recordMetric({
217
+ hook: 'git_tree_state',
218
+ operation: 'summarize_tree_state',
219
+ status: 'success',
220
+ result: 'no data'
221
+ });
103
222
  return 'no data';
104
223
  }
105
224
  const parts = [
@@ -107,7 +226,7 @@ const summarizeTreeState = (state, limits) => {
107
226
  `working ${state.workingCount}`,
108
227
  `unique ${state.uniqueCount}`
109
228
  ];
110
-
229
+
111
230
  if (typeof limits === 'number') {
112
231
  const limit = limits;
113
232
  if (Number.isFinite(limit) && limit > 0) {
@@ -129,7 +248,14 @@ const summarizeTreeState = (state, limits) => {
129
248
  parts.push(`(${limitParts.join(', ')})`);
130
249
  }
131
250
  }
132
- return parts.join(', ');
251
+ const result = parts.join(', ');
252
+ recordMetric({
253
+ hook: 'git_tree_state',
254
+ operation: 'summarize_tree_state',
255
+ status: 'success',
256
+ resultLength: result.length
257
+ });
258
+ return result;
133
259
  };
134
260
 
135
261
  module.exports = {