Give the sandbox a UTF-8 locale
A sandbox image ships without a locale, leaving LC_CTYPE at POSIX. Every multibyte glyph then degrades to a placeholder, so Nerd Font icons in the editor render as underscores and bash printf emits \uXXXX escapes literally. The locale is probed for usability rather than matched by name, because locale -a spells C.UTF-8 as C.utf8 on glibc and a name match would silently find nothing. LANG alone is set, leaving individual categories overridable.
This commit is contained in:
@@ -1055,6 +1055,39 @@ EOF
|
|||||||
'
|
'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# A sandbox image ships without a locale, which leaves LC_CTYPE at POSIX. Every
|
||||||
|
# multibyte glyph then degrades to a placeholder: Nerd Font icons in the editor
|
||||||
|
# render as underscores, and bash printf emits \uXXXX escapes literally. LANG
|
||||||
|
# alone is enough, and leaves a user free to override individual categories.
|
||||||
|
install_sandbox_locale() {
|
||||||
|
# shellcheck disable=SC2016
|
||||||
|
sbx exec "$SANDBOX_NAME" bash -c '
|
||||||
|
persistent=/etc/sandbox-persistent.sh
|
||||||
|
marker="# BEGIN ai-sbx locale"
|
||||||
|
|
||||||
|
if grep -Fq "$marker" "$persistent" 2>/dev/null; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# locale -a spells these inconsistently across distributions, so probe
|
||||||
|
# each one for usability rather than matching its name.
|
||||||
|
for candidate in C.UTF-8 en_US.UTF-8; do
|
||||||
|
if LC_ALL="$candidate" locale >/dev/null 2>&1; then
|
||||||
|
chosen="$candidate"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
[[ -n "${chosen:-}" ]] || exit 0
|
||||||
|
|
||||||
|
cat >>"$persistent" <<EOF
|
||||||
|
# BEGIN ai-sbx locale
|
||||||
|
export LANG=$chosen
|
||||||
|
# END ai-sbx locale
|
||||||
|
EOF
|
||||||
|
' </dev/null >/dev/null 2>&1 || true
|
||||||
|
}
|
||||||
|
|
||||||
validate_launch_mode() {
|
validate_launch_mode() {
|
||||||
case "$1" in
|
case "$1" in
|
||||||
agent | tmux) ;;
|
agent | tmux) ;;
|
||||||
@@ -1427,6 +1460,8 @@ run_command() {
|
|||||||
# runs every time rather than only at setup.
|
# runs every time rather than only at setup.
|
||||||
install_sandbox_mise
|
install_sandbox_mise
|
||||||
|
|
||||||
|
install_sandbox_locale
|
||||||
|
|
||||||
if [[ "$launch" == tmux ]]; then
|
if [[ "$launch" == tmux ]]; then
|
||||||
install_sandbox_workspace
|
install_sandbox_workspace
|
||||||
|
|
||||||
|
|||||||
@@ -47,8 +47,12 @@ dispatch() {
|
|||||||
cat "$SBX_LOG"
|
cat "$SBX_LOG"
|
||||||
}
|
}
|
||||||
|
|
||||||
[[ "$DEFAULT_LAUNCH" == agent ]] ||
|
(
|
||||||
fail "AI_SBX_LAUNCH unset should default to agent, got: $DEFAULT_LAUNCH"
|
unset AI_SBX_LAUNCH
|
||||||
|
# shellcheck source=tasks/ai/sbx
|
||||||
|
source "$TASK"
|
||||||
|
[[ "$DEFAULT_LAUNCH" == agent ]]
|
||||||
|
) || fail "AI_SBX_LAUNCH unset should default to agent"
|
||||||
|
|
||||||
(
|
(
|
||||||
AI_SBX_LAUNCH=tmux
|
AI_SBX_LAUNCH=tmux
|
||||||
@@ -87,6 +91,13 @@ DEFAULT_LAUNCH=agent
|
|||||||
[[ "$(dispatch -- --launch tmux)" == *"run ai-test -- --launch tmux"* ]] ||
|
[[ "$(dispatch -- --launch tmux)" == *"run ai-test -- --launch tmux"* ]] ||
|
||||||
fail "--launch after -- belongs to the agent, not to the task"
|
fail "--launch after -- belongs to the agent, not to the task"
|
||||||
|
|
||||||
|
DEFAULT_LAUNCH=agent
|
||||||
|
locale_dispatch="$(dispatch)"
|
||||||
|
[[ "$locale_dispatch" == *"BEGIN ai-sbx locale"* ]] ||
|
||||||
|
fail "run should install a UTF-8 locale, or Nerd Font glyphs render as placeholders: $locale_dispatch"
|
||||||
|
[[ "$locale_dispatch" == *"LC_ALL=\"\$candidate\" locale"* ]] ||
|
||||||
|
fail "the locale must be probed for usability, not matched by name against locale -a"
|
||||||
|
|
||||||
if (validate_launch_mode bogus) 2>/dev/null; then
|
if (validate_launch_mode bogus) 2>/dev/null; then
|
||||||
fail "an unknown launch mode was accepted"
|
fail "an unknown launch mode was accepted"
|
||||||
fi
|
fi
|
||||||
|
|||||||
Reference in New Issue
Block a user