Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@
# AGENTMEMORY_IMPORT_TIMEOUT_MS=120000 # import-jsonl POST timeout
# AGENTMEMORY_URL=http://localhost:3111 # REST base URL — honored by status, doctor, MCP shim
# AGENTMEMORY_VIEWER_URL=http://localhost:3113 # Override the viewer URL printed by `agentmemory status`
# VIEWER_LANGUAGE=zh-CN # Startup default for the viewer UI; users can switch in the viewer header
# AGENTMEMORY_EXPORT_ROOT=~/agentmemory-backup # Default destination for `agentmemory export`
# AGENTMEMORY_BACKUP_ENABLED=true # Periodically write logical JSON exports
# AGENTMEMORY_BACKUP_DIR=~/.agentmemory/backups # Required when scheduled backups are enabled
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1282,6 +1282,8 @@ Auto-starts on port `3113`. Live observation stream, session explorer, memory br
open http://localhost:3113
```

The viewer ships English and Simplified Chinese UI strings. It auto-selects Chinese for Chinese browser language preferences when no local viewer preference has been saved, and the header language selector persists your choice in the browser. Operators can also set the startup default with `VIEWER_LANGUAGE=zh` or `VIEWER_LANGUAGE=zh-CN`.

The viewer server binds to `127.0.0.1` by default. The REST-served `/agentmemory/viewer` endpoint follows the normal `AGENTMEMORY_SECRET` bearer-token rules. CSP headers use a per-response script nonce and disable inline handler attributes (`script-src-attr 'none'`).

---
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Issue 288 Arena Synthesis

Artifact: issue-validity and fix-direction decision for GitHub issue #288.

Rubric:
- Issue evidence accuracy.
- Current-code reproduction clarity.
- Duplicate/staleness diligence.
- Scoped fix direction.
- Verification specificity.

## Candidate Scores

| Candidate | Score | Summary |
| --- | ---: | --- |
| A | 23/25 | Correctly identified partial existing Chinese locale support and remaining coverage gaps; strongest route/build inventory. |
| B | 25/25 | Clearest conclusion: valid unresolved coverage/discoverability gap, not fixed, with practical implementation direction. |
| C | 21/25 | Strong rendered-output proof and font/search nuance, but verification attempt caused ignored dependency artifacts. |

## Pick

Base: Candidate B.

Reason: Candidate B best distinguishes existing i18n foundation from the unresolved user-facing gap. It recommends a scoped fix that does not require API, auth, schema, dependency, or architecture changes.

## Grafts

- From Candidate A: keep the route/build inventory in scope and remember that the shipped legacy viewer remains the production surface while the Vue/Vite app is preview-only.
- From Candidate A: do not import upstream PR #673 wholesale; local history already adapted the safe foundation.
- From Candidate C: use rendered-output style checks where practical so tests prove Chinese surfaces are reachable, not just locale files exist.
- From Candidate C: CJK search is separate from UI localization and must not be treated as closing this issue.
- From Candidate C: font fallback can improve Chinese readability, but font-only work does not satisfy the issue by itself.

## Rejections

- Close as already fixed: rejected because major shipped viewer surfaces remain hardcoded English and `VIEWER_LANGUAGE` is not discoverable for ordinary users.
- Close as duplicate without implementation: rejected because the current request requires a Human Checkpoint for duplicate closure and the arena found valid unresolved scope.
- Replace the viewer architecture: rejected because issue #148 owns the Vue/Vite migration and the shipped viewer remains `src/viewer/index.html`.
- Add runtime machine translation or external services: rejected because checked-in locale strings are safer and avoid privacy/CSP/network consequences.

## Decision

Proceed with a scoped valid-issue implementation:
- expose bundled locales to the browser safely;
- add a visible language selector with local persistence and Chinese-browser preference handling;
- expand Chinese locale keys for representative Dashboard and Memories surfaces;
- document `VIEWER_LANGUAGE=zh` / `zh-CN` and the in-viewer picker.

Verification must preserve existing CSP/nonced-script behavior, translated-attribute allowlist restrictions, viewer layout, and package build behavior.
249 changes: 249 additions & 0 deletions docs/todos/2026-06-19-issue-288-web-display-issue/plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
# Issue 288 Viewer Chinese Localization Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Make the shipped viewer's Chinese localization directly selectable and more complete on high-traffic Dashboard and Memories surfaces.

**Architecture:** Keep the existing nonced locale injection and static legacy viewer. Extend the injected locale bundle with bundled `available` locale data, add client-side locale selection/localStorage/browser-language resolution, and route representative Dashboard/Memories strings through existing safe translation helpers.

**Tech Stack:** TypeScript, static HTML/JavaScript viewer, JSON locale files, Vitest, pnpm.

---

## Files

- Modify: `src/viewer/locales.ts`
- Modify: `src/viewer/index.html`
- Modify: `src/viewer/locales/en.json`
- Modify: `src/viewer/locales/zh.json`
- Modify: `test/viewer-i18n.test.ts`
- Modify: `test/viewer-security.test.ts`
- Modify: `README.md`
- Modify: `.env.example`
- Modify: `docs/todos/2026-06-19-issue-288-web-display-issue/todo.md`

## Task 1: Red Tests For Switchable Viewer Locales

- [x] **Step 1: Add failing bundle and document tests**

Add tests to `test/viewer-i18n.test.ts` that assert:
- `buildLocaleBundle("en")` exposes `available.en` and `available.zh`.
- the rendered document includes `id="language-select"`.
- the rendered document includes the `agentmemory-viewer-language` storage key and `navigator.languages` browser-language check.
- `zh.json` contains representative Dashboard and Memories keys such as `dashboard.first_run_eyebrow`, `dashboard.cards.sessions`, `memories.search_placeholder`, and `common.delete`.
- the viewer source routes representative Dashboard and Memories HTML-builder strings through escaped `t(...)`: first-run copy, stat labels, Memories search/empty states/table headers, and delete modal copy.
- a viewer sandbox test can render Dashboard/Memories in English, switch to Chinese, and observe representative dynamic text change without a reload.

- [x] **Step 2: Verify red**

Run:

```bash
corepack pnpm exec vitest run test/viewer-i18n.test.ts -t "viewer locale"
```

Expected: fail because `available`, the picker, and new keys do not exist.

Evidence: failed 4 expected tests after deterministic pnpm setup.

## Task 2: Expose Locale Data Safely

- [x] **Step 1: Extend `LocaleBundle`**

Update `src/viewer/locales.ts` so `LocaleBundle` includes:

```ts
available: Record<string, LocaleMessages>;
```

Build it from checked-in `en` and `zh` locale files only. Keep the existing `lang`, `messages`, and `fallback` fields for compatibility.

- [x] **Step 2: Verify green for bundle tests**

Run:

```bash
corepack pnpm exec vitest run test/viewer-i18n.test.ts -t "bundle"
```

Expected: pass for the bundle tests that do not depend on HTML picker code yet.

Evidence: full focused i18n suite passed after implementation.

## Task 3: Add Viewer Language Picker Runtime

- [x] **Step 1: Add picker markup and runtime selection**

Modify `src/viewer/index.html`:
- Add a compact `<select id="language-select">` in `.header-right` with `en` and `zh` options.
- Add `agentmemory-viewer-language` localStorage handling.
- Pick language in this order: valid localStorage preference, Chinese browser language from `navigator.languages`, injected bundle language.
- Re-apply `window.applyI18n(document)` after switching.
- Update `document.documentElement.lang`.
- Re-render already-loaded dynamic surfaces after switching. At minimum, call `renderDashboard()` when `state.dashboard.loaded` is true and `renderMemories()` when `state.memories.loaded` is true.
- Keep the active bundle used by `t(...)` and `tRaw(...)` in sync with the selected language before re-rendering.

- [x] **Step 2: Preserve CSP/attribute safety**

Keep locale JSON inside the existing nonced script. Do not add translated `href`, `src`, event handler, or IDREF attributes.

- [x] **Step 3: Verify picker/security tests**

Run:

```bash
corepack pnpm exec vitest run test/viewer-i18n.test.ts test/viewer-security.test.ts
```

Expected: pass after implementation.

Evidence: focused i18n/security/layout run passed 3 files / 37 tests.

## Task 4: Localize Dashboard And Memories Representative Surfaces

- [x] **Step 1: Add locale keys**

Expand `src/viewer/locales/en.json` and `src/viewer/locales/zh.json` with nested keys for:
- `language`
- `common`
- `dashboard.first_run_*`
- `dashboard.cards.*`
- `dashboard.sections.*`
- `memories.*`

Preserve every placeholder marker across English and Chinese.

- [x] **Step 2: Route Dashboard strings through helpers**

In `src/viewer/index.html`, use escaped `t(...)` for any translated string concatenated into `innerHTML`/modal HTML. Reserve `tRaw(...)` for `textContent`, safe allowlisted attributes, and other non-HTML contexts only.

Use `t(...)` for:
- first-run hero copy;
- stat card labels and subtitles;
- system resource title and labels;
- recent sessions and recent activity titles;
- dashboard table headers and empty states.

Keep backend values such as health state, connection state, operation names, and user data escaped/raw.

- [x] **Step 3: Route Memories strings through helpers**

In `src/viewer/index.html`, use locale helpers for:
- Memories description;
- search placeholder and type filter label;
- loading/empty/no-results copy;
- table headers;
- Delete button;
- Delete Memory modal title, body, Cancel, and Delete buttons.

Use `t(...)` in HTML strings and modal HTML. Use `tRaw(...)` only when assigning an input `placeholder` property or other safe non-HTML text/attribute value.

- [x] **Step 4: Verify focused i18n tests**

Run:

```bash
corepack pnpm exec vitest run test/viewer-i18n.test.ts
```

Expected: pass all locale parity and placeholder parity tests.

Evidence: focused i18n suite passed 17 tests.

- [x] **Step 5: Verify rendered path tests**

Run:

```bash
corepack pnpm exec vitest run test/viewer-i18n.test.ts -t "renders switched Dashboard and Memories copy"
```

Expected: pass because the sandbox renders English first, switches to Chinese, and sees representative Dashboard and Memories copy update.

Evidence: covered by focused i18n suite.

## Task 5: Document Viewer Language Selection

- [x] **Step 1: Update `README.md`**

In the Real-Time Viewer section, add concise docs that the viewer ships English and Simplified Chinese, auto-prefers Chinese browser languages when available, offers an in-viewer language selector, and supports `VIEWER_LANGUAGE=zh` or `VIEWER_LANGUAGE=zh-CN` as the startup default.

- [x] **Step 2: Update `.env.example`**

Add a commented `VIEWER_LANGUAGE=zh-CN` example near viewer runtime settings.

- [x] **Step 3: Verify docs references**

Run:

```bash
rg -n "VIEWER_LANGUAGE|Simplified Chinese|language selector|zh-CN" README.md .env.example
```

Expected: the new docs/config lines are present.

Evidence: command found README and `.env.example` entries.

## Task 6: Stabilization And PR Verification

- [ ] **Step 1: Focused cleanup**

Run a simple-code pass on the touched viewer/i18n files only. Preserve CSP, auth, routing, persistence, API, and build contracts.

- [ ] **Step 2: Run targeted checks**

Run:

```bash
corepack pnpm exec vitest run test/viewer-i18n.test.ts test/viewer-security.test.ts test/viewer-layout.test.ts
corepack pnpm run viewer:test
corepack pnpm run viewer:typecheck
corepack pnpm run build
git diff --check
```

Expected: all exit 0.

- [ ] **Step 3: Run broader checks before PR readiness**

Run:

```bash
corepack pnpm test
semgrep scan --config p/default --error --metrics=off .
```

Expected: all exit 0, or record blockers with closest targeted substitutes.

- [ ] **Step 4: Stage and run required staged secret scan**

Stage only task-owned files, inspect staged diff, then run:

```bash
gitleaks protect --staged --redact
```

Expected: no leaks.

- [ ] **Step 5: Commit**

Commit with:

```bash
git commit -m "fix(viewer): expose Chinese localization in web UI"
```

- [ ] **Step 6: GitHub PR flow**

After green verification and task-state final review notes:
- fetch/merge current `origin/main` per GitHub push preparation;
- push `issue/288-web-display-issue` to `origin`;
- create a PR against `origin/main`;
- merge only after clean/green PR checks;
- archive the current Codex thread after successful merge.

## Self-Review

- Spec coverage: The plan covers valid issue classification, switchable locale bundle, UI selector, browser-language handling, representative Dashboard/Memories localization, docs/config discoverability, and verification.
- Placeholder scan: No `TBD`, `TODO`, or unspecified implementation steps remain.
- Type consistency: The only locale bundle shape change is additive: `available` is added while existing `lang`, `messages`, and `fallback` remain.
Loading
Loading