fix: 質問待ちの詳細ビューで会話ログを遡れるようにする(Tab で切替) - #125
Merged
Merged
Conversation
セッション詳細では `pendingPermission` があいだキーを全部 PermissionDialog へ
委譲していたため、↑↓/PgUp/PgDn がすべて選択肢の移動に食われて**会話ログを 1 行も
遡れなかった**。質問の背景(何をしようとしているのか)が分からないまま回答する
しかない状態だったので、一覧の `ListFocus` と同じようにゾーンを分ける。
- `DetailFocus`(dialog / log)を追加し、`Tab` で往復する。既定は `dialog`
(回答は待たせている用事なので、そこへ辿り着くのに Tab を踏ませない)。
- `log` ゾーンでは ↑↓ / PgUp / PgDn がログのスクロールに戻り、ダイアログは
`active={false}` で表示のまま残す(回答の途中経過は内部 state なので
アンマウントしない)。`Esc` とダイアログのクリックでも回答へ戻れる。
- ホイールはゾーンに関係なく通す(押下と違って副作用が無く、背景を読む第一の手段)。
`log` ゾーンでは押下系も通すので範囲選択・URL クリックも普段どおり使える。
- pending が解けたらゾーンは `dialog` へ畳む(次の質問でキーの意味が変わらないように)。
- 「表示のみ」の案内は view から渡す(`inactiveHint`)。一覧の
「↑↓: セッション切替」は詳細では嘘になるため。
takecchi
commented
Aug 13, 2026
takecchi
left a comment
Owner
Author
There was a problem hiding this comment.
レビューしました。追加の指摘事項はありません。LGTM です。
DetailFocus によってダイアログとログのキー操作が明確に分離されており、ダイアログをアンマウントせず active だけを切り替えるため、回答途中の内部状態も保持されます。ホイール、クリック、Esc、Ctrl+C の各経路についても既存の PermissionDialog 側ハンドラーとの競合を確認しましたが、問題は見つかりませんでした。
確認結果:
- 追加された「許可待ちでも Tab でログを遡れ、Tab で回答へ戻れる」テスト成功
npm run typecheck成功npm run build成功- GitHub CI 成功
補足: ローカルで全テストを並列実行した際、今回の差分外にある既存の非同期テストがタイミング依存で失敗しました(hooks.spec.tsx 3件、app.test.tsx 5件)。hooks.spec.tsx は単独再実行で 7/7 成功し、対象の新規統合テストも成功しているため、本PRの不具合とは判断していません。
takecchi
added a commit
that referenced
this pull request
Aug 20, 2026
## 背景(報告された問題)
「ask が画面に出ているとき、下の詳細ログは隠れるのか」を調べたところ、**重なるのではなく押し潰されて**いました。ダイアログはログの兄弟で
`flexShrink={0}`、ログ側が `flexGrow={1}` なので、ダイアログの高さぶんログの可視行がそのまま減ります。
実測(幅 100 桁・選択肢 4 件+説明あり・詳細ビュー):
| 端末の行数 | ask 表示前のログ行数 | 表示後(修正前) | 表示後(修正後) |
|---|---|---|---|
| 24 | 16 | **0** | 5 |
| 30 | 22 | 5 | 5 |
| 40 | 32 | 15 | 15 |
| 50 | 42 | 25 | 25 |
24 行の端末では `Tab: ログを遡る` に切り替えても表示行が 0 なので、**質問の背景を読む手段が事実上なかった**(#125
で入れた Tab の意味が失われる)状態でした。
## 変更
コマンドパレットの `paletteMaxRows`(「ログを数行残す」上限)と同じ構図を ask にも入れました。
- **`core/layout.ts`** — `dialogMaxRows(rows,
view)`。ダイアログの縦幅(枠込み)に上限を設け、下に `DIALOG_CONTENT_RESERVE`(5
行)を必ず残す。ダイアログは入力欄の位置に出るので `COMPOSER_ROWS`(3) は戻して数える。極端に低い端末では
`DIALOG_MIN_ROWS` を下限にする。
- **`core/choice-lines.ts`** — 純関数 `choiceView(heights, cursor, cap)`。1
件 = 1 行ではない(ラベルの折返し + 説明)ので行数で詰める窓計算。カーソルの件は必ず窓に入れ、溢れた端には「↑↓ 他 N 件」用に 1
行予約する。下端アンカーなので `listView` / `visibleLineRange` と同じスクロール感(↑↓
でカーソルを送ると窓がついてくる)。
- **`ui/permission-dialog.tsx`** —
実際に描く固定部分(枠・見出し・質問文の折返し・区切り+相談する・ヒント・自由記述の入力欄)から選択肢ブロックの予算を出して窓表示。**クリックの当たり判定も描いた窓で逆算**する(上端インジケータ
1 行ぶんずれる)。
- **`ui/composer.tsx`** — 入力欄が描く行数 `drawnRows` を `ComposerController`
に公開(自由記述モードの高さ見積りに使う。既に内部で計算していた値)。
- **`ui/session-detail.tsx` / `ui/session-list.tsx`** —
`maxRows={dialogMaxRows(rows, …)}` を渡す。
- **i18n** — `permission.moreAbove` / `moreBelow`(ja/en 対で追加)。
- **docs** — README(詳細ビューの Tab 節)と
`.claude/rules/ink-components.md`(「`flexShrink={0}`
は縮む役を他へ回すだけなので、ダイアログ自身にも上限を持たせる」)を追記。
24 行の端末では選択肢 5 件が「1 件 + `↓ 他 4 件`」に畳まれ、ログは 5 行残ります。
## 対象外
- **ツール許可ダイアログ(`ToolDialog`)には上限を入れていません。** 入力サマリが 200 文字で切られているため最大でも
10 行程度で、ログを潰す規模になりません(許可対象のコマンドを黙って隠す方が有害)。
- 自由記述モード(「自分で入力する」)は入力欄 3 行ぶん余分に要るので、24 行の端末ではログが 2 行まで縮みます(0 にはなりません)。
## テスト
- `src/core/choice-lines.spec.ts` — `choiceView` のテーブルドリブン(先頭 / 末尾 / 中間
/ 範囲外カーソル、描画行数が cap 以下、↓ で単調にスクロール、1 件が cap より高い場合、cap < 1)
- `src/core/layout.spec.ts` — `dialogMaxRows`(chrome の差引・24 行端末で reserve
が残る・下限・単調増加)
- `tests/app.test.tsx` — 24 行の端末で ask を出し、ログの席が残る / `↓ 他 4 件` が出る / ↓
で案D まで辿れる / **窓の中の選択肢をクリック → Enter で正しい回答が返る**(当たり判定のずれの番人)
- `tests/commands.test.tsx` — `/prompt` エディタのドラッグ選択テストが固定 `flush()`
でフレームを掴んでいてフルスイートで落ちたので `settle()` に変更(helpers.ts の注記どおり)
`lint` / `typecheck` / `test`(2927 passed) / `build` の 4 点をローカルで通しています。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
背景
セッション詳細ビューは
pendingPermissionがあるあいだキーを全部PermissionDialogへ委譲していたため、↑↓/PgUp/PgDnがすべて選択肢の移動に食われ、会話ログを 1 行も遡れなかった。結果、「何の話か分からないまま質問に答える」しかない状態だった。一覧画面には同じ問題への答え(
ListFocus= composer / dialog / list をTabで回す)が既にあるので、詳細ビューにも同じ考え方(↑↓ が指す対象を一意にする)を持ち込む。変更
DetailFocus(dialog/log)を追加し、許可/質問待ちのあいだTabで往復する。dialog— 回答は待たせている用事なので、そこへ辿り着くためにTabを踏ませない(一覧のzoneForRowと同じ方針)。logゾーンでは↑↓/PgUp/PgDnがログのスクロールに戻る。ダイアログはactive={false}で表示のまま(質問文を読みながら遡れる)。Tab/Esc/ ダイアログのクリック(onActivate)の 3 つ。dialogへ畳む(次の質問でキーの意味が勝手に変わらないように)。logゾーンだけ通すので、範囲選択と URL クリックも普段どおり使える(dialogゾーンでは従来どおり飲む)。detail.helpLog/detail.dialogInactiveHelpを ja/en に追加し、detail.helpPendingにTabの案内を足した。PermissionDialogの「表示のみ」ヒントは view から渡す(inactiveHint)— 一覧の「↑↓: セッション切替」は詳細では嘘になるため、共有コンポーネントに view の知識を持たせない。.claude/rules/ink-components.md(ゾーンの不変条件・マウスの例外)/docs/ARCHITECTURE.md(SessionDetailの責務)/README.md(利用者向けのキー表)を実装より先に更新。テスト
tests/app.test.tsxに統合テストを追加(許可待ちでも Tab でログを遡れ、Tab で回答へ戻れる):dialogゾーンでは↑でログが動かない(ダイアログのもの)dialogゾーンでも効くTab→logゾーンでフッタ/ダイアログの案内が入れ替わり、質問文は表示されたままlogゾーンの↑でログを遡れ、「過去ログを表示中」が出るTabで戻ってそのままyで許可できる(往復でダイアログが壊れない)lint(Biome)/typecheck/test(tests/app.test.tsx99 件)/buildの 4 点体感確認(実 TTY + 認証が必要)はお願いします: 詳細ビューで質問が来ている状態で
Tab→↑↓でログが遡れること、Tab/ クリックで回答へ戻れることを確認してください。🤖 Generated with Claude Code