Skip to content

feat: PLAN31_2-tui-framework TUI 土台 (tui/ + メニューエンジン + 既存 project 操作の非回帰移送)#56

Merged
takemi-ohama merged 3 commits into
release/PLAN31_2from
feature/PLAN31_2-tui-framework
Jun 10, 2026
Merged

feat: PLAN31_2-tui-framework TUI 土台 (tui/ + メニューエンジン + 既存 project 操作の非回帰移送)#56
takemi-ohama merged 3 commits into
release/PLAN31_2from
feature/PLAN31_2-tui-framework

Conversation

@takemi-ohama

Copy link
Copy Markdown
Contributor

Summary

Test plan

  • 該当 action が plan 2.3 の契約どおり SimpleNamespace を組んで既存ハンドラを呼ぶ (monkeypatch 単体)
  • 破壊的操作は confirm を介す (該当時)
  • 非 TTY / questionary 不在のフォールバック

devbase list の対話 TUI を commands/project.py から lib/devbase/tui/ パッケージへ
分離し、全カテゴリを束ねるトップ階層メニューの入口を新設する (PLAN31_2 PR1)。

- tui/menu.py: questionary ラッパ・MENU_BACK 番兵・Esc/← バインド・引数収集
  ヘルパ (text/confirm/integer/path, input フォールバック)
- tui/dispatch.py: dispatch_lifecycle / dispatch_group (旧 _start_project_action
  を一般化、PR3〜5 の group 委譲も先行整備)
- tui/actions_project.py: 既存 project up/down/rebuild の非回帰移送 (一覧選択→
  running はサブメニュー→他は直接 up、番号入力フォールバック)
- tui/app.py: トップ階層メニュー (project/env/plugin/snapshot/status)。
  「プロジェクト操作」を先頭・既定ハイライトで従来フローへ Enter 連打到達 (3.2)。
  env 以降は後続 PR 用プレースホルダ (_route に1行追加で配線)
- commands/project.py: listing/整形の純粋ロジックへ縮約、cmd_project_list は
  tui.run への薄い委譲に置換

後方互換: --plain/非TTY→table、questionary 不在→従来の番号入力フォールバックへ縮退。

テスト: TUI エンジン系を tests/cli/tui/ へ移設・拡充。全 pytest 510 passed/1 skipped。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@takemi-ohama takemi-ohama left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 cross-review | round 1 | gemini | APPROVE

TUI機能の分離とトップメニュー化の土台として、既存のCLI互換性を保ちつつ綺麗に整理されています。1点だけ、堅牢性の観点から入力関数の再帰呼び出しについてインラインでコメントを残しました。

Comment thread lib/devbase/tui/menu.py Outdated

@takemi-ohama takemi-ohama left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 cross-review | round 1 | codex | REQUEST_CHANGES

対話 TUI 経路の戻り値契約と入力ヘルパのキャンセル規約に修正が必要です。

Comment thread lib/devbase/tui/actions_project.py Outdated
Comment thread lib/devbase/tui/menu.py Outdated
cross-review round1 の 3 件を修正:

1. [major] actions_project.run() が dispatch_lifecycle の戻り値を捨てており
   project up/down/rebuild 失敗時も devbase list の終了コードが常に 0 になる問題を
   修正。run() は操作実行時に rc(int) を返すプロトコルへ拡張し、app._top_menu_loop が
   last_rc を記憶して終了コードへ伝搬する (判定は is 同一性で rc=0 を誤マッチさせない)。

2. [minor] menu.text() / menu.path() の allow_empty=False 空入力時の自己再帰呼び出しを
   while ループへ変更し RecursionError リスクを除去。

3. [minor] questionary 経路の text/confirm/path に Esc→中止 (None) バインドが無く
   docstring/select のナビ規約と不整合だったため _ask_with_escape ヘルパで
   with_escape_cancel を適用。

テスト追従: rc 伝搬・非0 rc 伝搬・Esc バインド登録・while 再入力ループの検証を追加
(510 passed → 520 passed / 1 skipped)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@takemi-ohama

Copy link
Copy Markdown
Contributor Author

cross-review round1 対応サマリ

commit: 5948c08

重要度 件数 対応
critical 0 -
major 1 対応済
minor 2 対応済
deferred 0 -
rejected 0 -

対応内容

  1. [major] actions_project.py:93dispatch_lifecycle の rc を捨てず run() の戻り値として伝搬。app._top_menu_loop が last_rc を記憶し devbase list の終了コードへ反映 (rc=0 を None/MENU_BACK と誤マッチさせないよう is 同一性判定)。
  2. [minor] menu.py:163 — text()/path() の空入力再試行を自己再帰から while ループへ変更し RecursionError リスクを除去。
  3. [minor] menu.py:157 — questionary 経路の text/confirm/path に _ask_with_escape 経由で Esc→中止バインドを適用し select のナビ規約と整合化。

テスト

uv run pytest: 520 passed / 1 skipped (510→520、rc 伝搬・非0伝搬・Esc バインド・while 再入力ループ検証を追加)。

3 thread すべて reply + resolve 済み。

@takemi-ohama takemi-ohama left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 cross-review | round 2 | gemini | APPROVE

前回の指摘箇所(再帰呼び出しの回避)が修正されていることを確認しました。追加の修正提案はありません。

@takemi-ohama takemi-ohama left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 cross-review | round 2 | codex | APPROVE

追加の修正必須指摘はありません。

@takemi-ohama takemi-ohama merged commit 50ab9c2 into release/PLAN31_2 Jun 10, 2026
takemi-ohama added a commit that referenced this pull request Jun 10, 2026
PR1 を cross-review approved → release へ merge (50ab9c2) 済みに更新し、
後続 PR (project/env/plugin/snapshot/status) が tui 土台へ配線する手順
(_route 1 行追加・menu 引数収集・dispatch_group・confirm/chdir) を申し送りとして追記。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
takemi-ohama added a commit that referenced this pull request Jun 11, 2026
* chore: PLAN31_2 release ブランチ初期化 (Draft PR 用)

* feat: PLAN31_2-tui-framework TUI 土台 (tui/ + メニューエンジン + 既存 project 操作の非回帰移送) (#56)

* chore: PLAN31_2-tui-framework Draft PR 作成

* feat(tui): PLAN31_2 TUI 土台を tui/ へ分離・トップ階層メニュー化 (PR1 #56)

devbase list の対話 TUI を commands/project.py から lib/devbase/tui/ パッケージへ
分離し、全カテゴリを束ねるトップ階層メニューの入口を新設する (PLAN31_2 PR1)。

- tui/menu.py: questionary ラッパ・MENU_BACK 番兵・Esc/← バインド・引数収集
  ヘルパ (text/confirm/integer/path, input フォールバック)
- tui/dispatch.py: dispatch_lifecycle / dispatch_group (旧 _start_project_action
  を一般化、PR3〜5 の group 委譲も先行整備)
- tui/actions_project.py: 既存 project up/down/rebuild の非回帰移送 (一覧選択→
  running はサブメニュー→他は直接 up、番号入力フォールバック)
- tui/app.py: トップ階層メニュー (project/env/plugin/snapshot/status)。
  「プロジェクト操作」を先頭・既定ハイライトで従来フローへ Enter 連打到達 (3.2)。
  env 以降は後続 PR 用プレースホルダ (_route に1行追加で配線)
- commands/project.py: listing/整形の純粋ロジックへ縮約、cmd_project_list は
  tui.run への薄い委譲に置換

後方互換: --plain/非TTY→table、questionary 不在→従来の番号入力フォールバックへ縮退。

テスト: TUI エンジン系を tests/cli/tui/ へ移設・拡充。全 pytest 510 passed/1 skipped。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(tui): 実行 rc をトップメニューまで伝搬 + text/path 再帰除去 + Esc バインド (PR56 round1)

cross-review round1 の 3 件を修正:

1. [major] actions_project.run() が dispatch_lifecycle の戻り値を捨てており
   project up/down/rebuild 失敗時も devbase list の終了コードが常に 0 になる問題を
   修正。run() は操作実行時に rc(int) を返すプロトコルへ拡張し、app._top_menu_loop が
   last_rc を記憶して終了コードへ伝搬する (判定は is 同一性で rc=0 を誤マッチさせない)。

2. [minor] menu.text() / menu.path() の allow_empty=False 空入力時の自己再帰呼び出しを
   while ループへ変更し RecursionError リスクを除去。

3. [minor] questionary 経路の text/confirm/path に Esc→中止 (None) バインドが無く
   docstring/select のナビ規約と不整合だったため _ask_with_escape ヘルパで
   with_escape_cancel を適用。

テスト追従: rc 伝搬・非0 rc 伝搬・Esc バインド登録・while 再入力ループの検証を追加
(510 passed → 520 passed / 1 skipped)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(PLAN31_2): PR1 (#56) 完了を進捗に反映 + PR2〜5 申し送り追記

PR1 を cross-review approved → release へ merge (50ab9c2) 済みに更新し、
後続 PR (project/env/plugin/snapshot/status) が tui 土台へ配線する手順
(_route 1 行追加・menu 引数収集・dispatch_group・confirm/chdir) を申し送りとして追記。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat: PLAN31_2-project-ops project login/ps/logs/scale/build の TUI 追加 (#57)

* chore: PLAN31_2-project-ops Draft PR 作成

* feat(tui): PLAN31_2 project 操作を login/ps/logs/scale/build へ拡張 (PR2 #57)

running 行の操作サブメニューを up/down/login/ps/logs/scale/build/rebuild の全操作へ
拡張し、各操作の引数を tui.menu の収集ヘルパで CLI と同じ属性 (plan 2.3 契約) として
集める。stopped/unknown は従来どおり直接 up (PR1 非回帰)。

- login: index (既定 "1") を text で収集
- ps: --all を confirm で収集
- logs: --follow を confirm、--tail を optional int (空=全件) で収集
- scale: new_scale を integer (min=1) で収集
- build: containers/<image>/Dockerfile を列挙して選択 (compose.yml 全体= image None)
- down: 破壊的操作のため confirm で確認 (plan 3.4)
- 引数収集を Esc/Ctrl-C で中止したら操作サブメニューへ戻る (_ARG_CANCEL)

login/ps/logs/scale は running コンテナ対象のため running 行限定とした。
全 pytest 542 passed / 1 skipped (PR2 で +22)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(tui): project login の空 index バグ修正 + logs --tail 負数バリデーション (PR2 #57 round1)

- login: menu.text(空入力で "" → --index= 失敗) を menu.integer(default=1,
  min_value=1) に変更し、str(index) で文字列契約を満たして dispatch。
- _optional_int: min_value=0 検証を追加し、logs --tail への負数入力を弾いて
  再入力を促す (docker compose エラー防止)。
- テスト: login を menu.integer モックに追従、負数再入力テストを追加。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat: PLAN31_2-env-ops env 全操作の TUI 追加 (#58)

* chore: PLAN31_2-env-ops Draft PR 作成

* feat: PLAN31_2-env-ops env 全操作の TUI 追加

- tui/actions_env.py 新設: env init/list/set/get/delete/edit/sync/project/
  export/import を選択メニュー + 引数収集で cmd_env へ委譲 (plan 2.3 契約)
- project スコープ (set --project / project) は事前にプロジェクト選択 →
  chdir + PWD 切替で実行し、try/finally で必ず元の CWD/PWD へ復帰 (plan 3.3)
- 破壊的な env delete は実行前に menu.confirm で確認 (plan 3.4)
- export/import は主要引数 (dest/source) のみ収集し、残りは CLI parser 既定値と
  同一の属性を明示付与 (parser との同期テスト付き)
- tui/app.py の _route に env を配線、未実装カテゴリ前提のテストを plugin へ更新
- tests/cli/tui/test_actions_env.py 新設 (契約・chdir 復帰・confirm・ナビ遷移)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: env list の「プロジェクトのみ」で対象プロジェクト選択 + chdir/PWD 切替を行う

cmd_env_list は PWD が projects/ 配下のときだけプロジェクト .env を表示する
ため、TUI (通常 DEVBASE_ROOT で稼働) から project スコープを選んでも何も
表示されなかった (codex round1 major 指摘)。set/project と同様に
_select_project で対象を選ばせ、_run_in_project 経由で実行するよう修正。
回帰テスト (chdir + 復帰 / 選択中止) を追加。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: env get に取得元選択を追加しプロジェクト .env のキーを取得可能にする

cmd_env_get はグローバル .env に無いキーを CWD (PWD) のプロジェクト .env へ
フォールバックして探すが、TUI は常に DEVBASE_ROOT で実行されるため
プロジェクト固有キーを取得できなかった (codex round2 指摘)。
list/set と同様に取得元 (グローバル / プロジェクト) を選ばせ、プロジェクト
選択時は _run_in_project 経由で chdir + PWD 切替後に dispatch する。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

* feat: PLAN31_2-plugin-ops plugin 全操作 + repo の TUI 追加 (#59)

* chore: PLAN31_2-plugin-ops Draft PR 作成

* feat: PLAN31_2-plugin-ops plugin 全操作 + repo の TUI 追加

- tui/actions_plugin.py 新設: plugin list/install/uninstall/update/info/
  sync/migrate と repo add/remove/list/refresh のサブ階層メニューを実装。
  引数は menu.* で収集し dispatch_group 経由で cmd_plugin へ委譲
  (plan 2.3 の属性契約は cli.py parser と突き合わせて検証済み・乖離なし)
- uninstall/update/info と repo remove/refresh の name は registry
  (plugins.yml) の一覧から選択。破壊的な uninstall / repo remove は
  menu.confirm で実行前確認 (plan 3.4)
- tui/app.py の _route に plugin を配線 (未実装プレースホルダ案内を解消)
- tests/cli/tui/test_actions_plugin.py 新設 + test_app.py の routing 検証更新
  (597 passed / 1 skipped・退行なし)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

* feat: PLAN31_2-snapshot-status snapshot 全操作 + status 閲覧の TUI 追加 (#60)

* chore: PLAN31_2-snapshot-status Draft PR 作成

* feat: PLAN31_2-snapshot-status snapshot 全操作 + status 閲覧の TUI 追加

- tui/actions_snapshot.py 新設: create/list/restore/copy/delete/rotate の
  操作メニューと引数収集 (属性契約は cli.py parser と突き合わせ済み)。
  restore/copy/delete の対象は SnapshotManager.list() の既存一覧から選択
  (取得失敗時は自由入力へ縮退)。破壊的な restore/delete は menu.confirm で
  確認し、拒否時は実行しない (plan 3.4)
- tui/actions_status.py 新設: cmd_status(devbase_root) への薄い委譲
  (引数なし・閲覧のみ。表示後トップへ rc を返す)
- tui/app.py: _route に snapshot/status を配線 (残りは PR3 env / PR4 plugin)
- テスト 39 件追加 (582 passed / 1 skipped、ベースライン 544 から退行ゼロ)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

* docs(PLAN31_2): PR2〜5 (#57-#60) 完了を進捗に反映 + env edit スコープの plan 訂正

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(tui): dispatch 委譲層で CWD/環境変数を実行後に復元 (PR #55 round1 major)

TUI から project 操作を実行すると _resolve_project_name の
os.chdir / env 反映 / COMPOSE_PROJECT_NAME 上書きが同一プロセスに
残留し、トップメニュー復帰後の env get 等が直前プロジェクトの
CWD・環境変数 (PWD 含む) を参照していた。

委譲チョークポイントの tui.dispatch に _preserve_cwd_env コンテキスト
マネージャを追加し、dispatch_lifecycle / dispatch_group の前後で
CWD と os.environ を保存・復元する (例外時も finally で保証)。
回帰テスト 3 件を追加。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(tui): 選択メニューの Ctrl-C を Esc と区別し全体中止を伝搬 (PR #55 round2 minor)

menu.select(back=True) ベースの選択ヘルパが Ctrl-C (None) と Esc/←
(MENU_BACK) を両方 _ARG_CANCEL に畳んでいたため、選択中の Ctrl-C が
ナビ規約の「全体中止」にならずサブメニュー再表示になっていた。

- actions_env: _select_project / list・set・get の scope 選択で
  None (Ctrl-C) を呼び出し元まで伝搬し、Esc のみ _ARG_CANCEL とする
- actions_plugin: _select_name で同様に区別。all_label の「全対象」は
  "" のまま返し、呼び出し側 (update / repo refresh) で None へ変換
- actions_snapshot: _select_snapshot_name で同様に区別 (text 縮退時は
  Esc/Ctrl-C を区別できないため従来どおり _ARG_CANCEL)
- actions_project: _select_build_image で同様に区別。「compose.yml
  全体」は "" 番兵に統一し、呼び出し側で image=None へ変換
- 各 _run_operation は選択ヘルパの None を return し、run ループ経由で
  トップループの全体中止 (None) に到達させる

テスト: 既存のキャンセル系を Esc=_ARG_CANCEL / Ctrl-C=None の新契約に
更新し、Ctrl-C 伝搬の回帰テスト 8 件を追加 (693→701 passed)。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(tui): env list の「グローバル + プロジェクト」もプロジェクト選択後に chdir して実行 (PR #55 round3 major)

TUI は DEVBASE_ROOT で動くため、both スコープを CWD 判定のまま dispatch すると
cmd_env_list の projects/ 配下チェックに掛からずグローバルしか表示されなかった。
project スコープと同様に対象プロジェクトを選ばせ、_run_in_project で
chdir + PWD 切替後に global_only=False / project_only=False で実行する。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(tui): 引数入力プロンプトの Ctrl-C を Esc と区別し全体中止を伝搬 (PR #55 round4 major)

menu.text/confirm/path が Esc と Ctrl-C を同じ None で返し、各 actions_* が
それを _ARG_CANCEL に畳んでいたため、引数入力中の Ctrl-C がナビ規約の
「全体中止」にならずサブメニュー再表示になっていた (round2 で対応した
選択メニューと同じ問題が入力プロンプトに残存)。

- menu: _ask_with_escape を with_escape_back(bind_left=False) ベースへ変更し、
  text/confirm/path/integer が Esc=MENU_BACK / Ctrl-C=None を区別して返す
  新契約に統一 (← は入力カーソル移動用に空ける)
- actions_env/plugin/project/snapshot: 入力ヘルパの None (Ctrl-C) を
  呼び出し元まで return し、MENU_BACK (Esc) のみ _ARG_CANCEL とする。
  confirm の「not ok」判定は MENU_BACK が truthy のため is 判定を先行
- _optional_int / _optional_point: 「空入力 = None (既定動作)」と Ctrl-C の
  None が衝突するため専用番兵 _ABORT を導入し、呼び出し側で None へ変換

テスト: 入力系キャンセルを Esc=_ARG_CANCEL / Ctrl-C=None の新契約へ
パラメトライズ更新し、Ctrl-C 全体中止と MENU_BACK 伝搬の回帰テストを追加
(701→732 passed)。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant