- 홈
- Documentation
- TUI
- 테마 레퍼런스
테마 레퍼런스
이 문서는 현재 코딩 에이전트에서 테마가 작동하는 방식을 설명합니다: 스키마, 로딩, 런타임 동작, 실패 모드를 포함합니다.
테마 시스템이 제어하는 것
섹션 제목: “테마 시스템이 제어하는 것”테마 시스템이 구동하는 요소:
- TUI 전반에 사용되는 전경/배경 색상 토큰
- 마크다운 스타일링 어댑터 (
getMarkdownTheme()) - 선택기/편집기/설정 목록 어댑터 (
getSelectListTheme(),getEditorTheme(),getSettingsListTheme()) - 심볼 프리셋 + 심볼 오버라이드 (
unicode,nerd,ascii) - 네이티브 하이라이터(
@f5-sales-demo/pi-natives)가 사용하는 구문 강조 색상 - 상태 라인 세그먼트 색상
주요 구현: src/modes/theme/theme.ts.
테마 JSON 구조
섹션 제목: “테마 JSON 구조”테마 파일은 theme.ts의 런타임 스키마(ThemeJsonSchema)에 대해 검증되고 src/modes/theme/theme-schema.json에 미러링되는 JSON 객체입니다.
최상위 필드:
name(필수)colors(필수; 모든 색상 토큰 필수)vars(선택; 재사용 가능한 색상 변수)export(선택; HTML 내보내기 색상)symbols(선택)preset(선택:unicode | nerd | ascii)overrides(선택:SymbolKey에 대한 키/값 오버라이드)
색상 값이 허용하는 형식:
- 16진수 문자열 (
"#RRGGBB") - 256색 인덱스 (
0..255) - 변수 참조 문자열 (
vars를 통해 해석) - 빈 문자열 (
"") - 터미널 기본값을 의미 (\x1b[39mfg,\x1b[49mbg)
필수 색상 토큰 (현재)
섹션 제목: “필수 색상 토큰 (현재)”아래의 모든 토큰은 colors에 필수입니다.
핵심 텍스트 및 테두리 (11)
섹션 제목: “핵심 텍스트 및 테두리 (11)”accent, border, borderAccent, borderMuted, success, error, warning, muted, dim, text, thinkingText
배경 블록 (7)
섹션 제목: “배경 블록 (7)”selectedBg, userMessageBg, customMessageBg, toolPendingBg, toolSuccessBg, toolErrorBg, statusLineBg
메시지/도구 텍스트 (5)
섹션 제목: “메시지/도구 텍스트 (5)”userMessageText, customMessageText, customMessageLabel, toolTitle, toolOutput
마크다운 (10)
섹션 제목: “마크다운 (10)”mdHeading, mdLink, mdLinkUrl, mdCode, mdCodeBlock, mdCodeBlockBorder, mdQuote, mdQuoteBorder, mdHr, mdListBullet
도구 diff + 구문 강조 (12)
섹션 제목: “도구 diff + 구문 강조 (12)”toolDiffAdded, toolDiffRemoved, toolDiffContext,
syntaxComment, syntaxKeyword, syntaxFunction, syntaxVariable, syntaxString, syntaxNumber, syntaxType, syntaxOperator, syntaxPunctuation
모드/사고 테두리 (8)
섹션 제목: “모드/사고 테두리 (8)”thinkingOff, thinkingMinimal, thinkingLow, thinkingMedium, thinkingHigh, thinkingXhigh, bashMode, pythonMode
상태 라인 세그먼트 색상 (14)
섹션 제목: “상태 라인 세그먼트 색상 (14)”statusLineSep, statusLineModel, statusLinePath, statusLineGitClean, statusLineGitDirty, statusLineContext, statusLineSpend, statusLineStaged, statusLineDirty, statusLineUntracked, statusLineOutput, statusLineCost, statusLineSubagents
선택 토큰
섹션 제목: “선택 토큰”export 섹션 (선택)
섹션 제목: “export 섹션 (선택)”HTML 내보내기 테마 헬퍼에 사용됩니다:
export.pageBgexport.cardBgexport.infoBg
생략된 경우, 내보내기 코드는 해석된 테마 색상에서 기본값을 도출합니다.
symbols 섹션 (선택)
섹션 제목: “symbols 섹션 (선택)”symbols.preset은 테마 레벨의 기본 심볼 세트를 설정합니다.symbols.overrides는 개별SymbolKey값을 오버라이드할 수 있습니다.
런타임 우선순위:
- 설정의
symbolPreset오버라이드 (설정된 경우) - 테마 JSON의
symbols.preset - 폴백
"unicode"
유효하지 않은 오버라이드 키는 무시되고 로깅됩니다 (logger.debug).
내장 vs 커스텀 테마 소스
섹션 제목: “내장 vs 커스텀 테마 소스”테마 조회 순서 (loadThemeJson):
- 내장 임베디드 테마 (
defaults/xcsh-dark.json및defaults/xcsh-light.json이defaultThemes로 컴파일됨) - 커스텀 테마 파일:
<customThemesDir>/<name>.json
커스텀 테마 디렉토리는 getCustomThemesDir()에서 가져옵니다:
- 기본값:
~/.xcsh/agent/themes PI_CODING_AGENT_DIR로 오버라이드 가능 ($PI_CODING_AGENT_DIR/themes)
getAvailableThemes()는 내장 + 커스텀 이름을 병합하여 정렬된 결과를 반환하며, 이름 충돌 시 내장 테마가 우선합니다.
로딩, 검증, 해석
섹션 제목: “로딩, 검증, 해석”커스텀 테마 파일의 경우:
- JSON 읽기
- JSON 파싱
ThemeJsonSchema에 대해 검증vars참조를 재귀적으로 해석- 해석된 값을 터미널 기능 모드에 따라 ANSI로 변환
검증 동작:
- 필수 색상 토큰 누락: 명시적 그룹화된 오류 메시지
- 잘못된 토큰 타입/값: JSON 경로가 포함된 검증 오류
- 알 수 없는 테마 파일:
Theme not found: <name>
변수 참조 동작:
- 중첩 참조 지원
- 누락된 변수 참조 시 예외 발생
- 순환 참조 시 예외 발생
터미널 색상 모드 동작
섹션 제목: “터미널 색상 모드 동작”색상 모드 감지 (detectColorMode):
COLORTERM=truecolor|24bit=> truecolorWT_SESSION=> truecolorTERM이dumb,linux, 또는 빈 값 => 256color- 그 외 => truecolor
변환 동작:
- hex ->
Bun.color(..., "ansi-16m" | "ansi-256") - numeric ->
38;5/48;5ANSI ""-> 기본 fg/bg 리셋
런타임 전환 동작
섹션 제목: “런타임 전환 동작”초기 테마 (initTheme)
섹션 제목: “초기 테마 (initTheme)”main.ts는 설정으로 테마를 초기화합니다:
symbolPresetcolorBlindModetheme.darktheme.light
자동 테마 슬롯 선택은 COLORFGBG 배경 감지를 사용합니다:
COLORFGBG에서 배경 인덱스 파싱< 8=> 다크 슬롯 (theme.dark)>= 8=> 라이트 슬롯 (theme.light)- 파싱 실패 => 다크 슬롯
설정 스키마의 현재 기본값:
theme.dark = "xcsh-dark"theme.light = "xcsh-light"symbolPreset = "unicode"colorBlindMode = false
명시적 전환 (setTheme)
섹션 제목: “명시적 전환 (setTheme)”- 선택한 테마를 로드
- 전역
theme싱글턴 업데이트 - 선택적으로 워처 시작
onThemeChange콜백 트리거
실패 시:
- 내장
dark로 폴백 { success: false, error }반환
미리보기 전환 (previewTheme)
섹션 제목: “미리보기 전환 (previewTheme)”- 임시 미리보기 테마를 전역
theme에 적용 - 자체적으로 영속화된 설정을 변경하지 않음
- 폴백 대체 없이 성공/오류 반환
설정 UI는 이를 라이브 미리보기에 사용하고, 취소 시 이전 테마를 복원합니다.
워처 및 라이브 리로드
섹션 제목: “워처 및 라이브 리로드”워처가 활성화된 경우 (setTheme(..., true) / 대화형 초기화):
- 커스텀 파일 경로
<customThemesDir>/<currentTheme>.json만 감시 - 내장 테마는 사실상 감시되지 않음
- 파일
change: 리로드 시도 (디바운스 적용) - 파일
rename/삭제:dark로 폴백, 워처 종료
자동 모드는 SIGWINCH 리스너도 설치하며, 터미널 상태가 변경될 때 다크/라이트 슬롯 매핑을 재평가할 수 있습니다.
색맹 모드 동작
섹션 제목: “색맹 모드 동작”colorBlindMode는 런타임에 하나의 토큰만 변경합니다:
toolDiffAdded가 HSV 조정됨 (녹색이 파란색 쪽으로 이동)- 조정은 해석된 값이 16진수 문자열인 경우에만 적용됨
다른 토큰은 변경되지 않습니다.
테마 설정이 영속화되는 위치
섹션 제목: “테마 설정이 영속화되는 위치”테마 관련 설정은 Settings에 의해 전역 설정 YAML에 영속화됩니다:
- 경로:
<agentDir>/config.yml - 기본 에이전트 디렉토리:
~/.xcsh/agent - 실질적 기본 파일:
~/.xcsh/agent/config.yml
영속화되는 키:
theme.darktheme.lightsymbolPresetcolorBlindMode
레거시 마이그레이션 존재: 이전 플랫 형식 theme: "name"은 휘도 감지를 기반으로 중첩된 theme.dark 또는 theme.light로 마이그레이션됩니다.
커스텀 테마 만들기 (실용)
섹션 제목: “커스텀 테마 만들기 (실용)”- 커스텀 테마 디렉토리에 파일을 생성합니다. 예:
~/.xcsh/agent/themes/my-theme.json. name, 선택적vars, 그리고 모든 필수colors토큰을 포함합니다.- 선택적으로
symbols및export를 포함합니다. - 설정에서 테마를 선택합니다 (
Display -> Dark theme또는Display -> Light theme) - 원하는 자동 슬롯에 따라 선택합니다.
최소 뼈대. colors의 모든 키는 필수입니다 — 런타임 검증기(additionalProperties: false)는 누락된 키와 알 수 없는 키를 모두 거부합니다.
제공된 레퍼런스 구현은
packages/coding-agent/src/modes/theme/defaults/xcsh-dark.json
및 xcsh-light.json을 참조하세요.
상태 라인에는 이슈 #242에 문서화된 두 가지 병렬 색상 시스템이 있습니다:
- 16진수 텍스트 색상 (
statusLinePath,statusLineGitClean,statusLineGitDirty,statusLineStaged,statusLineDirty,statusLineUntracked)은 비-파워라인 렌더링을 구동합니다. - 256색 팔레트 인덱스 (
statusLine<Segment>Bg/statusLine<Segment>Fg)는 파워라인 세그먼트 채우기를 구동합니다. 이들은 위의 16진수 키와 독립적이므로 — 둘 다 설정해야 합니다.
{ "name": "my-theme", "vars": { "accent": "#7aa2f7", "muted": 244 }, "colors": { "accent": "accent", "chromeAccent": "accent", "spinnerAccent": "accent", "contentAccent": "muted", "border": "#4c566a", "borderAccent": "accent", "borderMuted": "muted", "success": "#9ece6a", "error": "#f7768e", "warning": "#e0af68", "muted": "muted", "dim": 240, "gutterSuccess": "#7dcfff", "gutterWarning": "#e0af68", "text": "", "thinkingText": "muted",
"selectedBg": "#2a2f45", "userMessageBg": "#1f2335", "userMessageText": "", "customMessageBg": "#24283b", "customMessageText": "", "customMessageLabel": "accent", "toolPendingBg": "#1f2335", "toolSuccessBg": "#1f2d2a", "toolErrorBg": "#2d1f2a", "toolTitle": "", "toolOutput": "muted",
"mdHeading": "accent", "mdLink": "accent", "mdLinkUrl": "muted", "mdCode": "#c0caf5", "mdCodeBlock": "#c0caf5", "mdCodeBlockBorder": "muted", "mdQuote": "muted", "mdQuoteBorder": "muted", "mdHr": "muted", "mdListBullet": "accent",
"toolDiffAdded": "#9ece6a", "toolDiffRemoved": "#f7768e", "toolDiffContext": "muted",
"syntaxComment": "#565f89", "syntaxKeyword": "#bb9af7", "syntaxFunction": "#7aa2f7", "syntaxVariable": "#c0caf5", "syntaxString": "#9ece6a", "syntaxNumber": "#ff9e64", "syntaxType": "#2ac3de", "syntaxOperator": "#89ddff", "syntaxPunctuation": "#9aa5ce", "syntaxControl": "#bb9af7",
"thinkingOff": 240, "thinkingMinimal": 244, "thinkingLow": "#7aa2f7", "thinkingMedium": "#2ac3de", "thinkingHigh": "#bb9af7", "thinkingXhigh": "#f7768e",
"bashMode": "#2ac3de", "pythonMode": "#bb9af7",
"statusLineBg": "#16161e", "statusLineSep": 240, "statusLineModel": "#bb9af7", "statusLinePath": "#7aa2f7", "statusLineGitClean": "#9ece6a", "statusLineGitDirty": "#e0af68", "statusLineContext": "#2ac3de", "statusLineSpend": "#7dcfff", "statusLineStaged": "#9ece6a", "statusLineDirty": "#e0af68", "statusLineUntracked": "#f7768e", "statusLineOutput": "#c0caf5", "statusLineCost": "#ff9e64", "statusLineSubagents": "#bb9af7",
"statusLineOsIconBg": 7, "statusLineOsIconFg": 232, "statusLinePathBg": 4, "statusLinePathFg": 254, "statusLineGitCleanBg": 2, "statusLineGitCleanFg": 0, "statusLineGitDirtyBg": 3, "statusLineGitDirtyFg": 0, "statusLineGitStagedBg": 64, "statusLineGitStagedFg": 0, "statusLineGitUntrackedBg": 39, "statusLineGitUntrackedFg": 0, "statusLineGitConflictBg": 1, "statusLineGitConflictFg": 7, "statusLinePlanModeBg": 236, "statusLinePlanModeFg": 117, "statusLineProfileXcshBg": "accent", "statusLineProfileXcshFg": 231 }}커스텀 테마 테스트
섹션 제목: “커스텀 테마 테스트”다음 워크플로를 사용하세요:
- 대화형 모드를 시작합니다 (시작 시 워처 활성화).
- 설정을 열고 테마 값을 미리봅니다 (라이브
previewTheme). - 커스텀 테마 파일의 경우, 실행 중에 JSON을 편집하고 저장 시 자동 리로드를 확인합니다.
- 주요 표면을 검증합니다:
- 마크다운 렌더링
- 도구 블록 (대기/성공/오류)
- diff 렌더링 (추가/삭제/컨텍스트)
- 상태 라인 가독성
- 사고 레벨 테두리 변경
- bash/python 모드 테두리 색상
- 테마가 글리프 너비/외관에 의존하는 경우 두 심볼 프리셋을 모두 검증합니다.
실제 제약 사항 및 주의 사항
섹션 제목: “실제 제약 사항 및 주의 사항”- 커스텀 테마에는 모든
colors토큰이 필수입니다. export및symbols는 선택입니다.- 테마 JSON의
$schema는 정보 제공용이며; 런타임 검증은 코드 내 컴파일된 TypeBox 스키마에 의해 강제됩니다. setTheme실패 시dark로 폴백합니다;previewTheme실패 시 현재 테마를 대체하지 않습니다.- 파일 워처 리로드 오류 시 성공적인 리로드 또는 폴백 경로가 트리거될 때까지 현재 로드된 테마를 유지합니다.