@linxiraos/pi-stats 1.1.26 → 1.2.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.
Files changed (125) hide show
  1. package/CHANGELOG.md +12 -5
  2. package/build.ts +4 -0
  3. package/dist/client/favicon.ico +0 -0
  4. package/dist/client/index.css +1 -1
  5. package/dist/client/index.html +1 -0
  6. package/dist/client/index.js +96 -96
  7. package/dist/types/aggregator.d.ts +4 -1
  8. package/dist/types/client/api.d.ts +5 -1
  9. package/dist/types/client/app/nav.d.ts +5 -2
  10. package/dist/types/client/data/formatters.d.ts +7 -2
  11. package/dist/types/client/data/live.d.ts +16 -11
  12. package/dist/types/client/data/query-store.d.ts +39 -0
  13. package/dist/types/client/data/query.d.ts +10 -5
  14. package/dist/types/client/data/range.d.ts +4 -3
  15. package/dist/types/client/i18n/format.d.ts +9 -0
  16. package/dist/types/client/i18n/index.d.ts +18 -0
  17. package/dist/types/client/i18n/messages/charts.d.ts +8 -0
  18. package/dist/types/client/i18n/messages/common.d.ts +153 -0
  19. package/dist/types/client/i18n/messages/costs.d.ts +92 -0
  20. package/dist/types/client/i18n/messages/en.d.ts +1255 -0
  21. package/dist/types/client/i18n/messages/errors.d.ts +78 -0
  22. package/dist/types/client/i18n/messages/frustration.d.ts +191 -0
  23. package/dist/types/client/i18n/messages/gain.d.ts +54 -0
  24. package/dist/types/client/i18n/messages/models.d.ts +94 -0
  25. package/dist/types/client/i18n/messages/nav.d.ts +46 -0
  26. package/dist/types/client/i18n/messages/overview.d.ts +80 -0
  27. package/dist/types/client/i18n/messages/projects.d.ts +84 -0
  28. package/dist/types/client/i18n/messages/providers.d.ts +142 -0
  29. package/dist/types/client/i18n/messages/requests.d.ts +72 -0
  30. package/dist/types/client/i18n/messages/tools.d.ts +119 -0
  31. package/dist/types/client/i18n/messages/traces.d.ts +144 -0
  32. package/dist/types/client/i18n/messages/ui.d.ts +44 -0
  33. package/dist/types/client/i18n/messages/zh-CN.d.ts +13 -0
  34. package/dist/types/client/i18n/types.d.ts +15 -0
  35. package/dist/types/client/traces/Minimap.d.ts +2 -0
  36. package/dist/types/client/traces/TimelineCanvas.d.ts +29 -8
  37. package/dist/types/client/traces/TranscriptList.d.ts +3 -1
  38. package/dist/types/db.d.ts +14 -21
  39. package/dist/types/embedded-client.d.ts +5 -0
  40. package/dist/types/frustration.d.ts +18 -9
  41. package/dist/types/live.d.ts +5 -3
  42. package/dist/types/locale.d.ts +16 -0
  43. package/dist/types/parser.d.ts +0 -17
  44. package/dist/types/rollup.d.ts +9 -1
  45. package/dist/types/server.d.ts +6 -0
  46. package/dist/types/shared-types.d.ts +7 -0
  47. package/dist/types/trace.d.ts +18 -6
  48. package/dist/types/types.d.ts +13 -1
  49. package/dist/types/user-metrics.d.ts +23 -1
  50. package/package.json +5 -5
  51. package/src/aggregator.ts +31 -11
  52. package/src/client/api.ts +40 -5
  53. package/src/client/app/LiveChip.tsx +14 -13
  54. package/src/client/app/Shell.tsx +19 -13
  55. package/src/client/app/ThemeToggle.tsx +4 -3
  56. package/src/client/app/nav.ts +19 -16
  57. package/src/client/data/formatters.ts +80 -13
  58. package/src/client/data/live.tsx +85 -45
  59. package/src/client/data/query-store.ts +108 -0
  60. package/src/client/data/query.ts +47 -56
  61. package/src/client/data/range.ts +34 -14
  62. package/src/client/data/series.ts +7 -1
  63. package/src/client/favicon.ico +0 -0
  64. package/src/client/i18n/format.ts +28 -0
  65. package/src/client/i18n/index.ts +53 -0
  66. package/src/client/i18n/messages/charts.ts +8 -0
  67. package/src/client/i18n/messages/common.ts +157 -0
  68. package/src/client/i18n/messages/costs.ts +104 -0
  69. package/src/client/i18n/messages/en.ts +40 -0
  70. package/src/client/i18n/messages/errors.ts +80 -0
  71. package/src/client/i18n/messages/frustration.ts +198 -0
  72. package/src/client/i18n/messages/gain.ts +54 -0
  73. package/src/client/i18n/messages/models.ts +94 -0
  74. package/src/client/i18n/messages/nav.ts +46 -0
  75. package/src/client/i18n/messages/overview.ts +90 -0
  76. package/src/client/i18n/messages/projects.ts +84 -0
  77. package/src/client/i18n/messages/providers.ts +165 -0
  78. package/src/client/i18n/messages/requests.ts +73 -0
  79. package/src/client/i18n/messages/tools.ts +120 -0
  80. package/src/client/i18n/messages/traces.ts +160 -0
  81. package/src/client/i18n/messages/ui.ts +46 -0
  82. package/src/client/i18n/messages/zh-CN.ts +43 -0
  83. package/src/client/i18n/types.ts +19 -0
  84. package/src/client/index.tsx +4 -0
  85. package/src/client/routes/CostsRoute.tsx +61 -48
  86. package/src/client/routes/ErrorsRoute.tsx +71 -47
  87. package/src/client/routes/FrustrationRoute.tsx +131 -116
  88. package/src/client/routes/GainRoute.tsx +42 -30
  89. package/src/client/routes/ModelsRoute.tsx +90 -73
  90. package/src/client/routes/OverviewRoute.tsx +109 -63
  91. package/src/client/routes/ProjectsRoute.tsx +73 -46
  92. package/src/client/routes/ProvidersRoute.tsx +151 -114
  93. package/src/client/routes/RequestsRoute.tsx +69 -46
  94. package/src/client/routes/ToolsRoute.tsx +108 -94
  95. package/src/client/routes/TracesRoute.tsx +25 -23
  96. package/src/client/styles.css +5 -2
  97. package/src/client/traces/AggregatesPanel.tsx +19 -8
  98. package/src/client/traces/Minimap.tsx +65 -27
  99. package/src/client/traces/SpanDrawer.tsx +46 -21
  100. package/src/client/traces/SummaryStrip.tsx +27 -11
  101. package/src/client/traces/TimelineCanvas.tsx +245 -116
  102. package/src/client/traces/TraceView.tsx +51 -36
  103. package/src/client/traces/TranscriptList.tsx +20 -11
  104. package/src/client/traces/traces.css +26 -0
  105. package/src/client/ui/JsonBlock.tsx +3 -2
  106. package/src/client/ui/Modal.tsx +3 -2
  107. package/src/client/ui/RequestDrawer.tsx +33 -30
  108. package/src/client/ui/SearchInput.tsx +2 -1
  109. package/src/client/ui/States.tsx +3 -2
  110. package/src/client/ui/Table.tsx +7 -3
  111. package/src/db.ts +150 -135
  112. package/src/embedded-client.ts +9 -0
  113. package/src/frustration.ts +9 -30
  114. package/src/index.ts +2 -1
  115. package/src/live.ts +36 -11
  116. package/src/locale.ts +29 -0
  117. package/src/parser.ts +37 -72
  118. package/src/port-conflict.ts +1 -1
  119. package/src/prompts/judge/frustration.json +19 -0
  120. package/src/rollup.ts +41 -20
  121. package/src/server.ts +67 -27
  122. package/src/shared-types.ts +7 -0
  123. package/src/trace.ts +54 -40
  124. package/src/types.ts +13 -1
  125. package/src/user-metrics.ts +220 -6
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Tools copy. Keys are slugs (`tools.<name>`); the English string is the
3
+ * source of truth and `zh-CN` overrides it. Tool names themselves (`bash`,
4
+ * `read`, `edit`) are identifiers and are never translated.
5
+ */
6
+ export const tools = {
7
+ en: {
8
+ "tools.title": "Tools",
9
+ "tools.description": "Which tools zeta called in {window}, how often they failed, and what they cost.",
10
+ "tools.tool-calls": "Tool calls",
11
+ "tools.failed-n": "{count} failed",
12
+ "tools.distinct-tools": "Distinct tools",
13
+ "tools.most-used": "Most used: {tool}",
14
+ "tools.error-rate-title": "Tool results that came back flagged as errors",
15
+ "tools.succeeded-n": "{count} succeeded",
16
+ "tools.attributed-tokens": "Attributed tokens",
17
+ "tools.tokens-output": "{tokens} output",
18
+ "tools.attributed-cost": "Attributed cost",
19
+ "tools.attribution-note":
20
+ "Tokens and API-equivalent cost of each invoking turn, split evenly across that turn's tool calls",
21
+ "tools.attribution-estimate": "{note}; API-equivalent estimate",
22
+ "tools.unpriced-requests-n": "{count} unpriced requests",
23
+ "tools.api-equivalent": "API-equivalent",
24
+ "tools.result-text": "Result text",
25
+ "tools.result-chars-title": "Characters of tool-result text fed back into context",
26
+ "tools.chars": "{count} chars",
27
+ "tools.call-arguments": "Call arguments",
28
+ "tools.args-chars-title": "Characters of serialized tool-call arguments",
29
+ "tools.avg-result-per-call": "Avg result per call",
30
+ "tools.avg-args-per-call": "Avg arguments per call",
31
+ "tools.calls-over-time": "Calls over time",
32
+ "tools.errors-over-time": "Errors over time",
33
+ "tools.chart-description": "Per {bucket}, top {count} tools stacked",
34
+ "tools.bucket-5m": "5 minutes",
35
+ "tools.bucket-hour": "hour",
36
+ "tools.bucket-day": "day",
37
+ "tools.calls": "Calls",
38
+ "tools.errors": "Errors",
39
+ "tools.no-tool-errors": "No tool errors in this range",
40
+ "tools.by-tool": "By tool",
41
+ "tools.by-tool-description": "{note}. Select a tool to break it down by model.",
42
+ "tools.by-tool-and-model": "By tool and model",
43
+ "tools.by-tool-and-model-description": "Which models call which tools, and how often those calls fail",
44
+ "tools.filter-by-tool": "Filter by tool",
45
+ "tools.all-tools": "All tools",
46
+ "tools.clear-tool-filter": "Clear tool filter",
47
+ "tools.no-tool-calls": "No tool calls in this range",
48
+ "tools.no-calls-to-tool": "No calls to {tool} in this range",
49
+ "tools.tool": "Tool",
50
+ "tools.trend": "Trend",
51
+ "tools.trend-title": "Calls per bucket over the range",
52
+ "tools.share-of-calls": "{percent} of all tool calls",
53
+ "tools.errors-title": "Calls whose result came back flagged as an error",
54
+ "tools.args": "Args",
55
+ "tools.result": "Result",
56
+ "tools.result-per-call": "Result / call",
57
+ "tools.result-per-call-title": "Mean tool-result characters per call",
58
+ "tools.attr-tokens": "Attr. tokens",
59
+ "tools.share-of-tokens": "{percent} of attributed tokens",
60
+ "tools.attr-cost": "Attr. cost",
61
+ "tools.share-of-cost": "{percent} of attributed cost",
62
+ "tools.last-used": "Last used",
63
+ },
64
+ "zh-CN": {
65
+ "tools.title": "工具",
66
+ "tools.description": "zeta 在{window}调用了哪些工具、它们的失败频率如何,以及产生了多少费用。",
67
+ "tools.tool-calls": "工具调用",
68
+ "tools.failed-n": "{count} 个失败",
69
+ "tools.distinct-tools": "不同工具数",
70
+ "tools.most-used": "使用最多:{tool}",
71
+ "tools.error-rate-title": "返回时被标记为错误的工具结果",
72
+ "tools.succeeded-n": "{count} 个成功",
73
+ "tools.attributed-tokens": "归属 Token",
74
+ "tools.tokens-output": "{tokens} 输出",
75
+ "tools.attributed-cost": "归属费用",
76
+ "tools.attribution-note": "每次调用回合的 Token 与 API 等价费用,平均分摊到该回合的各个工具调用",
77
+ "tools.attribution-estimate": "{note};按 API 等价估算",
78
+ "tools.unpriced-requests-n": "{count} 个未定价请求",
79
+ "tools.api-equivalent": "按 API 等价",
80
+ "tools.result-text": "结果文本",
81
+ "tools.result-chars-title": "回填到上下文中的工具结果文本字符数",
82
+ "tools.chars": "{count} 字符",
83
+ "tools.call-arguments": "调用参数",
84
+ "tools.args-chars-title": "序列化后的工具调用参数字符数",
85
+ "tools.avg-result-per-call": "每次调用平均结果",
86
+ "tools.avg-args-per-call": "每次调用平均参数",
87
+ "tools.calls-over-time": "调用次数随时间变化",
88
+ "tools.errors-over-time": "错误数随时间变化",
89
+ "tools.chart-description": "按{bucket}统计,堆叠显示前 {count} 个工具",
90
+ "tools.bucket-5m": "5 分钟",
91
+ "tools.bucket-hour": "小时",
92
+ "tools.bucket-day": "天",
93
+ "tools.calls": "调用次数",
94
+ "tools.errors": "错误数",
95
+ "tools.no-tool-errors": "该时间范围内没有工具错误",
96
+ "tools.by-tool": "按工具",
97
+ "tools.by-tool-description": "{note}。选择某个工具可按模型细分。",
98
+ "tools.by-tool-and-model": "按工具和模型",
99
+ "tools.by-tool-and-model-description": "哪些模型调用了哪些工具,以及这些调用的失败频率",
100
+ "tools.filter-by-tool": "按工具筛选",
101
+ "tools.all-tools": "全部工具",
102
+ "tools.clear-tool-filter": "清除工具筛选",
103
+ "tools.no-tool-calls": "该时间范围内没有工具调用",
104
+ "tools.no-calls-to-tool": "该时间范围内没有对 {tool} 的调用",
105
+ "tools.tool": "工具",
106
+ "tools.trend": "趋势",
107
+ "tools.trend-title": "时间范围内每个分桶的调用次数",
108
+ "tools.share-of-calls": "占全部工具调用的 {percent}",
109
+ "tools.errors-title": "结果返回时被标记为错误的调用",
110
+ "tools.args": "参数",
111
+ "tools.result": "结果",
112
+ "tools.result-per-call": "结果 / 次",
113
+ "tools.result-per-call-title": "每次调用平均工具结果字符数",
114
+ "tools.attr-tokens": "归属 Token",
115
+ "tools.share-of-tokens": "占归属 Token 的 {percent}",
116
+ "tools.attr-cost": "归属费用",
117
+ "tools.share-of-cost": "占归属费用的 {percent}",
118
+ "tools.last-used": "最近使用",
119
+ },
120
+ } as const;
@@ -0,0 +1,160 @@
1
+ /**
2
+ * Traces copy. Keys are slugs (`trace.<name>`); the English string is the
3
+ * source of truth and `zh-CN` overrides it.
4
+ */
5
+ export const traces = {
6
+ en: {
7
+ // ── session list (TracesRoute) ──────────────────────────────────────
8
+ "trace.title": "Traces",
9
+ "trace.description": "Recent sessions with subagent activity folded in. Open one to inspect its timeline.",
10
+ "trace.sessions": "Sessions",
11
+ "trace.session": "Session",
12
+ "trace.most-recent": "{count} most recent",
13
+ "trace.most-recent-filtered": "{shown} of {total} most recent",
14
+ "trace.filter-placeholder": "Filter by title, project, model…",
15
+ "trace.empty-title": "No sessions found",
16
+ "trace.empty-hint": "Run a sync to index recent activity.",
17
+ "trace.no-matching-title": "No matching sessions",
18
+ "trace.no-matching-hint": "Try a different filter.",
19
+ // ── span categories ─────────────────────────────────────────────────
20
+ "trace.tool": "Tool",
21
+ "trace.tools": "Tools",
22
+ "trace.agent": "Agent",
23
+ "trace.agents": "Agents",
24
+ "trace.background": "Background",
25
+ "trace.bg": "Bg",
26
+ // ── trace viewer toolbar / headings (TraceView) ─────────────────────
27
+ "trace.refresh": "Refresh trace",
28
+ "trace.timeline": "Timeline",
29
+ "trace.timeline-hint":
30
+ "W/S zoom · A/D pan · drag pan · wheel zoom · 0 fit · F focus selection · dbl-click focus · Esc deselect",
31
+ "trace.expand-all": "Expand all",
32
+ "trace.collapse-all": "Collapse all",
33
+ "trace.axis-mode": "Axis mode",
34
+ "trace.mode-time-title": "Real wall-clock time",
35
+ "trace.mode-turns-title": "Equal width per user turn",
36
+ "trace.mode-calls-title": "Equal width per model/tool call boundary",
37
+ "trace.turns": "Turns",
38
+ "trace.calls": "Calls",
39
+ "trace.compress-idle": "Compress idle",
40
+ "trace.search-placeholder": "Search spans…",
41
+ "trace.previous-match": "Previous match",
42
+ "trace.next-match": "Next match",
43
+ "trace.transcript": "Transcript",
44
+ "trace.transcript-description": "Every span and marker in order; click to inspect",
45
+ "trace.no-matching-events": "No matching events",
46
+ // ── flamegraph canvas / minimap ─────────────────────────────────────
47
+ "trace.canvas-aria": "Trace timeline. W and S zoom, A and D pan, 0 fits all, F focuses the selection.",
48
+ "trace.minimap-aria": "Timeline overview brush",
49
+ "trace.expand-track": "Expand {track}",
50
+ "trace.collapse-track": "Collapse {track}",
51
+ "trace.unterminated": "unterminated",
52
+ "trace.tok": "tok",
53
+ "trace.ttft": "TTFT",
54
+ // ── summary strip ───────────────────────────────────────────────────
55
+ "trace.wall-time": "Wall time",
56
+ "trace.model-time": "Model time",
57
+ "trace.tool-time": "Tool time",
58
+ "trace.idle": "Idle",
59
+ "trace.tool-calls-n": "{count} tool calls",
60
+ "trace.of-wall": "{percent} of wall",
61
+ // ── tool aggregates ─────────────────────────────────────────────────
62
+ "trace.tool-aggregates": "Tool aggregates",
63
+ "trace.tool-aggregates-desc": "{count} tools, by total time",
64
+ "trace.errors": "Errors",
65
+ "trace.failed-n": "{count} failed",
66
+ "trace.avg": "Avg",
67
+ "trace.max": "Max",
68
+ // ── span drawer ─────────────────────────────────────────────────────
69
+ "trace.start": "Start",
70
+ "trace.track": "Track",
71
+ "trace.io-cached": "Input / output / cached",
72
+ "trace.stop-reason": "Stop reason",
73
+ "trace.copy-json": "Copy raw JSON",
74
+ "trace.error-message": "Error message",
75
+ "trace.task": "Task",
76
+ "trace.open-child-track": "Open child track",
77
+ "trace.args": "Args",
78
+ "trace.thinking": "Thinking",
79
+ "trace.text": "Text",
80
+ "trace.raw-entry": "Raw entry",
81
+ "trace.load-failed": "Failed to load entry: {message}",
82
+ },
83
+ "zh-CN": {
84
+ // ── session list (TracesRoute) ──────────────────────────────────────
85
+ "trace.title": "调用链",
86
+ "trace.description": "最近的会话,已合并子代理活动。打开其中一个即可查看其时间线。",
87
+ "trace.sessions": "会话",
88
+ "trace.session": "会话",
89
+ "trace.most-recent": "最近 {count} 条",
90
+ "trace.most-recent-filtered": "最近 {total} 条中的 {shown} 条",
91
+ "trace.filter-placeholder": "按标题、项目或模型筛选…",
92
+ "trace.empty-title": "未找到会话",
93
+ "trace.empty-hint": "运行一次同步以索引最近的活动。",
94
+ "trace.no-matching-title": "没有匹配的会话",
95
+ "trace.no-matching-hint": "请尝试其他筛选条件。",
96
+ // ── span categories ─────────────────────────────────────────────────
97
+ "trace.tool": "工具",
98
+ "trace.tools": "工具",
99
+ "trace.agent": "智能体",
100
+ "trace.agents": "智能体",
101
+ "trace.background": "后台",
102
+ "trace.bg": "背景",
103
+ // ── trace viewer toolbar / headings (TraceView) ─────────────────────
104
+ "trace.refresh": "刷新调用链",
105
+ "trace.timeline": "时间线",
106
+ "trace.timeline-hint":
107
+ "W/S 缩放 · A/D 平移 · 拖拽平移 · 滚轮缩放 · 0 适应全部 · F 聚焦所选 · 双击聚焦 · Esc 取消选择",
108
+ "trace.expand-all": "全部展开",
109
+ "trace.collapse-all": "全部折叠",
110
+ "trace.axis-mode": "坐标轴模式",
111
+ "trace.mode-time-title": "真实墙钟时间",
112
+ "trace.mode-turns-title": "每个用户轮次等宽",
113
+ "trace.mode-calls-title": "每个模型/工具调用边界等宽",
114
+ "trace.turns": "轮次",
115
+ "trace.calls": "调用次数",
116
+ "trace.compress-idle": "压缩空闲时间",
117
+ "trace.search-placeholder": "搜索跨度…",
118
+ "trace.previous-match": "上一个匹配",
119
+ "trace.next-match": "下一个匹配",
120
+ "trace.transcript": "对话记录",
121
+ "trace.transcript-description": "按顺序列出所有跨度和标记;点击可查看详情",
122
+ "trace.no-matching-events": "没有匹配的事件",
123
+ // ── flamegraph canvas / minimap ─────────────────────────────────────
124
+ "trace.canvas-aria": "调用链时间线。W 和 S 缩放,A 和 D 平移,0 适应全部,F 聚焦所选。",
125
+ "trace.minimap-aria": "时间线概览刷选",
126
+ "trace.expand-track": "展开 {track}",
127
+ "trace.collapse-track": "折叠 {track}",
128
+ "trace.unterminated": "未结束",
129
+ "trace.tok": "Token",
130
+ "trace.ttft": "首 Token 延迟",
131
+ // ── summary strip ───────────────────────────────────────────────────
132
+ "trace.wall-time": "墙钟时间",
133
+ "trace.model-time": "模型耗时",
134
+ "trace.tool-time": "工具耗时",
135
+ "trace.idle": "空闲",
136
+ "trace.tool-calls-n": "{count} 次工具调用",
137
+ "trace.of-wall": "占墙钟时间 {percent}",
138
+ // ── tool aggregates ─────────────────────────────────────────────────
139
+ "trace.tool-aggregates": "工具汇总",
140
+ "trace.tool-aggregates-desc": "{count} 个工具,按总耗时排序",
141
+ "trace.errors": "错误",
142
+ "trace.failed-n": "{count} 个失败",
143
+ "trace.avg": "平均",
144
+ "trace.max": "最大",
145
+ // ── span drawer ─────────────────────────────────────────────────────
146
+ "trace.start": "开始",
147
+ "trace.track": "轨道",
148
+ "trace.io-cached": "输入 / 输出 / 缓存读取",
149
+ "trace.stop-reason": "停止原因",
150
+ "trace.copy-json": "复制原始 JSON",
151
+ "trace.error-message": "错误信息",
152
+ "trace.task": "任务",
153
+ "trace.open-child-track": "打开子轨道",
154
+ "trace.args": "参数",
155
+ "trace.thinking": "思考过程",
156
+ "trace.text": "文本",
157
+ "trace.raw-entry": "原始条目",
158
+ "trace.load-failed": "加载条目失败:{message}",
159
+ },
160
+ } as const;
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Ui copy. Keys are slugs (`ui.<name>`); the English string is the
3
+ * source of truth and `zh-CN` overrides it.
4
+ */
5
+ export const ui = {
6
+ en: {
7
+ // ── table / states ──────────────────────────────────────────────────
8
+ "ui.table-shown-of": "{shown} of {total}",
9
+ "ui.show-fewer": "Show fewer",
10
+ "ui.retry": "Retry",
11
+ "ui.delta-new": "new",
12
+ "ui.json": "JSON",
13
+ // ── request drawer ──────────────────────────────────────────────────
14
+ "ui.trace": "Trace",
15
+ "ui.open-trace": "Open this request's session in the trace view",
16
+ "ui.status-ok": "OK",
17
+ "ui.section-timing": "Timing",
18
+ "ui.time-to-first-token": "Time to first token",
19
+ "ui.uncached-input": "Uncached input",
20
+ "ui.section-cost": "API-equivalent cost",
21
+ "ui.section-identity": "Identity",
22
+ "ui.stop-reason": "Stop reason",
23
+ "ui.api": "API",
24
+ "ui.session-file": "Session file",
25
+ "ui.stats-row": "Stats row",
26
+ },
27
+ "zh-CN": {
28
+ "ui.table-shown-of": "已显示 {shown} / 共 {total}",
29
+ "ui.show-fewer": "收起",
30
+ "ui.retry": "重试",
31
+ "ui.delta-new": "新增",
32
+ "ui.json": "JSON 数据",
33
+ "ui.trace": "调用链",
34
+ "ui.open-trace": "在调用链视图中打开该请求的会话",
35
+ "ui.status-ok": "正常",
36
+ "ui.section-timing": "时间",
37
+ "ui.time-to-first-token": "首 Token 延迟",
38
+ "ui.uncached-input": "未缓存输入",
39
+ "ui.section-cost": "API 等价费用",
40
+ "ui.section-identity": "标识",
41
+ "ui.stop-reason": "停止原因",
42
+ "ui.api": "接口",
43
+ "ui.session-file": "会话文件",
44
+ "ui.stats-row": "统计行",
45
+ },
46
+ } as const;
@@ -0,0 +1,43 @@
1
+ import type { MessageKey } from "./en";
2
+ import { nav } from "./nav";
3
+ import { common } from "./common";
4
+ import { overview } from "./overview";
5
+ import { models } from "./models";
6
+ import { providers } from "./providers";
7
+ import { costs } from "./costs";
8
+ import { requests } from "./requests";
9
+ import { errors } from "./errors";
10
+ import { traces } from "./traces";
11
+ import { tools } from "./tools";
12
+ import { frustration } from "./frustration";
13
+ import { projects } from "./projects";
14
+ import { gain } from "./gain";
15
+ import { ui } from "./ui";
16
+ import { charts } from "./charts";
17
+
18
+ /**
19
+ * Simplified Chinese overrides. Incomplete on purpose in source: the coverage
20
+ * test (`packages/stats/test/i18n-coverage.test.ts`) fails on any missing key,
21
+ * which keeps a half-translated page out of a release without breaking builds
22
+ * mid-flight.
23
+ */
24
+ export const zhCNMessages: Partial<Record<MessageKey, string>> = {
25
+ ...nav["zh-CN"],
26
+ ...common["zh-CN"],
27
+ ...overview["zh-CN"],
28
+ ...models["zh-CN"],
29
+ ...providers["zh-CN"],
30
+ ...costs["zh-CN"],
31
+ ...requests["zh-CN"],
32
+ ...errors["zh-CN"],
33
+ ...traces["zh-CN"],
34
+ ...tools["zh-CN"],
35
+ ...frustration["zh-CN"],
36
+ ...projects["zh-CN"],
37
+ ...gain["zh-CN"],
38
+ ...ui["zh-CN"],
39
+ ...charts["zh-CN"],
40
+ };
41
+
42
+ /** The Simplified Chinese locale pack. */
43
+ export const zhCNLocale = { id: "zh-CN", messages: zhCNMessages } as const;
@@ -0,0 +1,19 @@
1
+ export type { StatsLocale } from "../../locale";
2
+
3
+ import type { StatsLocale } from "../../locale";
4
+
5
+ /** Values a message may interpolate through `{name}` placeholders. */
6
+ export type TranslationParams = Record<string, string | number>;
7
+
8
+ /** A locale pack: the messages one locale overrides, keyed by slug. */
9
+ export interface LocalePack {
10
+ readonly id: StatsLocale;
11
+ readonly messages: Readonly<Record<string, string>>;
12
+ }
13
+
14
+ /**
15
+ * Messages for every locale, keyed first by locale id. `undefined` is part of
16
+ * the value type because a locale may override only some keys (English is the
17
+ * fallback for the rest).
18
+ */
19
+ export type MessagesByLocale = Readonly<Record<StatsLocale, Readonly<Record<string, string | undefined>>>>;
@@ -2,6 +2,10 @@ import "./styles.css";
2
2
  import { createRoot } from "react-dom/client";
3
3
  import App from "./App";
4
4
 
5
+ // The locale resolves when `./i18n` is first imported (the server stamps the
6
+ // host CLI's language into the page before this module runs), so the app is
7
+ // already rendering in the right language by the time React mounts.
8
+
5
9
  const root = document.getElementById("root");
6
10
  if (!root) throw new Error("missing #root");
7
11
  createRoot(root).render(<App />);