@cryptiklemur/lattice 1.6.0 → 1.8.0

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.
@@ -520,6 +520,216 @@ function aggregate(sessions: SessionData[], period: AnalyticsPeriod): AnalyticsP
520
520
 
521
521
  var tokenFlowSankey: AnalyticsPayload["tokenFlowSankey"] = { nodes: sankeyNodes, links: sankeyLinks };
522
522
 
523
+ var activityCalendarMap = new Map<string, { count: number; tokens: number; cost: number }>();
524
+ for (var aci = 0; aci < filtered.length; aci++) {
525
+ var acSess = filtered[aci];
526
+ var acDate = formatDate(acSess.endTime > 0 ? acSess.endTime : acSess.startTime);
527
+ var acEntry = activityCalendarMap.get(acDate);
528
+ if (!acEntry) {
529
+ acEntry = { count: 0, tokens: 0, cost: 0 };
530
+ activityCalendarMap.set(acDate, acEntry);
531
+ }
532
+ acEntry.count++;
533
+ acEntry.tokens += acSess.inputTokens + acSess.outputTokens;
534
+ acEntry.cost += acSess.cost;
535
+ }
536
+
537
+ var activityCalendar: AnalyticsPayload["activityCalendar"] = [];
538
+ if (dates.length > 0) {
539
+ var calStart = new Date(dates[0]);
540
+ var calEnd = new Date(dates[dates.length - 1]);
541
+ var calCursor = new Date(calStart);
542
+ while (calCursor <= calEnd) {
543
+ var calKey = formatDate(calCursor.getTime());
544
+ var calData = activityCalendarMap.get(calKey);
545
+ activityCalendar.push({
546
+ date: calKey,
547
+ count: calData ? calData.count : 0,
548
+ tokens: calData ? calData.tokens : 0,
549
+ cost: calData ? calData.cost : 0,
550
+ });
551
+ calCursor.setDate(calCursor.getDate() + 1);
552
+ }
553
+ }
554
+
555
+ var hourlyHeatmap: AnalyticsPayload["hourlyHeatmap"] = [];
556
+ var heatmapGrid = new Map<string, number>();
557
+ for (var hmi = 0; hmi < filtered.length; hmi++) {
558
+ var hmSess = filtered[hmi];
559
+ if (hmSess.startTime <= 0) continue;
560
+ var hmDate = new Date(hmSess.startTime);
561
+ var hmDay = hmDate.getDay();
562
+ var hmHour = hmDate.getHours();
563
+ var hmKey = hmDay + ":" + hmHour;
564
+ heatmapGrid.set(hmKey, (heatmapGrid.get(hmKey) || 0) + 1);
565
+ }
566
+ for (var hd = 0; hd < 7; hd++) {
567
+ for (var hh = 0; hh < 24; hh++) {
568
+ var hhKey = hd + ":" + hh;
569
+ hourlyHeatmap.push({ day: hd, hour: hh, count: heatmapGrid.get(hhKey) || 0 });
570
+ }
571
+ }
572
+
573
+ var sessionTimeline: AnalyticsPayload["sessionTimeline"] = [];
574
+ var tlSorted = filtered
575
+ .filter(function (s) { return s.startTime > 0 && s.endTime > 0; })
576
+ .sort(function (a, b) { return b.startTime - a.startTime; });
577
+ var tlCap = Math.min(tlSorted.length, 50);
578
+ for (var tli = 0; tli < tlCap; tli++) {
579
+ var tlSess = tlSorted[tli];
580
+ sessionTimeline.push({
581
+ id: tlSess.id,
582
+ title: tlSess.title,
583
+ project: tlSess.project,
584
+ start: tlSess.startTime,
585
+ end: tlSess.endTime,
586
+ cost: tlSess.cost,
587
+ });
588
+ }
589
+
590
+ var dailySummaryMap = new Map<string, { sessions: number; cost: number; tokens: number; tools: Map<string, number>; models: Map<string, number> }>();
591
+ for (var dsi = 0; dsi < filtered.length; dsi++) {
592
+ var dsSess = filtered[dsi];
593
+ var dsDate = formatDate(dsSess.endTime > 0 ? dsSess.endTime : dsSess.startTime);
594
+ var dsEntry = dailySummaryMap.get(dsDate);
595
+ if (!dsEntry) {
596
+ dsEntry = { sessions: 0, cost: 0, tokens: 0, tools: new Map(), models: new Map() };
597
+ dailySummaryMap.set(dsDate, dsEntry);
598
+ }
599
+ dsEntry.sessions++;
600
+ dsEntry.cost += dsSess.cost;
601
+ dsEntry.tokens += dsSess.inputTokens + dsSess.outputTokens;
602
+ dsSess.tools.forEach(function (count, tool) {
603
+ dsEntry!.tools.set(tool, (dsEntry!.tools.get(tool) || 0) + count);
604
+ });
605
+ dsSess.models.forEach(function (val, key) {
606
+ dsEntry!.models.set(key, (dsEntry!.models.get(key) || 0) + val.cost);
607
+ });
608
+ }
609
+
610
+ var dailySummaries: AnalyticsPayload["dailySummaries"] = [];
611
+ var dsSortedDates = Array.from(dailySummaryMap.keys()).sort();
612
+ for (var dsdi = 0; dsdi < dsSortedDates.length; dsdi++) {
613
+ var dsd = dsSortedDates[dsdi];
614
+ var dsData = dailySummaryMap.get(dsd)!;
615
+ var topTool = "";
616
+ var topToolCount = 0;
617
+ dsData.tools.forEach(function (count, tool) {
618
+ if (count > topToolCount) {
619
+ topToolCount = count;
620
+ topTool = tool;
621
+ }
622
+ });
623
+ var modelMix: Record<string, number> = {};
624
+ var modelTotal = 0;
625
+ dsData.models.forEach(function (cost) { modelTotal += cost; });
626
+ if (modelTotal > 0) {
627
+ dsData.models.forEach(function (cost, model) {
628
+ modelMix[model] = Math.round((cost / modelTotal) * 100) / 100;
629
+ });
630
+ }
631
+ dailySummaries.push({
632
+ date: dsd,
633
+ sessions: dsData.sessions,
634
+ cost: dsData.cost,
635
+ tokens: dsData.tokens,
636
+ topTool: topTool,
637
+ modelMix: modelMix,
638
+ });
639
+ }
640
+
641
+ var toolTreemap: AnalyticsPayload["toolTreemap"] = [];
642
+ toolStats.forEach(function (val, key) {
643
+ toolTreemap.push({
644
+ name: key,
645
+ count: val.count,
646
+ avgCost: val.sessions > 0 ? val.totalCost / val.sessions : 0,
647
+ });
648
+ });
649
+ toolTreemap.sort(function (a, b) { return b.count - a.count; });
650
+
651
+ var toolCategoryMap: Record<string, string> = {
652
+ Read: "Read", Glob: "Read", Grep: "Read", LS: "Read",
653
+ Edit: "Write", Write: "Write", MultiEdit: "Write",
654
+ Bash: "Execute",
655
+ Agent: "AI", Skill: "AI",
656
+ };
657
+ var toolSunburst: AnalyticsPayload["toolSunburst"] = [];
658
+ toolStats.forEach(function (val, key) {
659
+ var category = toolCategoryMap[key] || "Other";
660
+ toolSunburst.push({ name: key, category: category, count: val.count });
661
+ });
662
+ toolSunburst.sort(function (a, b) { return b.count - a.count; });
663
+
664
+ var totalToolCalls = 0;
665
+ toolStats.forEach(function (val) { totalToolCalls += val.count; });
666
+ var permissionStats: AnalyticsPayload["permissionStats"] = {
667
+ allowed: totalToolCalls,
668
+ denied: 0,
669
+ alwaysAllowed: 0,
670
+ };
671
+
672
+ var projectRadarMap = new Map<string, { cost: number; sessions: number; totalDuration: number; durationCount: number; tools: Set<string>; totalTokens: number }>();
673
+ for (var pri = 0; pri < filtered.length; pri++) {
674
+ var prSess = filtered[pri];
675
+ var prEntry = projectRadarMap.get(prSess.project);
676
+ if (!prEntry) {
677
+ prEntry = { cost: 0, sessions: 0, totalDuration: 0, durationCount: 0, tools: new Set(), totalTokens: 0 };
678
+ projectRadarMap.set(prSess.project, prEntry);
679
+ }
680
+ prEntry.cost += prSess.cost;
681
+ prEntry.sessions++;
682
+ prEntry.totalTokens += prSess.inputTokens + prSess.outputTokens;
683
+ if (prSess.startTime > 0 && prSess.endTime > prSess.startTime) {
684
+ prEntry.totalDuration += prSess.endTime - prSess.startTime;
685
+ prEntry.durationCount++;
686
+ }
687
+ prSess.tools.forEach(function (_count, tool) { prEntry!.tools.add(tool); });
688
+ }
689
+ var projectRadar: AnalyticsPayload["projectRadar"] = [];
690
+ projectRadarMap.forEach(function (val, key) {
691
+ projectRadar.push({
692
+ project: key,
693
+ cost: val.cost,
694
+ sessions: val.sessions,
695
+ avgDuration: val.durationCount > 0 ? val.totalDuration / val.durationCount : 0,
696
+ toolDiversity: val.tools.size,
697
+ tokensPerSession: val.sessions > 0 ? val.totalTokens / val.sessions : 0,
698
+ });
699
+ });
700
+ projectRadar.sort(function (a, b) { return b.cost - a.cost; });
701
+ if (projectRadar.length > 5) projectRadar.length = 5;
702
+
703
+ var contextWindowSizesForComplexity: Record<string, number> = { opus: 200000, sonnet: 200000, haiku: 200000, other: 200000 };
704
+ var sessionComplexity: AnalyticsPayload["sessionComplexity"] = [];
705
+ for (var sci = 0; sci < filtered.length; sci++) {
706
+ var scSess = filtered[sci];
707
+ var scUniqueTools = scSess.tools.size;
708
+ var scMessages = scSess.contextMessages.length;
709
+ var scRunning = 0;
710
+ var scPrimaryModel = "other";
711
+ var scMaxTokens = 0;
712
+ scSess.models.forEach(function (val, key) {
713
+ if (val.tokens > scMaxTokens) { scMaxTokens = val.tokens; scPrimaryModel = key; }
714
+ });
715
+ var scWindowSize = contextWindowSizesForComplexity[scPrimaryModel] || 200000;
716
+ for (var scmi = 0; scmi < scSess.contextMessages.length; scmi++) {
717
+ scRunning += scSess.contextMessages[scmi].inputTokens;
718
+ }
719
+ var scContextPercent = Math.min((scRunning / scWindowSize) * 100, 100);
720
+ var scScore = (scMessages * 1) + (scUniqueTools * 5) + (scContextPercent * 0.5);
721
+ sessionComplexity.push({
722
+ id: scSess.id,
723
+ title: scSess.title,
724
+ score: Math.round(scScore * 10) / 10,
725
+ messages: scMessages,
726
+ tools: scUniqueTools,
727
+ contextPercent: Math.round(scContextPercent * 10) / 10,
728
+ });
729
+ }
730
+ sessionComplexity.sort(function (a, b) { return b.score - a.score; });
731
+ if (sessionComplexity.length > 20) sessionComplexity.length = 20;
732
+
523
733
  return {
524
734
  totalCost: totalCost,
525
735
  totalSessions: filtered.length,
@@ -545,6 +755,15 @@ function aggregate(sessions: SessionData[], period: AnalyticsPeriod): AnalyticsP
545
755
  responseTimeData: responseTimeData,
546
756
  contextUtilization: contextUtilization,
547
757
  tokenFlowSankey: tokenFlowSankey,
758
+ activityCalendar: activityCalendar,
759
+ hourlyHeatmap: hourlyHeatmap,
760
+ sessionTimeline: sessionTimeline,
761
+ dailySummaries: dailySummaries,
762
+ toolTreemap: toolTreemap,
763
+ toolSunburst: toolSunburst,
764
+ permissionStats: permissionStats,
765
+ projectRadar: projectRadar,
766
+ sessionComplexity: sessionComplexity,
548
767
  };
549
768
  }
550
769
 
@@ -22,6 +22,17 @@ export interface AnalyticsPayload {
22
22
  responseTimeData: Array<{ tokens: number; duration: number; model: string; sessionId: string }>;
23
23
  contextUtilization: Array<{ messageIndex: number; contextPercent: number; sessionId: string; title: string }>;
24
24
  tokenFlowSankey: { nodes: Array<{ name: string }>; links: Array<{ source: number; target: number; value: number }> };
25
+
26
+ activityCalendar: Array<{ date: string; count: number; tokens: number; cost: number }>;
27
+ hourlyHeatmap: Array<{ day: number; hour: number; count: number }>;
28
+ sessionTimeline: Array<{ id: string; title: string; project: string; start: number; end: number; cost: number }>;
29
+ dailySummaries: Array<{ date: string; sessions: number; cost: number; tokens: number; topTool: string; modelMix: Record<string, number> }>;
30
+
31
+ toolTreemap: Array<{ name: string; count: number; avgCost: number }>;
32
+ toolSunburst: Array<{ name: string; category: string; count: number }>;
33
+ permissionStats: { allowed: number; denied: number; alwaysAllowed: number };
34
+ projectRadar: Array<{ project: string; cost: number; sessions: number; avgDuration: number; toolDiversity: number; tokensPerSession: number }>;
35
+ sessionComplexity: Array<{ id: string; title: string; score: number; messages: number; tools: number; contextPercent: number }>;
25
36
  }
26
37
 
27
38
  export type AnalyticsPeriod = "24h" | "7d" | "30d" | "90d" | "all";