@@ -246,6 +246,32 @@ def test_cmd_project_list_non_tty_falls_back_to_table(tmp_path, monkeypatch, cap
246246 assert "alpha-proj" in out
247247
248248
249+ def test_cmd_project_list_stdout_non_tty_falls_back_to_table (tmp_path , monkeypatch , capsys ):
250+ """stdin が TTY でも stdout が非 TTY (`devbase list | cat` / `> out.txt`) なら
251+ 対話起動せず一覧表示へフォールバックする。"""
252+ from devbase .commands import project as project_mod
253+ from devbase .commands import status as status_mod
254+ from devbase .commands import container as container_mod
255+
256+ _make_plugin_project (tmp_path , "repos/o--r/alpha" , "alpha-proj" )
257+ _link_project (tmp_path , "alpha-proj" , "repos/o--r/alpha" , "alpha-proj" )
258+ monkeypatch .setattr (status_mod , "_container_status_for" ,
259+ lambda entry : {"name" : entry .name , "status" : "stopped" , "count" : 0 })
260+ monkeypatch .setattr (project_mod .sys .stdin , "isatty" , lambda : True )
261+ monkeypatch .setattr (project_mod .sys .stdout , "isatty" , lambda : False )
262+
263+ called = []
264+ monkeypatch .setattr (container_mod , "cmd_project" , lambda args : called .append (1 ) or 0 )
265+
266+ args = types .SimpleNamespace (interactive = True )
267+ rc = project_mod .cmd_project_list (tmp_path , args )
268+ out = capsys .readouterr ().out
269+
270+ assert rc == 0
271+ assert called == [], "stdout 非 TTY では対話起動しない"
272+ assert "alpha-proj" in out
273+
274+
249275# ---------------------------------------------------------------------------
250276# cmd_project_list: --interactive
251277# ---------------------------------------------------------------------------
@@ -263,6 +289,7 @@ def test_cmd_project_list_interactive_selects_and_ups(tmp_path, monkeypatch):
263289
264290 # 対話選択は TTY 環境でのみ起動するため isatty を True に固定する。
265291 monkeypatch .setattr (project_mod .sys .stdin , "isatty" , lambda : True )
292+ monkeypatch .setattr (project_mod .sys .stdout , "isatty" , lambda : True )
266293 # 番号 "2" を選択 (sorted: alpha-proj=1, beta-proj=2)
267294 monkeypatch .setattr ("builtins.input" , lambda * a , ** k : "2" )
268295
@@ -288,6 +315,7 @@ def test_cmd_project_list_interactive_empty_input_aborts(tmp_path, monkeypatch):
288315 _link_project (tmp_path , "alpha-proj" , "repos/o--r/alpha" , "alpha-proj" )
289316 monkeypatch .setattr (status_mod , "_container_status_for" , lambda entry : None )
290317 monkeypatch .setattr (project_mod .sys .stdin , "isatty" , lambda : True )
318+ monkeypatch .setattr (project_mod .sys .stdout , "isatty" , lambda : True )
291319 monkeypatch .setattr ("builtins.input" , lambda * a , ** k : "" )
292320
293321 called = []
@@ -313,6 +341,7 @@ def raise_eof(*a, **k):
313341 raise EOFError
314342
315343 monkeypatch .setattr (project_mod .sys .stdin , "isatty" , lambda : True )
344+ monkeypatch .setattr (project_mod .sys .stdout , "isatty" , lambda : True )
316345 monkeypatch .setattr ("builtins.input" , raise_eof )
317346 called = []
318347 monkeypatch .setattr (container_mod , "cmd_project" , lambda args : called .append (1 ) or 0 )
@@ -337,6 +366,7 @@ def raise_interrupt(*a, **k):
337366 raise KeyboardInterrupt
338367
339368 monkeypatch .setattr (project_mod .sys .stdin , "isatty" , lambda : True )
369+ monkeypatch .setattr (project_mod .sys .stdout , "isatty" , lambda : True )
340370 monkeypatch .setattr ("builtins.input" , raise_interrupt )
341371 called = []
342372 monkeypatch .setattr (container_mod , "cmd_project" , lambda args : called .append (1 ) or 0 )
@@ -358,6 +388,7 @@ def test_cmd_project_list_interactive_out_of_range_reprompts(tmp_path, monkeypat
358388 monkeypatch .setattr (status_mod , "_container_status_for" , lambda entry : None )
359389
360390 monkeypatch .setattr (project_mod .sys .stdin , "isatty" , lambda : True )
391+ monkeypatch .setattr (project_mod .sys .stdout , "isatty" , lambda : True )
361392 # "99" (範囲外) → "1" (有効) の順に入力 → 再入力後に up が起動する
362393 inputs = iter (["99" , "1" ])
363394 monkeypatch .setattr ("builtins.input" , lambda * a , ** k : next (inputs ))
@@ -382,6 +413,7 @@ def test_cmd_project_list_interactive_non_numeric_reprompts(tmp_path, monkeypatc
382413 monkeypatch .setattr (status_mod , "_container_status_for" , lambda entry : None )
383414
384415 monkeypatch .setattr (project_mod .sys .stdin , "isatty" , lambda : True )
416+ monkeypatch .setattr (project_mod .sys .stdout , "isatty" , lambda : True )
385417 # "abc" (数値以外) → "1" (有効)
386418 inputs = iter (["abc" , "1" ])
387419 monkeypatch .setattr ("builtins.input" , lambda * a , ** k : next (inputs ))
0 commit comments