diff --git a/AGENTS.md b/AGENTS.md index 133323e..d5e9abb 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -435,3 +435,42 @@ mid-refactor). The footer is not a gate — it is a record. Other agents picking up this repo mid-session can read the git log and immediately know the state of the codebase at each commit without re-running the full suite to establish a baseline. + +--- + +## UTF-8 compliance + +**Rule: always write UTF-8 to `~/.login_conf`. Never write a legacy charset.** + +### `~/.login_conf` format + +``` +me:\ + :charset=UTF-8:\ + :lang=sl_SI.UTF-8: +``` + +The `lang` tag must end in `.UTF-8`. The `charset` field must be `UTF-8`. +Never write `ISO8859-2`, `ISO-8859-2`, `latin2`, or any other non-UTF-8 +encoding — doing so silently breaks Slovenian character rendering (č/š/ž +appear as `_`) in every terminal session until manually corrected. + +### Normalisation rule for `applyHostLocale()` + +Strip any existing charset suffix from the detected locale tag, then +append `.UTF-8`. For example: + +| Detected | Written | +|----------|---------| +| `sl_SI` | `sl_SI.UTF-8` | +| `sl_SI.ISO8859-2` | `sl_SI.UTF-8` | +| `sl_SI.UTF-8` | `sl_SI.UTF-8` | +| `en_US.UTF-8` | `en_US.UTF-8` | + +### After writing `~/.login_conf` + +Always run `cap_mkdb ~/.login_conf` to rebuild the binary database. +The new locale takes effect on the **next login** — a new tmux window, +new SSH session, or `exec $SHELL -l`. **Never suggest `tmux kill-server`** +to activate locale changes; that destroys the user's entire working +environment. diff --git a/setup/onboarding.ts b/setup/onboarding.ts index 36a325e..544d893 100644 --- a/setup/onboarding.ts +++ b/setup/onboarding.ts @@ -274,9 +274,13 @@ function writeIdentity(envFile: string, agentName: string, assistantName: string function applyHostLocale(systemLocale: string): boolean { try { + // Always normalise to UTF-8 — strip any non-UTF-8 charset suffix and + // rewrite the locale tag with .UTF-8 so ~/.login_conf never locks the + // user into a legacy encoding like ISO8859-2. const dotIdx = systemLocale.indexOf('.'); - const charset = dotIdx !== -1 ? systemLocale.slice(dotIdx + 1) : 'UTF-8'; - const content = `me:\\\n\t:charset=${charset}:\\\n\t:lang=${systemLocale}:\n`; + const baseLocale = dotIdx !== -1 ? systemLocale.slice(0, dotIdx) : systemLocale; + const normalizedLocale = `${baseLocale}.UTF-8`; + const content = `me:\\\n\t:charset=UTF-8:\\\n\t:lang=${normalizedLocale}:\n`; const loginConfPath = path.join(os.homedir(), '.login_conf'); fs.writeFileSync(loginConfPath, content, { encoding: 'utf-8' }); execFileSync('cap_mkdb', [loginConfPath], { stdio: 'ignore' }); @@ -791,7 +795,7 @@ export async function run(args: string[]): Promise { runBsddialog([ '--title', 'Host Locale Set', '--msgbox', - `Locale set to ${systemLocale}.\n\nWritten to ~/.login_conf.\n\nRespawn tmux to activate:\n tmux kill-server && tmux`, + `Locale set to ${systemLocale} (normalised to UTF-8).\n\nWritten to ~/.login_conf.\n\nOpen a new tmux window or fresh SSH login to activate.`, '0', '0', ]); } @@ -891,7 +895,7 @@ export async function run(args: string[]): Promise { const hostLocaleApplied = applyHostLocale(systemLocale); if (hostLocaleApplied) { console.log( - `Locale set to ${systemLocale} in ~/.login_conf. Respawn tmux to activate: tmux kill-server && tmux`, + `Locale set to ${systemLocale} (normalised to UTF-8) in ~/.login_conf. Open a new tmux window or fresh SSH login to activate.`, ); }