feat: session remove を名前省略時に一覧モーダルで一括削除する#74
Merged
Conversation
session remove を名前なしで実行するとセッション一覧モーダルを開き、 Space で複数選択して Enter で一括削除できるようにする。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…odal # Conflicts: # document/03-commands/02-tui.md # document/design/05-home.md # src/presentation/tui/home/ui.rs
📊 Test Coverage
🎉✨ パーフェクト!全ファイル Lines カバレッジ 100% を達成しました 🏆🐰 |
kkyosuke
pushed a commit
that referenced
this pull request
Jun 21, 2026
没入(Attached)で Ctrl-O を押して切替(Switch)に抜けると、ヘッダーは switch になるのに ↑/↓・j/k でセッションを移動できなかった。 原因は `read_key_timeout`(animate 時のポーリング読み取り)が、ターミナルが cooked(canonical) モードのまま `crossterm::event::poll` を呼んでいたこと。 イベントループは console の「1 キーごとに raw を on/off する」読み取りに 依存しており、その合間は cooked モードのまま(AlternateScreenGuard / echo は ECHO を落とすだけで canonical は維持)。canonical な tty は改行で 1 行確定 するまで readable にならないため、Enter を伴わない矢印・j/k は poll から ready に見えず、ティックを繰り返すだけで一度も読まれなかった。 animate は #66 で has_live_sessions() が加わり live セッションがあれば常に真 になるため、没入から Ctrl-O で抜けた直後(セッションが生きている)は必ずこの 経路に入り、矢印が握り潰されていた。 poll とデコードを raw モードで囲い(RAII の RawModeGuard で退出時に cooked へ 復元)、各キーが即時に届くようにした。console がブロッキング経路で使う 「読み取りの間だけ raw」と同じ挙動を timeout 経路にも適用しただけ。 term_reader.rs は端末 I/O 専用ラッパでカバレッジ除外。 fmt / clippy -D warnings / test(1382 passed) 通過。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
kkyosuke
added a commit
that referenced
this pull request
Jun 21, 2026
## 目的 没入(Attached)で `Ctrl-O` を押して切替(Switch)に抜けると、ヘッダーのモードは switch になるのに **↑/↓・`j`/`k` でセッションを移動できない**バグを修正する(issue #74)。`Enter` だけは効き、live セッションが無い状態(統括から `Ctrl-O`)の切替では矢印が効く——という「live セッションがあるときだけ navigation が死ぬ」症状。 ## 原因 `src/presentation/tui/term_reader.rs` の `read_key_timeout`(`animate` 時のポーリング読み取り)が、**ターミナルが cooked(canonical) モードのまま** `crossterm::event::poll` を呼んでいた。 - イベントループは `console` の「1 キーごとに raw を on/off する」読み取りに依存しており、読み取りの**合間は cooked モード**のまま(`AlternateScreenGuard` / `echo.rs` は `ECHO` を落とすだけで canonical は維持)。 - canonical な tty は、ラインディシプリンが**改行で 1 行確定するまで** readable にならない。そのため `Enter` を伴わない矢印・`j`/`k` は `poll` から ready に見えず、`Ok(None) => continue` のティックを繰り返すだけで**一度も読まれなかった**。 - `animate` は #66 で `state.has_live_sessions()` が加わり **live セッションがあれば常に真**になるため、没入から `Ctrl-O` で抜けた直後(セッションが生きている)は必ずこの経路に入り矢印が握り潰されていた。 - 無入力時は `read_key()`(`console` がその読み取りの間だけ raw 化)なので矢印が通る。これが「live が無ければ動く/あると動かない」の差。 ## 変更内容 - `read_key_timeout` の `poll` +デコードを **raw モードで囲う**(RAII の `RawModeGuard` で退出時に cooked へ復元)。各キーが即時に届き、`poll` がキー単位で ready を返すようになる。`console` がブロッキング経路で使う「読み取りの間だけ raw」と同じ挙動を timeout 経路にも適用しただけで、ループの他の挙動は不変。 ## テスト・確認方法 - `cargo fmt` / `cargo clippy --all-targets -- -D warnings` / `cargo test`(1382 passed、カバレッジ 100% 維持)。`term_reader.rs` は端末 I/O 専用ラッパでカバレッジ除外(`scripts/coverage.sh`)。 - 手動: 没入 → `Ctrl-O` → 切替 で ↑/↓・`j`/`k` がセッションを移動できること。live セッションがある状態の統括/在席でもキー入力が遅延・欠落しないこと。 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: test <test@example.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
kkyosuke
added a commit
that referenced
this pull request
Jun 21, 2026
## 目的 TUI の以下 3 つのバグを修正する。 - task のローディングアニメーション(スピナー)が回らない - task 実行完了が UI に反映されない(session create しても何かしらの入力があるまで更新されない) - 没入(Attached) → `Ctrl-O` で切替(Switch) に抜けたとき、`c` を 2 回押さないと session create に入れない ## 原因 3 症状はすべて同一原因。`src/presentation/tui/term_reader.rs` の `read_key_timeout`(animate ループのキー待ち経路)が、`crossterm::event::poll` で到着を待ってから `console` でキーをデコードしていた。 `crossterm::event::poll` は単なる可読性チェックではなく、**tty バイトを実際に読み取って crossterm 内部のパースバッファに溜め込む**(crossterm 0.29 `event/source/unix/tty.rs` の `try_read` → `read_complete` → `parser.advance`)。その後 fd を直接読む `console` にはそのバイトが見えず、次のキー入力までブロックする。この「1 キー分のズレ」が: - **c 二度押し**: 切替で押した最初の `c` を poll が食べ、`console` は次の押下までブロック。2 回目で初めて `switch_begin_create` が発火する。 - **スピナー停止 / 完了未反映**: 何らかのバイト・イベントが crossterm バッファに残ると `poll` が真を返し続け、`console` 読み取りでループが停止。再描画も `tasks.drain_completed()` も走らず、スピナーが止まり、完了がキー入力まで反映されない。 ## 変更内容 到着待ちを **バイトを消費しない方式**に置き換えた。 - `libc` で tty fd を直接ポーリング(可読性チェックのみ・読み取らない)し、その後これまで通り `console` にデコードさせる。 - `console` 自身の readiness 判定に合わせ、**macOS の tty は `select`**(macOS の tty は `poll` 不可)、**それ以外は `poll`**。 - raw モード(`RawModeGuard`)は #74 と同じ理由(cooked モードでは改行までキー単位で readable にならない)でそのまま維持。 ループ側のロジック・他経路の挙動は不変。 ## テスト・確認方法 - `cargo fmt` / `cargo clippy --all-targets -- -D warnings` / `cargo test`(1382 + 各バイナリ)すべてパス。 - lefthook pre-commit(branch-name / fmt / coverage)・pre-push(clippy / test)通過。 - 仕様・画面・データ構造の変更はなく、ドキュメント更新は不要(内部 I/O 挙動の修正のみ)。 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: test <test@example.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
目的
session removeを 名前なし で実行したとき、削除対象を毎回タイプせずに済むよう、セッション一覧モーダルから複数選択して一括削除できるようにする。変更内容
session removeを名前省略で実行するとEffect::OpenRemoveModalを返し、記録済みセッションのチェックリストを画面中央のモーダルに表示する(session remove <name>の直接削除は従来どおり)。↑/↓(またはj/k)でカーソル移動、Spaceで選択/解除、Enterで選択したセッションを 1 件ずつ一括削除、Escでキャンセル。何も選択していないEnterは no-op でモーダルを開いたまま。session remove --forceで開いた場合は破棄を伴って削除(未コミット変更ありでも削除)。↑ N more/↓ N moreで表示。home/state.rs(RemoveModal)、描画はhome/ui.rs、キー処理はhome/event.rs。既存のモーダル基盤(widgetsのboxed/render_modal)を再利用。document/03-commands/02-tui.md/document/04-orchestration.md/document/design/05-home.md/issues/003-session.md。モーダル UI
>がカーソル行、[x]が選択済み、[ ]が未選択。下部に選択件数とキー操作を表示。テスト・確認方法
cargo fmt --check/cargo clippy --all-targets -- -D warnings/cargo test(656 件)すべてパス。scripts/coverage.shの閾値でゲート通過を確認)。command.rs/state.rs/event.rs/ui.rsに単体テストを追加(モーダルの開閉・カーソル移動・選択トグル・一括削除・スクロール表示・空一覧・キャンセル)。🤖 Generated with Claude Code