openclacky 1.2.5 → 1.2.7

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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +43 -0
  3. data/README.md +34 -0
  4. data/README_CN.md +34 -0
  5. data/lib/clacky/agent/cost_tracker.rb +24 -10
  6. data/lib/clacky/agent/llm_caller.rb +25 -3
  7. data/lib/clacky/agent/message_compressor.rb +2 -1
  8. data/lib/clacky/agent/message_compressor_helper.rb +6 -2
  9. data/lib/clacky/agent/session_serializer.rb +23 -4
  10. data/lib/clacky/agent/tool_executor.rb +14 -0
  11. data/lib/clacky/agent/tool_registry.rb +0 -7
  12. data/lib/clacky/agent.rb +43 -10
  13. data/lib/clacky/agent_config.rb +54 -6
  14. data/lib/clacky/billing/billing_store.rb +62 -4
  15. data/lib/clacky/brand_config.rb +5 -0
  16. data/lib/clacky/cli.rb +76 -24
  17. data/lib/clacky/client.rb +59 -4
  18. data/lib/clacky/default_parsers/wps_parser.rb +82 -0
  19. data/lib/clacky/default_skills/onboard/SKILL.md +2 -2
  20. data/lib/clacky/json_ui_controller.rb +5 -2
  21. data/lib/clacky/message_format/anthropic.rb +13 -3
  22. data/lib/clacky/message_format/bedrock.rb +2 -2
  23. data/lib/clacky/plain_ui_controller.rb +1 -1
  24. data/lib/clacky/platform_http_client.rb +28 -1
  25. data/lib/clacky/providers.rb +11 -29
  26. data/lib/clacky/server/channel/channel_manager.rb +148 -12
  27. data/lib/clacky/server/channel/channel_ui_controller.rb +4 -2
  28. data/lib/clacky/server/http_server.rb +133 -13
  29. data/lib/clacky/server/session_registry.rb +30 -4
  30. data/lib/clacky/server/web_ui_controller.rb +6 -3
  31. data/lib/clacky/tools/browser.rb +4 -13
  32. data/lib/clacky/tools/terminal.rb +23 -27
  33. data/lib/clacky/ui2/ui_controller.rb +1 -1
  34. data/lib/clacky/ui_interface.rb +1 -1
  35. data/lib/clacky/utils/file_processor.rb +3 -0
  36. data/lib/clacky/utils/parser_manager.rb +3 -0
  37. data/lib/clacky/version.rb +1 -1
  38. data/lib/clacky/web/app.css +659 -75
  39. data/lib/clacky/web/app.js +0 -1
  40. data/lib/clacky/web/billing.js +371 -99
  41. data/lib/clacky/web/i18n.js +48 -2
  42. data/lib/clacky/web/index.html +34 -1
  43. data/lib/clacky/web/sessions.js +213 -82
  44. data/lib/clacky/web/settings.js +59 -17
  45. data/lib/clacky/web/workspace.js +204 -0
  46. data/lib/clacky/web/ws-dispatcher.js +19 -3
  47. data/lib/clacky.rb +9 -3
  48. metadata +4 -5
  49. data/lib/clacky/tools/list_tasks.rb +0 -54
  50. data/lib/clacky/tools/redo_task.rb +0 -41
  51. data/lib/clacky/tools/undo_task.rb +0 -35
@@ -1514,7 +1514,106 @@ body {
1514
1514
  #btn-welcome-new:hover { background: var(--color-button-primary-hover); }
1515
1515
 
1516
1516
  /* ── Chat panel ──────────────────────────────────────────────────────────── */
1517
- #chat-panel { flex: 1; display: flex; flex-direction: column; overflow: hidden; position: relative; }
1517
+ #chat-panel { flex: 1; display: flex; flex-direction: row; overflow: hidden; position: relative; }
1518
+ #chat-main { flex: 1; display: flex; flex-direction: column; overflow: hidden; position: relative; min-width: 0; }
1519
+
1520
+ /* ── Workspace panel (right file browser) ───────────────────────────────── */
1521
+ #workspace-panel {
1522
+ width: 280px;
1523
+ flex-shrink: 0;
1524
+ display: flex;
1525
+ flex-direction: column;
1526
+ border-left: 1px solid var(--color-border-primary);
1527
+ background: var(--color-bg-primary);
1528
+ overflow: hidden;
1529
+ transition: width var(--transition-base);
1530
+ }
1531
+ #workspace-panel.collapsed { width: 0; border-left: none; }
1532
+ #workspace-header {
1533
+ display: flex;
1534
+ align-items: center;
1535
+ justify-content: space-between;
1536
+ height: 2.5rem;
1537
+ min-height: 2.5rem;
1538
+ padding: 0 0.5rem 0 0.75rem;
1539
+ border-bottom: 1px solid var(--color-border-primary);
1540
+ font-size: 0.8125rem;
1541
+ font-weight: 600;
1542
+ color: var(--color-text-primary);
1543
+ }
1544
+ .workspace-header-actions { display: flex; gap: 0.125rem; }
1545
+ .workspace-icon-btn {
1546
+ display: inline-flex;
1547
+ align-items: center;
1548
+ justify-content: center;
1549
+ width: 1.75rem;
1550
+ height: 1.75rem;
1551
+ border: none;
1552
+ background: transparent;
1553
+ color: var(--color-text-secondary);
1554
+ border-radius: var(--radius-sm);
1555
+ cursor: pointer;
1556
+ transition: background-color var(--transition-base), color var(--transition-base);
1557
+ }
1558
+ .workspace-icon-btn:hover { background: var(--color-bg-hover); color: var(--color-text-primary); }
1559
+ #workspace-tree {
1560
+ flex: 1;
1561
+ overflow-y: auto;
1562
+ padding: 0.375rem 0.25rem;
1563
+ font-size: 0.8125rem;
1564
+ }
1565
+ .wt-node { user-select: none; }
1566
+ .wt-row {
1567
+ display: flex;
1568
+ align-items: center;
1569
+ gap: 0.25rem;
1570
+ padding: 0.1875rem 0.375rem;
1571
+ border-radius: var(--radius-sm);
1572
+ cursor: pointer;
1573
+ color: var(--color-text-primary);
1574
+ white-space: nowrap;
1575
+ overflow: hidden;
1576
+ }
1577
+ .wt-row:hover { background: var(--color-bg-hover); }
1578
+ .wt-caret {
1579
+ display: inline-flex;
1580
+ width: 0.875rem;
1581
+ flex-shrink: 0;
1582
+ color: var(--color-text-secondary);
1583
+ transition: transform var(--transition-base);
1584
+ }
1585
+ .wt-caret.open { transform: rotate(90deg); }
1586
+ .wt-caret.leaf { visibility: hidden; }
1587
+ .wt-icon { display: inline-flex; flex-shrink: 0; color: var(--color-text-secondary); }
1588
+ .wt-name { overflow: hidden; text-overflow: ellipsis; }
1589
+ .wt-size { margin-left: auto; padding-left: 0.5rem; font-size: 0.6875rem; color: var(--color-text-tertiary, var(--color-text-secondary)); flex-shrink: 0; }
1590
+ .wt-children { margin-left: 0.75rem; }
1591
+ .wt-empty, .wt-loading, .wt-error {
1592
+ padding: 0.375rem 0.625rem;
1593
+ font-size: 0.75rem;
1594
+ color: var(--color-text-secondary);
1595
+ }
1596
+ .wt-error { color: var(--color-danger, #d23); }
1597
+
1598
+ /* Collapsed-state opener tab — floats at the right edge of the chat area */
1599
+ #btn-workspace-open {
1600
+ position: absolute;
1601
+ top: 0.5rem;
1602
+ right: 0.5rem;
1603
+ z-index: 8;
1604
+ display: inline-flex;
1605
+ align-items: center;
1606
+ justify-content: center;
1607
+ width: 2rem;
1608
+ height: 2rem;
1609
+ border: 1px solid var(--color-border-primary);
1610
+ background: var(--color-bg-secondary);
1611
+ color: var(--color-text-secondary);
1612
+ border-radius: var(--radius-sm);
1613
+ cursor: pointer;
1614
+ transition: background-color var(--transition-base), color var(--transition-base);
1615
+ }
1616
+ #btn-workspace-open:hover { background: var(--color-bg-hover); color: var(--color-text-primary); }
1518
1617
 
1519
1618
  /* Mobile-only floating back button — replaces the old in-header back button.
1520
1619
  Hidden on desktop; mobile media query enables it. Positioned absolutely so
@@ -1971,6 +2070,14 @@ body {
1971
2070
  opacity: 0.5;
1972
2071
  cursor: not-allowed;
1973
2072
  }
2073
+ .msg-error a {
2074
+ color: var(--color-error);
2075
+ font-weight: 600;
2076
+ text-decoration: underline;
2077
+ }
2078
+ .msg-error a:hover {
2079
+ opacity: 0.8;
2080
+ }
1974
2081
  .msg-success { color: var(--color-success); align-self: flex-start; font-size: 0.8125rem; }
1975
2082
  .tool-name { color: var(--color-warning); font-weight: 600; }
1976
2083
  .progress-msg { color: var(--color-accent-primary); font-size: 0.75rem; align-self: center; }
@@ -2551,6 +2658,99 @@ body {
2551
2658
  color: var(--color-accent-primary);
2552
2659
  }
2553
2660
 
2661
+ .sib-submodel-default-tag {
2662
+ margin-left: 0.5rem;
2663
+ font-size: 0.5625rem;
2664
+ padding: 1px 0.3125rem;
2665
+ border-radius: 3px;
2666
+ background: color-mix(in srgb, var(--color-text-secondary) 15%, transparent);
2667
+ color: var(--color-text-secondary);
2668
+ opacity: 0.8;
2669
+ }
2670
+
2671
+ .sib-submodel-toggle {
2672
+ margin-left: 0.375rem;
2673
+ width: 1.125rem;
2674
+ height: 1.125rem;
2675
+ padding: 0;
2676
+ border: none;
2677
+ border-radius: 4px;
2678
+ background: transparent;
2679
+ color: var(--color-text-secondary);
2680
+ cursor: pointer;
2681
+ display: inline-flex;
2682
+ align-items: center;
2683
+ justify-content: center;
2684
+ transition: background-color 0.15s ease, color 0.15s ease, transform 0.15s ease;
2685
+ }
2686
+ .sib-submodel-toggle:hover {
2687
+ background: color-mix(in srgb, var(--color-accent-primary) 15%, transparent);
2688
+ color: var(--color-accent-primary);
2689
+ }
2690
+ .sib-submodel-toggle[aria-expanded="true"] {
2691
+ background: color-mix(in srgb, var(--color-accent-primary) 18%, transparent);
2692
+ color: var(--color-accent-primary);
2693
+ }
2694
+ .sib-submodel-toggle[aria-expanded="true"] svg {
2695
+ transform: rotate(90deg);
2696
+ }
2697
+ .sib-submodel-toggle svg {
2698
+ transition: transform 0.18s ease;
2699
+ }
2700
+
2701
+ .sib-model-option.submodel-open {
2702
+ background: var(--color-bg-hover);
2703
+ }
2704
+
2705
+ .sib-submodel-panel {
2706
+ position: fixed;
2707
+ min-width: 11rem;
2708
+ max-width: 16rem;
2709
+ background: var(--color-bg-secondary);
2710
+ border: 1px solid var(--color-border-primary);
2711
+ border-radius: 8px;
2712
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
2713
+ z-index: 10000;
2714
+ max-height: 18.75rem;
2715
+ overflow-y: auto;
2716
+ padding: 0.25rem 0;
2717
+ }
2718
+ .sib-submodel-panel-header {
2719
+ padding: 0.375rem 0.875rem 0.4375rem;
2720
+ font-size: 0.625rem;
2721
+ text-transform: uppercase;
2722
+ letter-spacing: 0.06em;
2723
+ color: var(--color-text-secondary);
2724
+ border-bottom: 1px solid var(--color-border-primary);
2725
+ margin-bottom: 0.25rem;
2726
+ }
2727
+ .sib-submodel-row {
2728
+ padding: 0.5rem 0.875rem;
2729
+ font-size: 0.7rem;
2730
+ font-family: var(--font-mono, monospace);
2731
+ color: var(--color-text-primary);
2732
+ cursor: pointer;
2733
+ transition: background-color 0.15s ease;
2734
+ display: flex;
2735
+ align-items: center;
2736
+ justify-content: space-between;
2737
+ gap: 0.5rem;
2738
+ }
2739
+ .sib-submodel-row:hover {
2740
+ background: var(--color-bg-hover);
2741
+ color: var(--color-accent-primary);
2742
+ }
2743
+ .sib-submodel-row.current {
2744
+ background: var(--color-bg-hover);
2745
+ font-weight: 600;
2746
+ color: var(--color-accent-primary);
2747
+ }
2748
+ .sib-submodel-row-name {
2749
+ overflow: hidden;
2750
+ text-overflow: ellipsis;
2751
+ white-space: nowrap;
2752
+ }
2753
+
2554
2754
  /* ── Model switcher benchmark banner & latency column ──────────────────────
2555
2755
  The banner sits at the top of the dropdown with a subtle border so it
2556
2756
  visually separates from the scrollable model list below. The ⚡ button is
@@ -2638,6 +2838,15 @@ body {
2638
2838
  white-space: nowrap;
2639
2839
  max-width: 100%;
2640
2840
  }
2841
+ .sib-model-option .sib-model-name-override {
2842
+ font-size: 0.6875rem;
2843
+ color: var(--color-accent-primary);
2844
+ font-weight: 600;
2845
+ overflow: hidden;
2846
+ text-overflow: ellipsis;
2847
+ white-space: nowrap;
2848
+ max-width: 100%;
2849
+ }
2641
2850
  .sib-model-option .sib-model-right {
2642
2851
  display: inline-flex;
2643
2852
  align-items: center;
@@ -2704,7 +2913,7 @@ body {
2704
2913
  display: flex;
2705
2914
  flex-wrap: wrap;
2706
2915
  gap: 0.5rem;
2707
- padding: 0.5rem 1rem 0;
2916
+ padding: 0.5rem 1rem;
2708
2917
  }
2709
2918
  .img-preview-item {
2710
2919
  position: relative;
@@ -3691,6 +3900,33 @@ body {
3691
3900
  color: var(--color-error);
3692
3901
  background: color-mix(in srgb, var(--color-error) 8%, transparent);
3693
3902
  }
3903
+ a.btn-card-grid-action {
3904
+ text-decoration: none;
3905
+ }
3906
+ .model-card-grid-footer {
3907
+ display: flex;
3908
+ justify-content: flex-end;
3909
+ margin-top: 0.25rem;
3910
+ }
3911
+ .model-card-grid-link {
3912
+ display: inline-flex;
3913
+ align-items: center;
3914
+ gap: 0.25rem;
3915
+ font-size: 0.6875rem;
3916
+ color: var(--color-text-tertiary);
3917
+ text-decoration: none;
3918
+ padding: 0.125rem 0.25rem;
3919
+ border-radius: 4px;
3920
+ transition: color 0.15s;
3921
+ }
3922
+ .model-card-grid-link:hover {
3923
+ color: var(--color-accent-primary);
3924
+ text-decoration: underline;
3925
+ }
3926
+ .model-card-grid-link svg {
3927
+ opacity: 0.7;
3928
+ flex-shrink: 0;
3929
+ }
3694
3930
 
3695
3931
  /* ── Settings Toggle List ───────────────────────────────────────────────────── */
3696
3932
  .settings-toggle-list {
@@ -8494,148 +8730,496 @@ body.setup-mode[data-theme="dark"] {
8494
8730
  .billing-error {
8495
8731
  color: var(--color-error);
8496
8732
  }
8497
- .billing-header {
8733
+ /* ── Dashboard Layout ─────────────────────────────────────────────────── */
8734
+ .billing-dashboard {
8735
+ display: flex;
8736
+ flex-direction: column;
8737
+ gap: 1.25rem;
8738
+ }
8739
+ .billing-top-bar {
8498
8740
  display: flex;
8499
8741
  justify-content: space-between;
8500
8742
  align-items: center;
8501
- margin-bottom: 1.5rem;
8743
+ flex-wrap: wrap;
8744
+ gap: 1rem;
8502
8745
  }
8503
- .billing-header h2 {
8746
+ .billing-title-row {
8747
+ display: flex;
8748
+ align-items: baseline;
8749
+ gap: 0.75rem;
8750
+ }
8751
+ .billing-title-row h2 {
8504
8752
  font-size: 1.5rem;
8505
8753
  font-weight: 600;
8506
8754
  color: var(--color-text-primary);
8507
8755
  margin: 0;
8508
8756
  }
8509
- .billing-period-select {
8510
- padding: 0.5rem 1rem;
8757
+ .billing-subtitle {
8758
+ font-size: 0.875rem;
8759
+ color: var(--color-text-secondary);
8760
+ }
8761
+ .billing-controls {
8762
+ display: flex;
8763
+ align-items: center;
8764
+ gap: 0.75rem;
8765
+ flex-wrap: wrap;
8766
+ }
8767
+
8768
+ /* ── Period Button Group ─────────────────────────────────────────────── */
8769
+ .billing-period-group {
8770
+ display: flex;
8771
+ background: var(--color-bg-secondary);
8772
+ border: 1px solid var(--color-border-primary);
8773
+ border-radius: 8px;
8774
+ overflow: hidden;
8775
+ }
8776
+ .billing-period-btn {
8777
+ padding: 0.5rem 0.875rem;
8778
+ border: none;
8779
+ background: transparent;
8780
+ color: var(--color-text-secondary);
8781
+ font-size: 0.8125rem;
8782
+ cursor: pointer;
8783
+ transition: all 0.15s ease;
8784
+ }
8785
+ .billing-period-btn:not(:last-child) {
8786
+ border-right: 1px solid var(--color-border-primary);
8787
+ }
8788
+ .billing-period-btn:hover {
8789
+ background: var(--color-bg-tertiary);
8790
+ color: var(--color-text-primary);
8791
+ }
8792
+ .billing-period-btn.active {
8793
+ background: #6366f1;
8794
+ color: #ffffff;
8795
+ font-weight: 500;
8796
+ }
8797
+
8798
+ /* ── Model Filter ────────────────────────────────────────────────────── */
8799
+ .billing-model-filter {
8800
+ padding: 0.5rem 0.875rem;
8511
8801
  border: 1px solid var(--color-border-primary);
8512
8802
  border-radius: 8px;
8513
8803
  background: var(--color-bg-secondary);
8514
8804
  color: var(--color-text-primary);
8805
+ font-size: 0.8125rem;
8806
+ cursor: pointer;
8807
+ min-width: 140px;
8808
+ }
8809
+
8810
+ /* ── Clear Button ────────────────────────────────────────────────────── */
8811
+ .billing-clear-container {
8812
+ position: relative;
8813
+ }
8814
+ .billing-clear-btn {
8815
+ padding: 0.5rem 0.625rem;
8816
+ border: 1px solid var(--color-border-primary);
8817
+ border-radius: 8px;
8818
+ background: var(--color-bg-secondary);
8819
+ color: var(--color-text-secondary);
8515
8820
  font-size: 0.875rem;
8516
8821
  cursor: pointer;
8822
+ transition: all 0.2s ease;
8823
+ }
8824
+ .billing-clear-btn:hover {
8825
+ background: var(--color-bg-tertiary);
8826
+ color: var(--color-text-primary);
8827
+ border-color: var(--color-error);
8828
+ }
8829
+ .billing-clear-popup {
8830
+ position: absolute;
8831
+ top: 100%;
8832
+ right: 0;
8833
+ margin-top: 0.25rem;
8834
+ display: flex;
8835
+ flex-direction: column;
8836
+ gap: 0.25rem;
8837
+ background: var(--color-bg-secondary);
8838
+ border: 1px solid var(--color-border-primary);
8839
+ border-radius: 8px;
8840
+ padding: 0.5rem;
8841
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
8842
+ z-index: 100;
8843
+ min-width: 120px;
8517
8844
  }
8518
- .billing-summary-cards {
8845
+ .billing-clear-option {
8846
+ padding: 0.5rem 0.75rem;
8847
+ border: none;
8848
+ border-radius: 6px;
8849
+ background: transparent;
8850
+ color: var(--color-text-primary);
8851
+ font-size: 0.8125rem;
8852
+ cursor: pointer;
8853
+ text-align: left;
8854
+ white-space: nowrap;
8855
+ transition: background 0.15s ease;
8856
+ }
8857
+ .billing-clear-option:hover {
8858
+ background: var(--color-bg-tertiary);
8859
+ }
8860
+ .billing-clear-danger {
8861
+ color: var(--color-error);
8862
+ }
8863
+ .billing-clear-danger:hover {
8864
+ background: rgba(239, 68, 68, 0.1);
8865
+ }
8866
+
8867
+ /* ── Stats Row ───────────────────────────────────────────────────────── */
8868
+ .billing-stats-row {
8519
8869
  display: grid;
8520
- grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
8870
+ grid-template-columns: repeat(4, 1fr);
8521
8871
  gap: 1rem;
8522
- margin-bottom: 2rem;
8523
8872
  }
8524
- .billing-card {
8873
+ @media (max-width: 900px) {
8874
+ .billing-stats-row { grid-template-columns: repeat(2, 1fr); }
8875
+ }
8876
+ @media (max-width: 500px) {
8877
+ .billing-stats-row { grid-template-columns: 1fr; }
8878
+ }
8879
+ .billing-stat-card {
8880
+ display: flex;
8881
+ align-items: center;
8882
+ gap: 0.875rem;
8883
+ padding: 1rem 1.25rem;
8525
8884
  background: var(--color-bg-secondary);
8526
8885
  border: 1px solid var(--color-border-primary);
8527
8886
  border-radius: 12px;
8528
- padding: 1.25rem;
8529
- text-align: center;
8530
8887
  }
8531
- .billing-card-primary {
8532
- background: linear-gradient(135deg, var(--color-accent-bg) 0%, var(--color-bg-secondary) 100%);
8888
+ .billing-stat-primary {
8889
+ background: linear-gradient(135deg, var(--color-accent-bg, rgba(99,102,241,0.1)) 0%, var(--color-bg-secondary) 100%);
8533
8890
  border-color: var(--color-accent);
8534
8891
  }
8535
- .billing-card-label {
8892
+ .billing-stat-icon {
8893
+ font-size: 1.5rem;
8894
+ opacity: 0.8;
8895
+ }
8896
+ .billing-stat-content {
8897
+ display: flex;
8898
+ flex-direction: column;
8899
+ }
8900
+ .billing-stat-value {
8901
+ font-size: 1.25rem;
8902
+ font-weight: 700;
8903
+ color: var(--color-text-primary);
8904
+ line-height: 1.2;
8905
+ }
8906
+ .billing-stat-primary .billing-stat-value {
8907
+ color: var(--color-accent);
8908
+ }
8909
+ .billing-stat-label {
8536
8910
  font-size: 0.75rem;
8537
8911
  color: var(--color-text-secondary);
8538
8912
  text-transform: uppercase;
8539
- letter-spacing: 0.05em;
8913
+ letter-spacing: 0.03em;
8914
+ }
8915
+
8916
+ /* ── Chart Row (Single Line) ─────────────────────────────────────────── */
8917
+ .billing-chart-row {
8918
+ width: 100%;
8919
+ }
8920
+ .billing-chart-card {
8921
+ background: var(--color-bg-secondary);
8922
+ border: 1px solid var(--color-border-primary);
8923
+ border-radius: 12px;
8924
+ padding: 1.25rem;
8925
+ min-height: 180px;
8926
+ display: flex;
8927
+ flex-direction: column;
8928
+ }
8929
+ .billing-chart-wide {
8930
+ width: 100%;
8931
+ }
8932
+ .billing-chart-header {
8933
+ display: flex;
8934
+ justify-content: space-between;
8935
+ align-items: center;
8936
+ margin-bottom: 1rem;
8937
+ }
8938
+ .billing-chart-header h4 {
8939
+ font-size: 0.9375rem;
8940
+ font-weight: 600;
8941
+ color: var(--color-text-primary);
8942
+ margin: 0;
8943
+ }
8944
+ .billing-chart-legends {
8945
+ display: flex;
8946
+ align-items: center;
8947
+ gap: 1rem;
8948
+ }
8949
+ .billing-chart-legend {
8950
+ display: flex;
8951
+ align-items: center;
8952
+ gap: 0.375rem;
8953
+ font-size: 0.75rem;
8954
+ color: var(--color-text-secondary);
8955
+ }
8956
+ .billing-legend-dot {
8957
+ width: 8px;
8958
+ height: 8px;
8959
+ border-radius: 50%;
8960
+ }
8961
+ .billing-legend-tokens {
8962
+ background: var(--color-accent);
8963
+ }
8964
+ .billing-legend-cost {
8965
+ background: #10b981;
8966
+ }
8967
+ .billing-chart-empty {
8968
+ flex: 1;
8969
+ display: flex;
8970
+ align-items: center;
8971
+ justify-content: center;
8972
+ color: var(--color-text-secondary);
8973
+ font-size: 0.875rem;
8974
+ }
8975
+
8976
+ /* ── Combined Chart ──────────────────────────────────────────────────── */
8977
+ .billing-combined-chart {
8978
+ display: flex;
8979
+ align-items: flex-end;
8980
+ gap: 4px;
8981
+ height: 140px;
8982
+ padding-bottom: 1.5rem;
8983
+ position: relative;
8984
+ }
8985
+ .billing-bar-group {
8986
+ flex: 1;
8987
+ display: flex;
8988
+ flex-direction: column;
8989
+ align-items: center;
8990
+ height: 100%;
8991
+ position: relative;
8992
+ min-width: 0;
8993
+ cursor: pointer;
8994
+ }
8995
+ .billing-bar-group:hover {
8996
+ background: var(--color-bg-tertiary);
8997
+ border-radius: 4px;
8998
+ }
8999
+ .billing-bar-pair {
9000
+ width: 100%;
9001
+ height: 100%;
9002
+ display: flex;
9003
+ align-items: flex-end;
9004
+ justify-content: center;
9005
+ gap: 3px;
9006
+ }
9007
+ .billing-input-stack {
9008
+ width: 12px;
9009
+ display: flex;
9010
+ flex-direction: column;
9011
+ justify-content: flex-end;
9012
+ align-items: stretch;
9013
+ }
9014
+ .billing-cache-hit {
9015
+ background: #93c5fd;
9016
+ width: 100%;
9017
+ border-radius: 2px 2px 0 0;
9018
+ transition: height 0.2s ease;
9019
+ }
9020
+ .billing-cache-miss {
9021
+ background: #3b82f6;
9022
+ width: 100%;
9023
+ transition: height 0.2s ease;
9024
+ }
9025
+ .billing-output-bar {
9026
+ width: 12px;
9027
+ background: #10b981;
9028
+ border-radius: 2px 2px 0 0;
9029
+ transition: height 0.2s ease;
9030
+ }
9031
+ .billing-bar-date {
9032
+ position: absolute;
9033
+ bottom: -1.25rem;
9034
+ font-size: 0.625rem;
9035
+ color: var(--color-text-secondary);
9036
+ white-space: nowrap;
9037
+ min-height: 0.75rem;
9038
+ }
9039
+
9040
+ /* Legend colors */
9041
+ .billing-legend-cache-hit { background: #93c5fd; }
9042
+ .billing-legend-cache-miss { background: #3b82f6; }
9043
+ .billing-legend-output { background: #10b981; }
9044
+
9045
+ /* ── Chart Tooltip ───────────────────────────────────────────────────── */
9046
+ .billing-chart-tooltip {
9047
+ display: none;
9048
+ position: fixed;
9049
+ background: var(--color-bg-primary);
9050
+ border: 1px solid var(--color-border-primary);
9051
+ border-radius: 8px;
9052
+ padding: 0.75rem;
9053
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
9054
+ z-index: 1000;
9055
+ min-width: 200px;
9056
+ pointer-events: none;
9057
+ }
9058
+ .tooltip-header {
9059
+ display: flex;
9060
+ justify-content: space-between;
9061
+ align-items: center;
8540
9062
  margin-bottom: 0.5rem;
9063
+ padding-bottom: 0.5rem;
9064
+ border-bottom: 1px solid var(--color-border-primary);
8541
9065
  }
8542
- .billing-card-value {
8543
- font-size: 1.5rem;
8544
- font-weight: 700;
9066
+ .tooltip-date {
9067
+ font-weight: 600;
8545
9068
  color: var(--color-text-primary);
8546
9069
  }
8547
- .billing-card-primary .billing-card-value {
9070
+ .tooltip-total {
9071
+ font-size: 0.875rem;
8548
9072
  color: var(--color-accent);
9073
+ font-weight: 500;
9074
+ }
9075
+ .tooltip-row {
9076
+ display: flex;
9077
+ align-items: center;
9078
+ gap: 0.5rem;
9079
+ padding: 0.25rem 0;
9080
+ font-size: 0.8125rem;
9081
+ }
9082
+ .tooltip-dot {
9083
+ width: 8px;
9084
+ height: 8px;
9085
+ border-radius: 50%;
9086
+ flex-shrink: 0;
9087
+ }
9088
+ .tooltip-cache-hit { background: #93c5fd; }
9089
+ .tooltip-cache-miss { background: #3b82f6; }
9090
+ .tooltip-output { background: #10b981; }
9091
+ .tooltip-label {
9092
+ flex: 1;
9093
+ color: var(--color-text-secondary);
9094
+ }
9095
+ .tooltip-value {
9096
+ font-weight: 500;
9097
+ color: var(--color-text-primary);
9098
+ }
9099
+
9100
+ /* ── Bottom Grid ─────────────────────────────────────────────────────── */
9101
+ .billing-bottom-grid {
9102
+ display: grid;
9103
+ grid-template-columns: repeat(2, 1fr);
9104
+ gap: 1rem;
9105
+ }
9106
+ @media (max-width: 768px) {
9107
+ .billing-bottom-grid { grid-template-columns: 1fr; }
8549
9108
  }
8550
9109
  .billing-section {
8551
9110
  background: var(--color-bg-secondary);
8552
9111
  border: 1px solid var(--color-border-primary);
8553
9112
  border-radius: 12px;
8554
9113
  padding: 1.25rem;
8555
- margin-bottom: 1.25rem;
8556
9114
  }
8557
9115
  .billing-section h3 {
8558
- font-size: 1rem;
9116
+ font-size: 0.9375rem;
8559
9117
  font-weight: 600;
8560
9118
  color: var(--color-text-primary);
8561
9119
  margin: 0 0 1rem 0;
8562
9120
  }
8563
- .billing-token-grid {
8564
- display: grid;
8565
- grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
8566
- gap: 0.75rem;
9121
+
9122
+ /* ── Token Breakdown Bars ────────────────────────────────────────────── */
9123
+ .billing-token-bars {
9124
+ display: flex;
9125
+ flex-direction: column;
9126
+ gap: 0.875rem;
8567
9127
  }
8568
- .billing-token-item {
9128
+ .billing-token-bar-item {
9129
+ display: flex;
9130
+ flex-direction: column;
9131
+ gap: 0.375rem;
9132
+ }
9133
+ .billing-token-bar-header {
8569
9134
  display: flex;
8570
9135
  justify-content: space-between;
8571
9136
  align-items: center;
8572
- padding: 0.5rem 0.75rem;
8573
- background: var(--color-bg-primary);
8574
- border-radius: 8px;
8575
9137
  }
8576
- .billing-token-label {
9138
+ .billing-token-bar-label {
8577
9139
  font-size: 0.8125rem;
8578
9140
  color: var(--color-text-secondary);
8579
9141
  }
8580
- .billing-token-value {
8581
- font-size: 0.875rem;
9142
+ .billing-token-bar-value {
9143
+ font-size: 0.8125rem;
8582
9144
  font-weight: 600;
8583
9145
  color: var(--color-text-primary);
8584
9146
  }
8585
- .billing-model-table {
8586
- width: 100%;
8587
- border-collapse: collapse;
9147
+ .billing-token-bar-track {
9148
+ height: 6px;
9149
+ background: var(--color-bg-tertiary);
9150
+ border-radius: 3px;
9151
+ overflow: hidden;
8588
9152
  }
8589
- .billing-model-table th,
8590
- .billing-model-table td {
8591
- padding: 0.625rem 0.75rem;
8592
- text-align: left;
8593
- border-bottom: 1px solid var(--color-border-primary);
9153
+ .billing-token-bar-fill {
9154
+ height: 100%;
9155
+ border-radius: 3px;
9156
+ transition: width 0.3s ease;
8594
9157
  }
8595
- .billing-model-table th {
8596
- font-size: 0.75rem;
8597
- font-weight: 600;
8598
- color: var(--color-text-secondary);
8599
- text-transform: uppercase;
9158
+ .billing-bar-prompt {
9159
+ background: linear-gradient(90deg, #3b82f6 0%, #60a5fa 100%);
8600
9160
  }
8601
- .billing-model-table td {
8602
- font-size: 0.875rem;
8603
- color: var(--color-text-primary);
9161
+ .billing-bar-completion {
9162
+ background: linear-gradient(90deg, #10b981 0%, #34d399 100%);
8604
9163
  }
8605
- .billing-model-name {
8606
- font-weight: 500;
9164
+ .billing-bar-cache-read {
9165
+ background: linear-gradient(90deg, #93c5fd 0%, #bfdbfe 100%);
8607
9166
  }
8608
- .billing-model-cost {
8609
- font-family: var(--font-mono);
9167
+ .billing-bar-cache-write {
9168
+ background: linear-gradient(90deg, #6366f1 0%, #818cf8 100%);
8610
9169
  }
8611
- .billing-chart {
9170
+
9171
+ /* ── Model List ──────────────────────────────────────────────────────── */
9172
+ .billing-model-list {
8612
9173
  display: flex;
8613
- align-items: flex-end;
8614
- gap: 4px;
8615
- height: 120px;
8616
- padding-top: 1rem;
9174
+ flex-direction: column;
9175
+ gap: 0.75rem;
8617
9176
  }
8618
- .billing-chart-bar-wrapper {
8619
- flex: 1;
9177
+ .billing-model-empty {
9178
+ color: var(--color-text-secondary);
9179
+ font-size: 0.875rem;
9180
+ padding: 1rem 0;
9181
+ }
9182
+ .billing-model-row {
9183
+ display: grid;
9184
+ grid-template-columns: 1fr 100px 70px;
9185
+ align-items: center;
9186
+ gap: 0.75rem;
9187
+ }
9188
+ .billing-model-info {
8620
9189
  display: flex;
8621
9190
  flex-direction: column;
8622
- align-items: center;
8623
- justify-content: flex-end;
8624
- height: 100%;
9191
+ gap: 0.125rem;
9192
+ min-width: 0;
8625
9193
  }
8626
- .billing-chart-bar {
8627
- width: 100%;
8628
- max-width: 40px;
8629
- min-height: 4px;
8630
- background: var(--color-accent, #6366f1);
8631
- border-radius: 4px 4px 0 0;
8632
- transition: height 0.3s ease;
9194
+ .billing-model-name {
9195
+ font-size: 0.8125rem;
9196
+ font-weight: 500;
9197
+ color: var(--color-text-primary);
9198
+ white-space: nowrap;
9199
+ overflow: hidden;
9200
+ text-overflow: ellipsis;
8633
9201
  }
8634
- .billing-chart-label {
8635
- font-size: 0.625rem;
9202
+ .billing-model-meta {
9203
+ font-size: 0.6875rem;
8636
9204
  color: var(--color-text-secondary);
8637
- margin-top: 0.25rem;
8638
- white-space: nowrap;
9205
+ }
9206
+ .billing-model-bar-track {
9207
+ height: 6px;
9208
+ background: var(--color-bg-tertiary);
9209
+ border-radius: 3px;
9210
+ overflow: hidden;
9211
+ }
9212
+ .billing-model-bar-fill {
9213
+ height: 100%;
9214
+ background: linear-gradient(90deg, var(--color-accent) 0%, #818cf8 100%);
9215
+ border-radius: 3px;
9216
+ }
9217
+ .billing-model-cost {
9218
+ font-size: 0.8125rem;
9219
+ font-weight: 600;
9220
+ font-family: var(--font-mono);
9221
+ color: var(--color-text-primary);
9222
+ text-align: right;
8639
9223
  }
8640
9224
 
8641
9225
  /* ── MCP panel ───────────────────────────────────────────────────── */