Skip to content

Commit 128abb4

Browse files
ryan-williamsclaude
andcommitted
Merge upstream waypoint C (kenn-io kenn-io#991 export v1 + kit-ui/service layer)
Waypoint C of the staged upstream catch-up (specs/merge-upstream-waypoints.md). Merges u/main up to 725a3d0 (126 commits: export v1 foundation, the export.PricingResolver cost model, a service layer for usage summaries, the kit-ui component library + TopBar/theme, i18n, pairwise usage comparison, new Activity/RecentEdits nav) into our branch. Pricing (thread the fork's 1h cache-write rate through export.PricingResolver without touching the frozen export v1 wire contract): - Add an internal, non-serialized CacheWrite1hPerMTok to export.ModelRates (no canonical_json key, no EffectiveModelRate field -> digest/wire stay byte-identical), populated from db.ModelPricing.CacheCreation1hPerMTok in loadPricingMap/modelPricingRates with the defensive 5m fallback. - Restore the 5m/1h split in dailyUsageAmounts and sessionRowCost via a new parseEphemeralCacheSplit helper (upstream's rewritten token parser skips the nested cache_creation object), computing cost inline so 1h bills at its rate. - Drop the now-orphaned db.modelRates struct; the export resolver is the single cost source. Usage summary: re-home the snapshot exporter's BuildUsageSummary onto the new service layer (service.BuildUsageSummaryResult + usageSummaryResponseFromService), since the fold*/computeCacheStats helpers moved into internal/service. Frontend: adopt kit-ui's TopBar header, filtering the nav `tabs` to hide curation routes in snapshot mode (replaces the old {#if !SNAPSHOT} nav); adopt kit-ui theme getters/setters in ui.svelte.ts; keep the fork's 24-color golden-angle + org-theming projectColor over kit-ui's hashColor; coexist the longestPrompts panel with the new pairwise-comparison panel in the usage store (Endpoint now spans summary|comparison|pairwise|topSessions|longestPrompts). CLI: `usage projects` and `usage longest-prompts` adopt the paired --format/--json convention upstream now enforces. Deferred (unchanged from B): 1h-cache parity for the PostgreSQL and DuckDB cost paths; SetSessionPrivate stays read-only on the PG store. Green: go build/vet/test (except the snapshot test needing a git `origin` remote), svelte-check, 1770 vitest tests, make build. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2 parents 309b8af + 725a3d0 commit 128abb4

926 files changed

Lines changed: 163369 additions & 30547 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
---
2+
name: localization-paraglide
3+
description: Use when adding, reviewing, or fixing localized UI copy in agentsview's Svelte frontend with Paraglide JS. Trigger for frontend/messages/*.json edits, generated m.* message usage, locale-aware number/date/relative-time formatting, pluralization, language switching, or hard-coded user-facing English in frontend/src.
4+
---
5+
6+
# Localization Paraglide
7+
8+
## Workflow
9+
10+
1. Read `frontend/project.inlang/settings.json`, `frontend/src/lib/i18n/index.ts`,
11+
and nearby localized components before editing.
12+
2. Put user-facing copy in `frontend/messages/en.json` and
13+
`frontend/messages/zh-CN.json` with identical keys.
14+
3. Import app localization through `frontend/src/lib/i18n/index.ts`:
15+
16+
```ts
17+
import { m } from "../../i18n/index.js";
18+
```
19+
20+
4. Call generated Paraglide messages as functions, for example
21+
`m.nav_sessions()` or `m.shared_active_filters_remove_agent({ agent })`.
22+
5. Use Paraglide message declarations for plural, number, datetime, and relative
23+
time when the formatted value is part of translatable copy.
24+
6. Use `formatDateTime()` from `frontend/src/lib/i18n/index.ts` for standalone
25+
visible date/time labels that need the active Paraglide locale.
26+
7. Keep technical identifiers untranslated: agent names, model names, file paths,
27+
CLI commands, IDs, and raw API values.
28+
8. Run `npm run i18n:compile` and `npm run check` from `frontend/` after message
29+
or component changes.
30+
31+
## Message Rules
32+
33+
- Keep key names scoped and descriptive, such as
34+
`settings_terminal_title` or `activity_concurrency_empty`.
35+
- Do not concatenate translated sentence fragments. Prefer one complete message
36+
with parameters.
37+
- Pass numbers as numbers to pluralized messages. Pass strings only for display
38+
fragments that have already been intentionally formatted.
39+
- In Svelte, put arrays or objects containing translated labels in `$derived` or
40+
`$derived.by` when they must update after locale changes.
41+
- Do not import from `frontend/src/lib/paraglide/*` directly in components unless
42+
changing the i18n wrapper itself.
43+
44+
## Formatting
45+
46+
Read `references/paraglide-formatting.md` when adding pluralization, ordinal
47+
rules, date/time formatting, relative dates, compact numbers, currencies, or
48+
mixed selector messages.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
interface:
2+
display_name: "Paraglide Localization"
3+
short_description: "Use Paraglide localization correctly"
4+
default_prompt: "Use $localization-paraglide to localize this agentsview UI change with Paraglide."
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
# Paraglide Formatting Reference
2+
3+
Official docs:
4+
5+
- Basic usage and generated messages:
6+
<https://github.com/opral/paraglide-js/blob/main/docs/basics.md>
7+
- Variants and plural selectors:
8+
<https://github.com/opral/paraglide-js/blob/main/docs/variants.md>
9+
- Number, datetime, and relative-time formatting:
10+
<https://github.com/opral/paraglide-js/blob/main/docs/formatting.md>
11+
12+
## Generated Messages
13+
14+
Use generated message functions through the app wrapper:
15+
16+
```ts
17+
import { m } from "../../i18n/index.js";
18+
19+
m.greeting({ name: "Ada" });
20+
```
21+
22+
Messages live in `frontend/messages/{locale}.json`. The English and Simplified
23+
Chinese catalogs must have the same keys.
24+
25+
## Cardinal Plurals
26+
27+
Use variant messages for counts. Paraglide's `plural` selector uses
28+
`Intl.PluralRules`, so it works for locales with more than English singular and
29+
plural categories.
30+
31+
```json
32+
{
33+
"tool_call_group_call_count": [
34+
{
35+
"declarations": [
36+
"input count",
37+
"local countPlural = count: plural"
38+
],
39+
"selectors": ["countPlural"],
40+
"match": {
41+
"countPlural=one": "{count} tool call",
42+
"countPlural=other": "{count} tool calls"
43+
}
44+
}
45+
]
46+
}
47+
```
48+
49+
Call with a number:
50+
51+
```ts
52+
m.tool_call_group_call_count({ count: 3 });
53+
```
54+
55+
For `zh-CN`, use the same declaration and provide the matching locale text; a
56+
single `other` or wildcard branch is often enough only when the locale truly has
57+
no visible plural distinction.
58+
59+
## Ordinals
60+
61+
Use `type=ordinal` for values such as 1st, 2nd, and 3rd.
62+
63+
```json
64+
{
65+
"ranking_place": [
66+
{
67+
"declarations": [
68+
"input place",
69+
"local placePlural = place: plural type=ordinal"
70+
],
71+
"selectors": ["placePlural"],
72+
"match": {
73+
"placePlural=one": "{place}st",
74+
"placePlural=two": "{place}nd",
75+
"placePlural=few": "{place}rd",
76+
"placePlural=*": "{place}th"
77+
}
78+
}
79+
]
80+
}
81+
```
82+
83+
## Date And Time
84+
85+
For dates inside translatable copy, use the Paraglide `datetime` formatter in the
86+
message declaration so locale formatting and word order stay in the catalog.
87+
88+
```json
89+
{
90+
"session_started_at": [
91+
{
92+
"declarations": [
93+
"input startedAt",
94+
"local started = startedAt: datetime dateStyle=medium timeStyle=short"
95+
],
96+
"match": {
97+
"startedAt=*": "Started {started}"
98+
}
99+
}
100+
]
101+
}
102+
```
103+
104+
For standalone visible date/time labels in components, use the app helper:
105+
106+
```ts
107+
import { formatDateTime } from "../../i18n/index.js";
108+
109+
formatDateTime(timestamp, {
110+
month: "short",
111+
day: "numeric",
112+
timeZone,
113+
});
114+
```
115+
116+
Do not hard-code `"en"` or `"en-US"` for visible UI formatting. It is acceptable
117+
to use a fixed locale for internal sentinel calculations when the formatted
118+
string is not displayed.
119+
120+
## Relative Dates
121+
122+
Use Paraglide's `relativetime` formatter. The `unit` option is required.
123+
124+
```json
125+
{
126+
"status_bar_synced_ago": [
127+
{
128+
"declarations": [
129+
"input duration",
130+
"local formattedDuration = duration: relativetime unit=minute numeric=auto"
131+
],
132+
"match": {
133+
"duration=*": "synced {formattedDuration}"
134+
}
135+
}
136+
]
137+
}
138+
```
139+
140+
Use a variable unit only when the caller computes the unit intentionally:
141+
142+
```json
143+
{
144+
"updated_relative": [
145+
{
146+
"declarations": [
147+
"input duration",
148+
"input unit",
149+
"local formattedDuration = duration: relativetime unit=$unit style=short"
150+
],
151+
"match": {
152+
"duration=*,unit=*": "Updated {formattedDuration}"
153+
}
154+
}
155+
]
156+
}
157+
```
158+
159+
## Numbers And Currency
160+
161+
Prefer Paraglide's `number` formatter for numbers embedded in messages:
162+
163+
```json
164+
{
165+
"usage_total_cost": [
166+
{
167+
"declarations": [
168+
"input amount",
169+
"local cost = amount: number style=currency currency=USD"
170+
],
171+
"match": {
172+
"amount=*": "Total cost {cost}"
173+
}
174+
}
175+
]
176+
}
177+
```
178+
179+
Use raw `toLocaleString()` only for non-sentence labels where the browser or
180+
app-level locale behavior is already intentional.

0 commit comments

Comments
 (0)