fix: i18n key path errors, locale drift, and TUI/CLI correctness fixes - #2
Merged
Merged
Conversation
# fix: i18n key path errors, locale drift, and TUI/CLI correctness fixes
## Summary
Static analysis of the fork found a cluster of user-facing bugs: several TUI
screens render raw i18n key paths instead of text, the Astron settings panel
is completely untranslated (and gets wiped by unrelated config saves), the
`/workflow` help prints `undefined`, and an 80 ms footer timer runs forever
once thinking effort is enabled.
All fixes are minimal, behavior-preserving except where the current behavior
is objectively wrong. Every `t()` key used in the touched files was
machine-verified to resolve in **both** `en` and `zh` runtime locales
(`locales/*.ts`), with placeholder parity.
## Bugs fixed
### 1. i18n key paths pointing at non-existent locations (raw keys shown in UI)
| File | Wrong prefix | Correct prefix | Count |
|---|---|---|---|
| `tui/commands/config.ts` | `tui.dialogs.config.configXxx` | `tui.messages.configXxx` | 41 |
| `migration/migration-screen.ts`, `migration/badge.ts` | `migration.X` | `tui.migration.X` | 34 |
| `tui/components/dialogs/coding-plan-config.ts` | `codingPlan.X` | `tui.codingPlan.X` | 12 |
The Rust translation engine falls back to returning the key itself, so the
config/migration/coding-plan screens currently display strings like
`tui.dialogs.config.configThemeSet` to users.
### 2. Astron settings panel untranslated + locale drift
`astron-settings.ts` references 14 keys under `tui.dialogs.astronSettings.*`
that exist in `locales/*.json` but were never synced into the runtime
`locales/*.ts` sources — the whole panel renders raw key paths. Also missing
in `*.ts`: `settingsSelector.astron/astronDesc` and
`messages.configAstronSaveFailed` (17 keys total, EN+ZH). Reverse drift:
`tui.chrome.footer.swarmPlan` existed only in `*.ts`; added to `*.json`.
`en.json/zh.json` ↔ `en.ts/zh.ts` are now fully in sync.
### 3. Malformed placeholder in zh locale
`zh unsupportedEffort` contained `{{arg}` (missing closing `}}`) — the value
would render literally. Fixed in both `zh.ts` and `zh.json`.
### 4. `/workflow` usage prints `undefined`
`workflow.ts` did `t('tui.slashCommands.workflowHelp') as Record<string,
string>` — `t()` returns a string, so every `wf.*` access was `undefined`.
Replaced with individual leaf-key calls (`workflowHelp.usage`, `.list`, ...).
### 5. `/discuss` prompt-structure injection
User-supplied roles/stances were interpolated into the quoted
`roleDescription`/`assignedStance` strings unescaped, so a `"` in a role name
corrupts the generated prompt. Now escapes `\` and `"` (and removes the dead
`safeName` variable that was computed but never used).
### 6. Changing theme/locale/editor wipes Astron settings
`currentTuiConfig()` hardcoded `astron: DEFAULT_TUI_CONFIG.astron`, so every
`saveTuiConfig` from the theme/locale/editor/update-preference flows reset
the user's Astron parameters to defaults. It is now async and seeds `astron`
from the persisted `tui.toml` (matching how `AstronSettingsComponent` itself
does load-modify-save).
### 7. `createI18n` ignores `initialLocale` when `noDetect` is set
`options.noDetect ? 'en' : (options.initialLocale ?? detectLocaleNode())`
made an explicit `initialLocale` lose to `noDetect`. Priority is now
`initialLocale ?? (noDetect ? 'en' : detectLocaleNode())`. Also exports the
previously instance-only `getMessages`/`translateBatch` at module level, and
fixes a JSDoc example referencing a non-existent key.
### 8. Footer pulse timer runs 12.5×/s forever
`syncPulseTimer(state.thinkingEffort !== 'off')` kept an 80 ms interval alive
permanently once thinking effort was enabled — constant re-renders while
idle. Now tied to actual activity: `thinkingEffort !== 'off' &&
streamingPhase !== 'idle'`.
### 9. Coding-plan editor accepts control keys as text
The input handler appended any non-Enter/Escape data to the field value, so
arrow keys / Tab / Ctrl combos leaked escape bytes (e.g. `\x1b[C`) into
config values. Now uses the codebase-standard `printableCha
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
fix: i18n key path errors, locale drift, and TUI/CLI correctness fixes
Summary
Static analysis of the fork found a cluster of user-facing bugs: several TUI
screens render raw i18n key paths instead of text, the Astron settings panel
is completely untranslated (and gets wiped by unrelated config saves), the
/workflowhelp printsundefined, and an 80 ms footer timer runs foreveronce thinking effort is enabled.
All fixes are minimal, behavior-preserving except where the current behavior
is objectively wrong. Every
t()key used in the touched files wasmachine-verified to resolve in both
enandzhruntime locales(
locales/*.ts), with placeholder parity.Bugs fixed
1. i18n key paths pointing at non-existent locations (raw keys shown in UI)
tui/commands/config.tstui.dialogs.config.configXxxtui.messages.configXxxmigration/migration-screen.ts,migration/badge.tsmigration.Xtui.migration.Xtui/components/dialogs/coding-plan-config.tscodingPlan.Xtui.codingPlan.XThe Rust translation engine falls back to returning the key itself, so the
config/migration/coding-plan screens currently display strings like
tui.dialogs.config.configThemeSetto users.2. Astron settings panel untranslated + locale drift
astron-settings.tsreferences 14 keys undertui.dialogs.astronSettings.*that exist in
locales/*.jsonbut were never synced into the runtimelocales/*.tssources — the whole panel renders raw key paths. Also missingin
*.ts:settingsSelector.astron/astronDescandmessages.configAstronSaveFailed(17 keys total, EN+ZH). Reverse drift:tui.chrome.footer.swarmPlanexisted only in*.ts; added to*.json.en.json/zh.json↔en.ts/zh.tsare now fully in sync.3. Malformed placeholder in zh locale
zh unsupportedEffortcontained{{arg}(missing closing}}) — the valuewould render literally. Fixed in both
zh.tsandzh.json.4.
/workflowusage printsundefinedworkflow.tsdidt('tui.slashCommands.workflowHelp') as Record<string, string>—t()returns a string, so everywf.*access wasundefined.Replaced with individual leaf-key calls (
workflowHelp.usage,.list, ...).5.
/discussprompt-structure injectionUser-supplied roles/stances were interpolated into the quoted
roleDescription/assignedStancestrings unescaped, so a"in a role namecorrupts the generated prompt. Now escapes
\and"(and removes the deadsafeNamevariable that was computed but never used).6. Changing theme/locale/editor wipes Astron settings
currentTuiConfig()hardcodedastron: DEFAULT_TUI_CONFIG.astron, so everysaveTuiConfigfrom the theme/locale/editor/update-preference flows resetthe user's Astron parameters to defaults. It is now async and seeds
astronfrom the persisted
tui.toml(matching howAstronSettingsComponentitselfdoes load-modify-save).
7.
createI18nignoresinitialLocalewhennoDetectis setoptions.noDetect ? 'en' : (options.initialLocale ?? detectLocaleNode())made an explicit
initialLocalelose tonoDetect. Priority is nowinitialLocale ?? (noDetect ? 'en' : detectLocaleNode()). Also exports thepreviously instance-only
getMessages/translateBatchat module level, andfixes a JSDoc example referencing a non-existent key.
8. Footer pulse timer runs 12.5×/s forever
syncPulseTimer(state.thinkingEffort !== 'off')kept an 80 ms interval alivepermanently once thinking effort was enabled — constant re-renders while
idle. Now tied to actual activity:
thinkingEffort !== 'off' && streamingPhase !== 'idle'.9. Coding-plan editor accepts control keys as text
The input handler appended any non-Enter/Escape data to the field value, so
arrow keys / Tab / Ctrl combos leaked escape bytes (e.g.
\x1b[C) intoconfig values. Now uses the codebase-standard
printableCharfilter (pastestill works).
10. Misleading error when resuming a session from another directory
run-v2-print.tsprinted a "created under a different directory" hint onstderr and then threw
Session "..." not found— contradictory. It nowthrows the
sessionDifferentDirmessage (which carries the remediationhint) directly.
Verification
t('<key>')in the touched files resolves to astring in both runtime locales — 0 missing.
en.json/zh.jsonvsen.ts/zh.tsdrift: 0 entries.intentional
{{plural}}omissions in zh, Chinese having no plural form).{{...}}placeholders remain in either locale..tsfiles parse cleanly (node --experimental-strip-types).git apply --checkagainst currentmain.