@@ -15,22 +15,6 @@ function severityEmoji(severity: string): string {
1515 return severity === "critical" ? ":rotating_light:" : ":warning:" ;
1616}
1717
18- function formatValue ( metric : string , value : number ) : string {
19- switch ( metric ) {
20- case "spend" :
21- case "cycle_spend" :
22- return `$${ ( value / 100 ) . toFixed ( 2 ) } ` ;
23- case "cost_per_req" :
24- return `$${ ( value / 100 ) . toFixed ( 2 ) } /req` ;
25- case "tokens" :
26- return `${ ( value / 1_000_000 ) . toFixed ( 2 ) } M` ;
27- case "requests" :
28- return `${ value . toFixed ( 0 ) } ` ;
29- default :
30- return `${ value } ` ;
31- }
32- }
33-
3418function buildAlertBlocks (
3519 anomaly : Anomaly ,
3620 incident : Incident ,
@@ -52,44 +36,14 @@ function buildAlertBlocks(
5236 text : `*${ anomaly . message } *` ,
5337 } ,
5438 } ,
55- {
56- type : "section" ,
57- fields : [
58- { type : "mrkdwn" , text : `*User:*\n${ anomaly . userEmail } ` } ,
59- { type : "mrkdwn" , text : `*Type:*\n${ anomaly . type } ` } ,
60- { type : "mrkdwn" , text : `*Metric:*\n${ anomaly . metric } ` } ,
61- {
62- type : "mrkdwn" ,
63- text : `*Value:*\n${ formatValue ( anomaly . metric , anomaly . value ) } ` ,
64- } ,
65- {
66- type : "mrkdwn" ,
67- text : `*Threshold:*\n${ formatValue ( anomaly . metric , anomaly . threshold ) } ` ,
68- } ,
69- {
70- type : "mrkdwn" ,
71- text : `*Incident:*\n#${ incident . id } ` ,
72- } ,
73- ] ,
74- } ,
7539 ] ;
7640
77- if ( anomaly . diagnosisModel ) {
78- blocks . push ( {
79- type : "section" ,
80- text : {
81- type : "mrkdwn" ,
82- text : `*Primary model:* \`${ anomaly . diagnosisModel } \`` ,
83- } ,
84- } ) ;
85- }
86-
8741 if ( dashboardUrl ) {
8842 blocks . push ( {
8943 type : "section" ,
9044 text : {
9145 type : "mrkdwn" ,
92- text : `<${ dashboardUrl } /users/${ encodeURIComponent ( anomaly . userEmail ) } |View user dashboard > · <${ dashboardUrl } /anomalies|View all anomalies>` ,
46+ text : `<${ dashboardUrl } /users/${ encodeURIComponent ( anomaly . userEmail ) } |View user details > · <${ dashboardUrl } /anomalies|All anomalies>` ,
9347 } ,
9448 } ) ;
9549 }
@@ -99,7 +53,7 @@ function buildAlertBlocks(
9953 elements : [
10054 {
10155 type : "mrkdwn" ,
102- text : `Detected at ${ anomaly . detectedAt } · cursor-usage-tracker` ,
56+ text : `Incident # ${ incident . id } · ${ anomaly . detectedAt } · cursor-usage-tracker` ,
10357 } ,
10458 ] ,
10559 } ) ;
@@ -225,13 +179,18 @@ export async function sendSlackAlert(
225179 }
226180
227181 const blocks = buildAlertBlocks ( anomaly , incident , options . dashboardUrl ) ;
228- const text = `${ severityEmoji ( anomaly . severity ) } ${ anomaly . message } — ${ anomaly . userEmail } ` ;
182+ const text = `${ severityEmoji ( anomaly . severity ) } ${ anomaly . message } ` ;
229183
230184 return postToSlack ( token , channel , text , blocks ) ;
231185}
232186
233187export async function sendPlanExhaustionAlert (
234- summary : { totalPlanExhausted : number ; totalActive : number } ,
188+ summary : {
189+ totalPlanExhausted : number ;
190+ totalActive : number ;
191+ newSinceLastAlert : number ;
192+ newUserNames : string ;
193+ } ,
235194 options : { dashboardUrl ?: string } = { } ,
236195) : Promise < boolean > {
237196 const token = process . env . SLACK_BOT_TOKEN ;
@@ -243,6 +202,8 @@ export async function sendPlanExhaustionAlert(
243202 return false ;
244203 }
245204
205+ const pct = Math . round ( ( summary . totalPlanExhausted / summary . totalActive ) * 100 ) ;
206+
246207 const blocks : SlackBlock [ ] = [
247208 {
248209 type : "header" ,
@@ -252,7 +213,14 @@ export async function sendPlanExhaustionAlert(
252213 type : "section" ,
253214 text : {
254215 type : "mrkdwn" ,
255- text : `*${ summary . totalPlanExhausted } /${ summary . totalActive } * active users have exceeded their included plan this cycle` ,
216+ text : `*${ summary . newSinceLastAlert } new users* exceeded their plan (${ summary . totalPlanExhausted } /${ summary . totalActive } total, ${ pct } %)` ,
217+ } ,
218+ } ,
219+ {
220+ type : "section" ,
221+ text : {
222+ type : "mrkdwn" ,
223+ text : `*New:* ${ summary . newUserNames } ` ,
256224 } ,
257225 } ,
258226 ] ;
@@ -274,7 +242,7 @@ export async function sendPlanExhaustionAlert(
274242 return postToSlack (
275243 token ,
276244 channel ,
277- `Cursor — ${ summary . totalPlanExhausted } users exceeded plan` ,
245+ `Cursor — ${ summary . newSinceLastAlert } new users exceeded plan ( ${ summary . totalPlanExhausted } total) ` ,
278246 blocks ,
279247 ) ;
280248}
0 commit comments