コンテンツにスキップ

テーマリファレンス

このドキュメントでは、現在のコーディングエージェントにおけるテーマの仕組みについて説明します:スキーマ、読み込み、ランタイムの動作、および障害モードについて記載しています。

テーマシステムが制御するもの

Section titled “テーマシステムが制御するもの”

テーマシステムは以下を制御します:

  • TUI全体で使用される前景色/背景色のカラートークン
  • Markdownスタイルアダプター(getMarkdownTheme()
  • セレクター/エディター/設定リストアダプター(getSelectListTheme()getEditorTheme()getSettingsListTheme()
  • シンボルプリセット+シンボルオーバーライド(unicodenerdascii
  • ネイティブハイライター(@f5-sales-demo/pi-natives)が使用する構文ハイライトカラー
  • ステータスラインセグメントの色

主な実装:src/modes/theme/theme.ts

テーマファイルは、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[39m、背景は\x1b[49m)を意味します

以下のトークンはすべてcolorsで必須です。

accentborderborderAccentborderMutedsuccesserrorwarningmuteddimtextthinkingText

selectedBguserMessageBgcustomMessageBgtoolPendingBgtoolSuccessBgtoolErrorBgstatusLineBg

メッセージ/ツールテキスト(5)

Section titled “メッセージ/ツールテキスト(5)”

userMessageTextcustomMessageTextcustomMessageLabeltoolTitletoolOutput

mdHeadingmdLinkmdLinkUrlmdCodemdCodeBlockmdCodeBlockBordermdQuotemdQuoteBordermdHrmdListBullet

ツールdiff+構文ハイライト(12)

Section titled “ツールdiff+構文ハイライト(12)”

toolDiffAddedtoolDiffRemovedtoolDiffContextsyntaxCommentsyntaxKeywordsyntaxFunctionsyntaxVariablesyntaxStringsyntaxNumbersyntaxTypesyntaxOperatorsyntaxPunctuation

thinkingOffthinkingMinimalthinkingLowthinkingMediumthinkingHighthinkingXhighbashModepythonMode

ステータスラインセグメントの色(14)

Section titled “ステータスラインセグメントの色(14)”

statusLineSepstatusLineModelstatusLinePathstatusLineGitCleanstatusLineGitDirtystatusLineContextstatusLineSpendstatusLineStagedstatusLineDirtystatusLineUntrackedstatusLineOutputstatusLineCoststatusLineSubagents

HTMLエクスポートのテーマヘルパーに使用されます:

  • export.pageBg
  • export.cardBg
  • export.infoBg

省略した場合、エクスポートコードは解決済みテーマカラーからデフォルトを導出します。

  • symbols.presetはテーマレベルのデフォルトシンボルセットを設定します。
  • symbols.overridesは個別のSymbolKey値をオーバーライドできます。

ランタイムの優先順位:

  1. 設定のsymbolPresetオーバーライド(設定されている場合)
  2. テーマJSONのsymbols.preset
  3. フォールバック "unicode"

無効なオーバーライドキーは無視され、ログに記録されます(logger.debug)。

ビルトインテーマとカスタムテーマのソース

Section titled “ビルトインテーマとカスタムテーマのソース”

テーマの検索順序(loadThemeJson):

  1. ビルトイン埋め込みテーマ(defaults/xcsh-dark.jsondefaults/xcsh-light.jsondefaultThemesにコンパイル済み)
  2. カスタムテーマファイル:<customThemesDir>/<name>.json

カスタムテーマディレクトリはgetCustomThemesDir()から取得されます:

  • デフォルト:~/.xcsh/agent/themes
  • PI_CODING_AGENT_DIRでオーバーライド($PI_CODING_AGENT_DIR/themes

getAvailableThemes()はビルトイン+カスタムのマージされた名前をソートして返し、名前が衝突した場合はビルトインが優先されます。

カスタムテーマファイルの場合:

  1. JSONを読み取り
  2. JSONをパース
  3. ThemeJsonSchemaに対して検証
  4. vars参照を再帰的に解決
  5. 解決された値をターミナルのカラーモードに応じてANSIに変換

検証の動作:

  • 必須カラートークンの欠落:明示的なグループ化されたエラーメッセージ
  • 不正なトークンの型/値:JSONパス付きの検証エラー
  • 不明なテーマファイル:Theme not found: <name>

変数参照の動作:

  • ネストされた参照をサポート
  • 存在しない変数参照でスロー
  • 循環参照でスロー

ターミナルカラーモードの動作

Section titled “ターミナルカラーモードの動作”

カラーモード検出(detectColorMode):

  • COLORTERM=truecolor|24bit => truecolor
  • WT_SESSION => truecolor
  • TERMdumblinux、または空 => 256color
  • それ以外 => truecolor

変換の動作:

  • hex -> Bun.color(..., "ansi-16m" | "ansi-256")
  • numeric -> 38;5 / 48;5 ANSI
  • "" -> デフォルトfg/bgリセット

main.tsは以下の設定でテーマを初期化します:

  • symbolPreset
  • colorBlindMode
  • theme.dark
  • theme.light

自動テーマスロット選択はCOLORFGBGの背景検出を使用します:

  • COLORFGBGから背景インデックスをパース
  • < 8 => ダークスロット(theme.dark
  • >= 8 => ライトスロット(theme.light
  • パース失敗 => ダークスロット

設定スキーマの現在のデフォルト:

  • theme.dark = "xcsh-dark"
  • theme.light = "xcsh-light"
  • symbolPreset = "unicode"
  • colorBlindMode = false
  • 選択されたテーマを読み込み
  • グローバルthemeシングルトンを更新
  • オプションでウォッチャーを開始
  • onThemeChangeコールバックをトリガー

失敗時:

  • ビルトインdarkにフォールバック
  • { success: false, error }を返却

プレビュー切り替え(previewTheme

Section titled “プレビュー切り替え(previewTheme)”
  • 一時的なプレビューテーマをグローバルthemeに適用
  • それ自体は永続化された設定を変更しません
  • フォールバック置換なしでsuccess/errorを返却

設定UIはこれをライブプレビューに使用し、キャンセル時に以前のテーマを復元します。

ウォッチャーとライブリロード

Section titled “ウォッチャーとライブリロード”

ウォッチャーが有効な場合(setTheme(..., true) / インタラクティブ初期化):

  • カスタムファイルパス<customThemesDir>/<currentTheme>.jsonのみを監視
  • ビルトインは実質的に監視されない
  • ファイルchange:リロードを試行(デバウンス付き)
  • ファイルrename/削除:darkにフォールバックし、ウォッチャーを閉じる

自動モードはSIGWINCHリスナーもインストールし、ターミナルの状態が変化したときにダーク/ライトスロットのマッピングを再評価できます。

colorBlindModeはランタイムで1つのトークンのみ変更します:

  • toolDiffAddedがHSV調整されます(緑が青方向にシフト)
  • 調整は解決された値が16進文字列の場合にのみ適用されます

その他のトークンは変更されません。

テーマ関連の設定はSettingsによってグローバル設定YAMLに永続化されます:

  • パス:<agentDir>/config.yml
  • デフォルトのエージェントディレクトリ:~/.xcsh/agent
  • 実効デフォルトファイル:~/.xcsh/agent/config.yml

永続化されるキー:

  • theme.dark
  • theme.light
  • symbolPreset
  • colorBlindMode

レガシー移行が存在します:古いフラットなtheme: "name"は、輝度検出に基づいてネストされたtheme.darkまたはtheme.lightに移行されます。

カスタムテーマの作成(実践編)

Section titled “カスタムテーマの作成(実践編)”
  1. カスタムテーマディレクトリにファイルを作成します(例:~/.xcsh/agent/themes/my-theme.json)。
  2. name、任意のvars、およびすべての必須colorsトークンを含めます。
  3. オプションでsymbolsexportを含めます。
  4. どの自動スロットに割り当てるかに応じて、設定(Display -> Dark themeまたはDisplay -> Light theme)でテーマを選択します。

最小限のスケルトン。colorsのすべてのキーが必須です — ランタイムバリデーター (additionalProperties: false)は、欠落キーと不明なキーの両方を拒否します。 出荷済みのリファレンス実装については packages/coding-agent/src/modes/theme/defaults/xcsh-dark.json およびxcsh-light.jsonを参照してください。

ステータスラインには、issue #242で文書化された2つの並列カラーシステムがあります:

  • 16進テキストカラー(statusLinePathstatusLineGitCleanstatusLineGitDirtystatusLineStagedstatusLineDirtystatusLineUntracked)は非powerline レンダリングを駆動します。
  • 256色パレットインデックス(statusLine<Segment>Bg / statusLine<Segment>Fg)は powerlineセグメントの塗りつぶしを駆動します。これらは上記の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
}
}

以下のワークフローを使用してください:

  1. インタラクティブモードで起動します(起動時にウォッチャーが有効)。
  2. 設定を開き、テーマの値をプレビューします(ライブpreviewTheme)。
  3. カスタムテーマファイルの場合、実行中にJSONを編集し、保存時の自動リロードを確認します。
  4. 重要な画面を検証します:
    • Markdownレンダリング
    • ツールブロック(保留中/成功/エラー)
    • diffレンダリング(追加/削除/コンテキスト)
    • ステータスラインの可読性
    • 思考レベルのボーダー変更
    • bash/pythonモードのボーダー色
  5. テーマがグリフの幅/外観に依存する場合は、両方のシンボルプリセットを検証してください。
  • カスタムテーマでは、すべてのcolorsトークンが必須です。
  • exportsymbolsは任意です。
  • テーマJSON内の$schemaは情報提供のみです。ランタイム検証はコード内のコンパイル済みTypeBoxスキーマによって実施されます。
  • setThemeの失敗はdarkにフォールバックします。previewThemeの失敗は現在のテーマを置換しません。
  • ファイルウォッチャーのリロードエラーが発生した場合、リロードが成功するかフォールバックパスがトリガーされるまで、現在読み込まれているテーマが維持されます。