@@ -359,14 +359,31 @@ public struct KiroStatusProbe: Sendable {
359359 // Track which key patterns matched to detect format changes
360360 var matchedPercent = false
361361 var matchedCredits = false
362+ var matchedNewFormat = false
362363
363- // Parse plan name from "| KIRO FREE" or similar
364+ // Parse plan name from "| KIRO FREE" or similar (legacy format)
364365 var planName = " Kiro "
365366 if let planMatch = stripped. range ( of: #"\|\s*(KIRO\s+\w+)"# , options: . regularExpression) {
366367 let raw = String ( stripped [ planMatch] ) . replacingOccurrences ( of: " | " , with: " " )
367368 planName = raw. trimmingCharacters ( in: . whitespaces)
368369 }
369370
371+ // Parse plan name from "Plan: Q Developer Pro" (new format, kiro-cli 1.24+)
372+ if let newPlanMatch = stripped. range ( of: #"Plan:\s*(.+)"# , options: . regularExpression) {
373+ let line = String ( stripped [ newPlanMatch] )
374+ // Extract just the plan name, stopping at newline
375+ let planLine = line. replacingOccurrences ( of: " Plan: " , with: " " ) . trimmingCharacters ( in: . whitespaces)
376+ if let firstLine = planLine. split ( separator: " \n " ) . first {
377+ planName = String ( firstLine) . trimmingCharacters ( in: . whitespaces)
378+ matchedNewFormat = true
379+ }
380+ }
381+
382+ // Check if this is a managed/enterprise plan with no usage data
383+ let isManagedPlan = lowered. contains ( " managed by admin " )
384+ || lowered. contains ( " managed by organization " )
385+ || lowered. contains ( " enterprise " )
386+
370387 // Parse reset date from "resets on 01/01"
371388 var resetsAt : Date ?
372389 if let resetMatch = stripped. range ( of: #"resets on (\d{2}/\d{2})"# , options: . regularExpression) {
@@ -423,8 +440,25 @@ public struct KiroStatusProbe: Sendable {
423440 }
424441 }
425442
443+ // For managed/enterprise plans in new format, we may not have usage data
444+ // but we should still show the plan name without error
445+ if matchedNewFormat, isManagedPlan {
446+ // Managed plans don't expose credits; return snapshot with plan name only
447+ return KiroUsageSnapshot (
448+ planName: planName,
449+ creditsUsed: 0 ,
450+ creditsTotal: 0 ,
451+ creditsPercent: 0 ,
452+ bonusCreditsUsed: nil ,
453+ bonusCreditsTotal: nil ,
454+ bonusExpiryDays: nil ,
455+ resetsAt: nil ,
456+ updatedAt: Date ( ) )
457+ }
458+
426459 // Require at least one key pattern to match to avoid silent failures
427- if !matchedPercent, !matchedCredits {
460+ // Only bypass error for managed plans in new format (they don't expose usage data)
461+ if !matchedPercent, !matchedCredits, !( matchedNewFormat && isManagedPlan) {
428462 throw KiroStatusProbeError . parseError (
429463 " No recognizable usage patterns found. Kiro CLI output format may have changed. " )
430464 }
@@ -482,5 +516,7 @@ public struct KiroStatusProbe: Sendable {
482516 return stripped. contains ( " covered in plan " )
483517 || stripped. contains ( " resets on " )
484518 || stripped. contains ( " bonus credits " )
519+ || stripped. contains ( " plan: " )
520+ || stripped. contains ( " managed by admin " )
485521 }
486522}
0 commit comments