-
Notifications
You must be signed in to change notification settings - Fork 2
Description
概要
メッセージ入力欄のスラッシュコマンドセレクターで「Enter custom command...」を選択した後、カスタムコマンドを入力してもEnterキーで送信できない。入力欄に「/」がセットされ文字の追加入力は可能だが、入力のたびにコマンドセレクターが再表示されるため、Enterキーがセレクター操作に消費されて送信されない。CodexとClaude Codeの両方で発生する。
再現手順
- Worktree詳細画面を開く(Codex or Claude Codeセッション)
- メッセージ入力欄に
/を入力し、スラッシュコマンドセレクターを表示 - 「Enter custom command...」ボタンをクリック
- セレクターが閉じ、入力欄に
/がセットされる - 続けてコマンド名を入力(例:
model)→ 入力欄は/modelになる - この時点でコマンドセレクターが再表示される
- Enterキーを押す → セレクターの操作として処理され、メッセージが送信されない
期待する動作
「Enter custom command...」選択後にカスタムコマンド(例: /model gpt-4o)を入力し、Enterキーで正常にCLIセッションへ送信できる。
実際の動作
- 「Enter custom command...」選択後、
/の後に文字を入力するとコマンドセレクターが再度表示される - セレクターが開いている間はEnterキーがセレクター操作に消費され、メッセージ送信ができない
- 結果として、カスタムコマンド機能が実質的に使用不可能な状態
根本原因の仮説
src/components/worktree/MessageInput.tsx L158 の handleMessageChange 内のセレクター表示ロジックに問題がある。
// L157-162
if (newValue === '/' || (newValue.startsWith('/') && !newValue.includes(' '))) {
setShowCommandSelector(true); // ← handleFreeInput()で閉じても再表示される
} else {
setShowCommandSelector(false);
}handleFreeInput()(L141-148)はセレクターを閉じて / をセットするが、その後の入力で handleMessageChange が呼ばれるたびに、メッセージが / で始まりスペースを含まない場合にセレクターが再表示されてしまう。
さらに、src/components/worktree/SlashCommandSelector.tsx のグローバルキーボードリスナー(document.addEventListener('keydown', handleKeyDown) L124-129)が、セレクターが開いている間にEnterキーを e.preventDefault() で消費する。このため、MessageInput.tsx L192 の !showCommandSelector ガードと合わせて、Enterキーイベントがダブルブロックされている。対策案の isFreeInputMode フラグによりセレクターを非表示(isOpen=false)にすれば、このグローバルリスナーも無効化されるため両方の問題が同時に解消される。
対策案
handleFreeInput() 呼び出し時にフリー入力モードのフラグ(例: isFreeInputMode)をセットし、handleMessageChange 内でこのフラグが true の場合はセレクターを再表示しないようにする。
フラグのリセット条件
isFreeInputMode フラグは以下の3つの条件でリセット(false に戻す)する:
submitMessage()時: メッセージ送信完了時にリセット- メッセージが空文字になった時:
handleMessageChange内でnewValue === ''をチェックしてリセット(ユーザーが手動で全削除した場合を含む) handleCommandCancel()時: コマンドセレクターのキャンセル操作時にリセット
handleMessageChange内の処理フロー
const handleMessageChange = (newValue: string) => {
setMessage(newValue);
// フリー入力モードのリセット判定
if (newValue === '') {
setIsFreeInputMode(false);
setShowCommandSelector(false);
return;
}
// フリー入力モード中はセレクター表示をスキップ
if (isFreeInputMode) {
return;
}
// 通常のセレクター表示ロジック
if (newValue === '/' || (newValue.startsWith('/') && !newValue.includes(' '))) {
setShowCommandSelector(true);
} else {
setShowCommandSelector(false);
}
};主な変更点
isFreeInputModeステートの追加(useState<boolean>(false))handleFreeInput()でフラグをtrueに設定handleMessageChange()でフラグtrue時にセレクター表示をスキップ、空文字時にフラグをリセットsubmitMessage()でフラグをリセットhandleCommandCancel()でフラグをリセット
影響範囲
変更対象ファイル
| ファイル | 変更内容 |
|---|---|
src/components/worktree/MessageInput.tsx |
isFreeInputMode ステート追加、handleFreeInput/handleMessageChange/submitMessage/handleCommandCancel の修正 |
関連コンポーネント
src/components/worktree/SlashCommandSelector.tsx(変更不要。isOpen=falseによりグローバルkeydownリスナーのhandleKeyDown内で早期リターン(L95:if (!isOpen) return)されるため、Enterキーイベントが消費されなくなる)src/lib/standard-commands.ts(変更不要だが関連)src/components/worktree/WorktreeDetailRefactored.tsx(変更不要。MessageInputのpropsインターフェースに変更なし。isFreeInputModeは内部状態のため破壊的変更なし)
テスト観点の影響
tests/unit/components/worktree/MessageInput.test.tsx:isFreeInputModeフラグの動作検証テストケースの追加が必要(詳細は受入条件のテスト要件を参照)tests/unit/components/SlashCommandSelector.test.tsx:isOpen=false時にグローバルkeydownリスナーがEnterイベントを消費しないことを検証するテストケースの追加を推奨(現状はisOpen=true時のEscapeキーテストのみ存在)
受入条件
機能要件
- 「Enter custom command...」選択後、カスタムコマンドを入力してEnterキーで送信できる
- カスタムコマンド入力中にコマンドセレクターが再表示されない
- 通常の
/入力時のコマンドセレクター表示は従来通り動作する - Codex・Claude Code両方で正常に動作する
- 既存のスラッシュコマンド選択機能に影響がない
- フリー入力モード中にメッセージを全削除した場合、再度
/を入力するとセレクターが正常に表示される
テスト要件
-
isFreeInputModeフラグの動作を検証するユニットテストがMessageInput.test.tsxに追加されていること。具体的には以下のテストケースを含むこと:- (1)
handleFreeInput呼び出し後にカスタムコマンドを入力してもshowCommandSelectorがfalseのままであること - (2)
handleFreeInput後にEnterキーでsubmitMessageが呼ばれること - (3) メッセージ全削除後に再度
/を入力するとセレクターが表示されること - (4)
submitMessage後にisFreeInputModeがリセットされること
- (1)
レビュー履歴
イテレーション 1 (2026-02-17)
- SF-1: Issueタイトルを問題の本質に合わせて修正(「Codexにてカスタムモデルが利用出来ない」→「Enter custom command選択後、カスタムコマンド入力中にセレクターが再表示されEnterで送信できない」)
- SF-2: 対策案にisFreeInputModeフラグの具体的なリセット条件(submitMessage時/空文字時/handleCommandCancel時)とhandleMessageChange内の処理フローを明記
- SF-3: 根本原因にSlashCommandSelectorのグローバルkeydownリスナーによるEnterキーのe.preventDefault()消費を補足説明として追加
イテレーション 2 (2026-02-17) - 影響範囲レビュー反映
- SF-1: 受入条件に「テスト要件」セクションを追加。isFreeInputModeフラグの動作を検証する具体的なユニットテストケース4項目を明記
- SF-2: 影響範囲に「テスト観点の影響」セクションを追加。MessageInput.test.tsxのテスト追加必要性と、SlashCommandSelector.test.tsxのisOpen=false時のEnterキー透過テスト推奨を記載
- NTH-1: 影響範囲の関連コンポーネントにWorktreeDetailRefactored.tsxへの破壊的変更がない旨を明記