feat: per-tool settings, persistent settings file, Codex and Antigravity sessions, tokens and hooks (#40 B, C1, C2, D)

Part B: Model Pricing, Hook Configuration and CLAUDE_HOME move from
Settings → Dashboard to the Claude Code tab's AgentHub sub-tab
(ClaudeAgentHubSettings.tsx); CODEX_HOME is editable in Codex → AgentHub.
A home that is or contains the OS home is refused (EBADHOME).

Settings persistence: dashboard-saved settings go to
~/.config/agenthub/settings.env (AGENTHUB_SETTINGS_FILE), outside the plugin
cache an update wipes. Load order: real env > the checkout's .env > that file.
The first CLAUDE_HOME change pins DASHBOARD_DATA_DIR so the DB stays put.

C1: codex-usage.js reads Codex rollout journals into sessions (new column
tool) and token_usage, tracked per file in codex_rollouts; forks deduped by
total vector, sub-agent threads folded into the root; pricing-sync also
prices OpenAI models; PricingSettings with a vendor filter.

C2: codex-hooks.js installs AgentHub's hooks into $CODEX_HOME/hooks.json on
a click, through a stable forwarder; Codex trust is never written. The hook
route creates tool='codex' sessions and folds sub-agent hooks into the root.

D: antigravity-usage.js reads agy's per-conversation SQLite files (tokens
from ModelUsageStats) into tool='antigravity' sessions; antigravity-hooks.js
installs the named hook `agenthub` (PreInvocation, PostToolUse, Stop — never
PreToolUse) into ~/.gemini/config/hooks.json; Settings → Antigravity tab;
Gemini pricing.

Whole-change review fixes: sameOriginGuard on both home PUTs, routers.missing
on a CLAUDE_HOME change, reset-pricing scope, GET /api/sessions?tool=,
clear-data covering the new tables, Codex child-thread events moving no
status, hooks owning status only while current, EFOREIGN for a forwarder
that is not ours, agy quiet window and turn rules, AGENTHUB_SETTINGS_FILE
honoured from .env.

Docs, OpenAPI and the CLAUDE.md marker updated. Server 2141, client 779.
This commit is contained in:
2026-09-29 16:09:19 +07:00
parent 7ec5a7cd85
commit 969b06253c
95 changed files with 9278 additions and 1696 deletions
+14 -27
View File
@@ -2,7 +2,7 @@
This guide documents how localization works in the Agent Dashboard, including architecture, resources, runtime behavior, testing, and rollout.
**Supported languages:** English (`en`), Chinese (`zh`), Vietnamese (`vi`), Korean (`ko`)
**Supported languages:** English (`en`), Vietnamese (`vi`)
---
@@ -36,7 +36,7 @@ flowchart TB
```
**Key runtime facts**
- `supportedLngs`: `["en", "zh", "vi", "ko"]`
- `supportedLngs`: `["en", "vi"]`
- `fallbackLng`: `"en"`
- `nonExplicitSupportedLngs`: `true` (e.g. `vi-VN` resolves to `vi`)
- Detection order: `localStorage` → `navigator`
@@ -48,9 +48,7 @@ flowchart TB
Translation resources are stored per language and namespace:
- `client/src/i18n/locales/en/*.json`
- `client/src/i18n/locales/zh/*.json`
- `client/src/i18n/locales/vi/*.json`
- `client/src/i18n/locales/ko/*.json`
Active namespaces:
- `common`
@@ -71,8 +69,8 @@ erDiagram
KEY ||--o{ TRANSLATION : maps_to
LANGUAGE {
string code "en|zh|vi"
string locale "en-US|zh-CN|vi-VN|ko-KR"
string code "en|vi"
string locale "en-US|vi-VN"
}
NAMESPACE {
string name "common|nav|dashboard|..."
@@ -89,7 +87,7 @@ erDiagram
**Strategy notes**
- Keep namespace boundaries page/domain focused.
- Keep key parity across `en`, `zh`, `vi` files for the same namespace.
- Keep key parity across `en` and `vi` files for the same namespace.
- Keep fallback behavior deterministic by ensuring `en` is always complete.
---
@@ -116,7 +114,7 @@ Use stable semantic keys, not English sentence literals.
```mermaid
classDiagram
class I18nConfig {
+supportedLngs: ["en","zh","vi"]
+supportedLngs: ["en","vi"]
+fallbackLng: "en"
+defaultNS: "common"
+detectionOrder: ["localStorage","navigator"]
@@ -184,19 +182,11 @@ sequenceDiagram
stateDiagram-v2
[*] --> Detecting
Detecting --> Loaded_en: localStorage/navigator resolves en
Detecting --> Loaded_zh: localStorage/navigator resolves zh
Detecting --> Loaded_vi: localStorage/navigator resolves vi
Detecting --> Loaded_ko: localStorage/navigator resolves ko
Detecting --> Loaded_en: unsupported locale -> fallback en
Loaded_en --> Loaded_zh: user switches to zh
Loaded_en --> Loaded_vi: user switches to vi
Loaded_zh --> Loaded_en: user switches to en
Loaded_zh --> Loaded_vi: user switches to vi
Loaded_vi --> Loaded_en: user switches to en
Loaded_vi --> Loaded_zh: user switches to zh
Loaded_en --> Loaded_ko: user switches to ko
Loaded_ko --> Loaded_en: user switches to en
```
---
@@ -205,14 +195,13 @@ stateDiagram-v2
Formatting utilities are centralized in `client/src/lib/format.ts`.
- `en` → `en-US`
- `zh` → `zh-CN`
- `en` → `en-US` (also the default for any other language)
- `vi` → `vi-VN`
`formatTime`, `formatDateTime`, and `fmtCostFull` use locale-aware `toLocale*` APIs.
Timestamp parsing normalizes timezone-less SQLite datetime strings to UTC before display formatting.
`formatModelName` converts raw model identifiers (e.g. `claude-opus-4-7-20260101`, `claude-opus-4-7[1m]`) into human-friendly display names (e.g. "Claude Opus 4.7", "Claude Opus 4.7 (1M)"). This is locale-independent (brand names are proper nouns) and is applied across all UI surfaces except the Settings page (which shows raw patterns for pricing rule configuration).
`formatModelName` converts raw model identifiers (e.g. `claude-opus-4-7-20260101`, `claude-opus-4-7[1m]`) into human-friendly display names (e.g. "Claude Opus 4.7", "Claude Opus 4.7 (1M)"). This is locale-independent (brand names are proper nouns) and is applied across all UI surfaces except the Model Pricing table (Settings → Claude Code → AgentHub, Settings → Codex → AgentHub and Settings → Antigravity), which shows raw patterns for pricing rule configuration.
```mermaid
flowchart LR
@@ -220,10 +209,8 @@ flowchart LR
B --> C["getCurrentLanguage()"]
C --> D{"Language"}
D -->|en| E["Locale en-US"]
D -->|zh| F["Locale zh-CN"]
D -->|vi| G["Locale vi-VN"]
E --> H["toLocaleTimeString / toLocaleString"]
F --> H
G --> H
H --> I["Localized date/time/number output"]
```
@@ -248,10 +235,10 @@ npm run test:client
| Area | What to verify | Example |
|---|---|---|
| Resource parity | Same key coverage across `en/zh/vi/ko` | Missing key detection in CI |
| Resource parity | Same key coverage across `en/vi` | Missing key detection in CI |
| Locale fallback | Unknown locales fall back to `en` | `vi-VN` resolves to `vi` |
| Terminology consistency | Canonical terms stay stable | `Agent`/`Subagent` expectations |
| Date/number formatting | Locale-specific output shape | `zh-CN`, `vi-VN`, `ko-KR` formatting |
| Date/number formatting | Locale-specific output shape | `en-US`, `vi-VN` formatting |
| Runtime switching | UI rerenders without reload | Sidebar language toggle |
---
@@ -261,7 +248,7 @@ npm run test:client
| Symptom | Likely cause | Resolution |
|---|---|---|
| UI stays in old language after switch | Cached key or stale component state | Confirm `i18n.changeLanguage(...)` is called and component uses `useTranslation` |
| Unexpected fallback to English | Unsupported locale code | Ensure code normalizes to `en|zh|vi|ko` and key exists in target namespace |
| Unexpected fallback to English | Unsupported locale code | Ensure code normalizes to `en|vi` and key exists in target namespace |
| Missing text on one page | Namespace file key missing | Add key to all language files for that namespace |
| Date/time looks wrong | Locale mapping or timezone parse issue | Verify `getCurrentLocale()` and `parseDate()` behavior |
| Inconsistent term translation | Manual translation drift | Enforce glossary and update locale tests |
@@ -278,7 +265,7 @@ gantt
section Resource Preparation
Lock key inventory :a1, 2026-01-01, 3d
Fill en/zh/vi/ko namespace files :a2, after a1, 5d
Fill en/vi namespace files :a2, after a1, 5d
section Runtime Integration
Wire detection + persistence :b1, after a2, 2d
@@ -295,10 +282,10 @@ gantt
```
### Operational checklist
- [ ] Confirm all namespaces exist for `en`, `zh`, `vi`, `ko`
- [ ] Confirm all namespaces exist for `en` and `vi`
- [ ] Confirm key parity across all locale JSON files
- [ ] Confirm language switching works in collapsed and expanded sidebar modes
- [ ] Confirm fallback behavior for region tags (e.g., `vi-VN`, `zh-CN`)
- [ ] Confirm fallback behavior for region tags (e.g., `vi-VN`, `en-US`)
- [ ] Confirm date/time/currency formatting for all supported languages
- [ ] Confirm client tests pass before release
- [ ] Confirm docs references are updated (`README`, `ARCHITECTURE`, `docs/README`)