77 - localpibox.run — subprocess helpers, tool discovery, container detection
88 - localpibox.cli — prompts, common flags, fatal-error helper
99 - support/build.py — env loading, build-arg mapping, docker command
10- - browser_state_cleanup — session pruning (age + count)
11- - backup_repos .py — gh repo listing + mirror cloning
10+ - browser-state-cleanup — session pruning (age + count)
11+ - backup-repos .py — gh repo listing + mirror cloning
1212
1313Runs with plain Python (no third-party deps), mirroring scripts/test_lpb.py.
1414"""
1515
1616from __future__ import annotations
1717
18+ import importlib # noqa: E402
1819import datetime
1920import io
2021import os
3940from localpibox import run as run_mod # noqa: E402
4041from localpibox import cli as cli_mod # noqa: E402
4142import build # noqa: E402
42- import browser_state_cleanup as bsc # noqa: E402
43- import backup_repos # noqa: E402
44- import lpb_config # noqa: E402
45- import validate # noqa: E402
46- import install_browser # noqa: E402
47- import install_openspec # noqa: E402
43+ bsc = importlib . import_module ( 'browser-state-cleanup' )
44+ backup_repos = importlib . import_module ( 'backup_repos' )
45+ lc = importlib . import_module ( 'lpb-config' )
46+ validate = importlib . import_module ( 'validate' )
47+ ib = importlib . import_module ( 'install-browser' )
48+ iospec = importlib . import_module ( 'install-openspec' )
4849
4950
5051# ═══════════════════════════════════════════════════════════════════════════
@@ -495,7 +496,7 @@ def test_lpb_config_migrate_legacy_layout(tmpdir):
495496 (pi_root / ".initialized" ).touch ()
496497 (pi_root / "agent" ).mkdir ()
497498 cons = _quiet_console ()
498- lpb_config .migrate_legacy_layout (pi_root , tmpdir / "agent_dir" , cons )
499+ lc .migrate_legacy_layout (pi_root , tmpdir / "agent_dir" , cons )
499500 assert (tmpdir / "agent_dir" / "auth.json" ).exists ()
500501 assert (pi_root / ".initialized" ).exists () # marker preserved
501502 assert (pi_root / "agent" ).exists () # subdir preserved
@@ -509,86 +510,86 @@ def test_lpb_config_migrate_noop_when_already_migrated(tmpdir):
509510 agent .mkdir ()
510511 (agent / ".git" ).mkdir ()
511512 cons = _quiet_console ()
512- lpb_config .migrate_legacy_layout (pi_root , agent , cons ) # must not raise
513+ lc .migrate_legacy_layout (pi_root , agent , cons ) # must not raise
513514 assert True
514515
515516
516517def test_lpb_config_update_clones (tmpdir ):
517518 remote = _setup_git_remote (tmpdir )
518519 agent = tmpdir / "agent"
519520 cons = _quiet_console ()
520- code = lpb_config .cmd_update (agent , str (remote ), "main" , cons )
521+ code = lc .cmd_update (agent , str (remote ), "main" , cons )
521522 assert code == 0
522523 assert (agent / "f" ).exists ()
523524
524525
525526def test_lpb_config_update_fast_forward (tmpdir ):
526527 remote = _setup_git_remote (tmpdir )
527528 agent = tmpdir / "agent"
528- lpb_config .cmd_update (agent , str (remote ), "main" , _quiet_console ())
529+ lc .cmd_update (agent , str (remote ), "main" , _quiet_console ())
529530 _push_commit (tmpdir / "work" , "two" , "two" )
530531 cons = _quiet_console ()
531- assert lpb_config .cmd_update (agent , str (remote ), "main" , cons ) == 0
532+ assert lc .cmd_update (agent , str (remote ), "main" , cons ) == 0
532533 assert (agent / "f" ).read_text () == "two"
533534
534535
535536def test_lpb_config_update_refuses_when_dirty (tmpdir ):
536537 remote = _setup_git_remote (tmpdir )
537538 agent = tmpdir / "agent"
538- lpb_config .cmd_update (agent , str (remote ), "main" , _quiet_console ())
539+ lc .cmd_update (agent , str (remote ), "main" , _quiet_console ())
539540 _push_commit (tmpdir / "work" , "two" , "two" )
540541 (agent / "local" ).write_text ("keep" ) # untracked = dirty
541542 cons = _quiet_console ()
542- assert lpb_config .cmd_update (agent , str (remote ), "main" , cons ) == 1
543+ assert lc .cmd_update (agent , str (remote ), "main" , cons ) == 1
543544 assert (agent / "local" ).exists ()
544545
545546
546547def test_lpb_config_reset_force (tmpdir ):
547548 remote = _setup_git_remote (tmpdir )
548549 agent = tmpdir / "agent"
549- lpb_config .cmd_update (agent , str (remote ), "main" , _quiet_console ())
550+ lc .cmd_update (agent , str (remote ), "main" , _quiet_console ())
550551 _push_commit (tmpdir / "work" , "two" , "two" )
551552 (agent / "junk" ).write_text ("x" )
552553 cons = _quiet_console ()
553- assert lpb_config .cmd_reset (agent , str (remote ), "main" , cons , force = True ) == 0
554+ assert lc .cmd_reset (agent , str (remote ), "main" , cons , force = True ) == 0
554555 assert not (agent / "junk" ).exists ()
555556 assert (agent / "f" ).read_text () == "two"
556557
557558
558559def test_lpb_config_reset_abort_without_confirmation (tmpdir ):
559560 remote = _setup_git_remote (tmpdir )
560561 agent = tmpdir / "agent"
561- lpb_config .cmd_update (agent , str (remote ), "main" , _quiet_console ())
562+ lc .cmd_update (agent , str (remote ), "main" , _quiet_console ())
562563 (agent / "junk" ).write_text ("x" )
563564 cons = _quiet_console ()
564- assert lpb_config .cmd_reset (agent , str (remote ), "main" , cons , force = False , inp = io .StringIO ("n\n " )) == 0
565+ assert lc .cmd_reset (agent , str (remote ), "main" , cons , force = False , inp = io .StringIO ("n\n " )) == 0
565566 assert (agent / "junk" ).exists ()
566567
567568
568569def test_lpb_config_status_states (tmpdir ):
569570 remote = _setup_git_remote (tmpdir )
570571 agent = tmpdir / "agent"
571- lpb_config .cmd_update (agent , str (remote ), "main" , _quiet_console ())
572+ lc .cmd_update (agent , str (remote ), "main" , _quiet_console ())
572573 out , err = io .StringIO (), io .StringIO ()
573574 cons = log_mod .Console (color = False , out = out , err = err )
574- assert lpb_config .cmd_status (agent , str (remote ), "main" , cons ) == 0
575+ assert lc .cmd_status (agent , str (remote ), "main" , cons ) == 0
575576 text = out .getvalue () + err .getvalue ()
576577 assert "Current:" in text and "Remote:" in text and "clean" in text
577578 # no repo yet
578579 out2 , err2 = io .StringIO (), io .StringIO ()
579580 cons2 = log_mod .Console (color = False , out = out2 , err = err2 )
580- assert lpb_config .cmd_status (tmpdir / "nope" , str (remote ), "main" , cons2 ) == 0
581+ assert lc .cmd_status (tmpdir / "nope" , str (remote ), "main" , cons2 ) == 0
581582 assert "No config repo" in (out2 .getvalue () + err2 .getvalue ())
582583
583584
584585def test_lpb_config_merge_uptodate (tmpdir ):
585586 remote = _setup_git_remote (tmpdir )
586587 agent = tmpdir / "agent"
587- lpb_config .cmd_update (agent , str (remote ), "main" , _quiet_console ())
588+ lc .cmd_update (agent , str (remote ), "main" , _quiet_console ())
588589 cons = _quiet_console ()
589- assert lpb_config .cmd_merge (agent , str (remote ), "main" , cons ) == 0
590+ assert lc .cmd_merge (agent , str (remote ), "main" , cons ) == 0
590591 # merge when no repo -> error
591- assert lpb_config .cmd_merge (tmpdir / "nope" , str (remote ), "main" , _quiet_console ()) == 1
592+ assert lc .cmd_merge (tmpdir / "nope" , str (remote ), "main" , _quiet_console ()) == 1
592593
593594
594595# ═══════════════════════════════════════════════════════════════════════════
@@ -690,8 +691,8 @@ def test_validate_pi_cli_missing(tmpdir):
690691
691692def test_install_browser_fetch_version ():
692693 payload = b'{"channels":{"Stable":{"version":"130.0.6723.58"}}}'
693- with mock .patch .object (install_browser .urllib .request , "urlopen" , return_value = io .BytesIO (payload )):
694- assert install_browser .fetch_stable_chrome_version () == "130.0.6723.58"
694+ with mock .patch .object (ib .urllib .request , "urlopen" , return_value = io .BytesIO (payload )):
695+ assert ib .fetch_stable_chrome_version () == "130.0.6723.58"
695696
696697
697698def test_install_browser_skips_existing_chrome (tmpdir ):
@@ -701,7 +702,7 @@ def test_install_browser_skips_existing_chrome(tmpdir):
701702 mock .patch .object (install_browser , "fetch_stable_chrome_version" , return_value = version ):
702703 (tmpdir / f"chrome-{ version } " / "chrome-linux64" ).mkdir (parents = True )
703704 (tmpdir / f"chrome-{ version } " / "chrome-linux64" / "chrome" ).touch ()
704- assert install_browser .install_chrome (cons ) == 0
705+ assert ib .install_chrome (cons ) == 0
705706 assert "already installed" in cons .err .getvalue ()
706707
707708
@@ -710,14 +711,14 @@ def test_install_browser_verify_no_chrome(tmpdir):
710711 with mock .patch .object (install_browser , "CHROME_BASE" , tmpdir ), \
711712 mock .patch .object (install_browser , "SYSTEM_CHROME" , tmpdir / "nope" ), \
712713 mock .patch .object (install_browser , "which" , return_value = None ):
713- assert install_browser .verify_installation (cons ) == 1
714+ assert ib .verify_installation (cons ) == 1
714715 assert "Chrome binary not found" in cons .err .getvalue ()
715716
716717
717718def test_install_browser_agent_install_missing_binary (tmpdir ):
718719 cons = _quiet_console ()
719720 with mock .patch .object (install_browser , "which" , return_value = None ):
720- assert install_browser .install_agent_browser (cons ) == 1
721+ assert ib .install_agent_browser (cons ) == 1
721722 assert "not found" in cons .err .getvalue ()
722723
723724
@@ -731,7 +732,7 @@ def fake_run(args, timeout=600, cwd=None):
731732
732733 with mock .patch .object (install_browser , "which" , return_value = "/bin/agent-browser" ), \
733734 mock .patch .object (install_browser , "run_cmd" , side_effect = fake_run ):
734- assert install_browser .install_agent_browser (cons ) == 0
735+ assert ib .install_agent_browser (cons ) == 0
735736 assert calls == [
736737 ["agent-browser" , "install" ],
737738 ["agent-browser" , "install" , "--with-deps" ],
@@ -746,16 +747,16 @@ def test_openspec_skips_when_installed(tmpdir):
746747 cons = _quiet_console ()
747748 with mock .patch .object (install_openspec , "which" , return_value = "/bin/openspec" ), \
748749 mock .patch .object (install_openspec , "run_cmd" , return_value = ("1.2.3" , "" , 0 )):
749- assert install_openspec .install_openspec (cons ) == 0
750+ assert iospec .install_openspec (cons ) == 0
750751 assert "already installed" in cons .out .getvalue ()
751752
752753
753754def test_openspec_install_retries_then_fails (tmpdir ):
754755 cons = _quiet_console ()
755756 with mock .patch .object (install_openspec , "which" , return_value = None ), \
756757 mock .patch .object (install_openspec , "run_cmd" , return_value = ("" , "npm err" , 1 )), \
757- mock .patch .object (install_openspec .time , "sleep" , return_value = None ):
758- assert install_openspec .install_openspec (cons ) == 1
758+ mock .patch .object (iospec .time , "sleep" , return_value = None ):
759+ assert iospec .install_openspec (cons ) == 1
759760 assert "3 attempts" in cons .err .getvalue ()
760761
761762
@@ -764,7 +765,7 @@ def test_openspec_init_new(tmpdir):
764765 target .mkdir ()
765766 cons = _quiet_console ()
766767 with mock .patch .object (install_openspec , "run_cmd" , return_value = ("" , "" , 0 )) as m :
767- assert install_openspec .init_openspec (target , cons ) == 0
768+ assert iospec .init_openspec (target , cons ) == 0
768769 assert m .call_args .args [0 ] == ["openspec" , "init" , "--tools" , "pi" ]
769770
770771
@@ -773,7 +774,7 @@ def test_openspec_init_existing_runs_update(tmpdir):
773774 (target / "openspec" ).mkdir (parents = True )
774775 cons = _quiet_console ()
775776 with mock .patch .object (install_openspec , "run_cmd" , return_value = ("" , "" , 0 )) as m :
776- assert install_openspec .init_openspec (target , cons ) == 0
777+ assert iospec .init_openspec (target , cons ) == 0
777778 assert m .call_args .args [0 ] == ["openspec" , "update" ]
778779
779780
@@ -786,20 +787,20 @@ def test_openspec_verify(tmpdir):
786787 (target / ".pi" / "prompts" / "opsx-apply.md" ).write_text ("x" )
787788 (target / ".pi" / "skills" / "openspec-foo" ).mkdir (parents = True )
788789 cons = _quiet_console ()
789- assert install_openspec .verify_installation (target , cons ) == 0
790+ assert iospec .verify_installation (target , cons ) == 0
790791 assert "2 command files" in cons .out .getvalue ()
791792
792793
793794def test_openspec_verify_missing_openspec (tmpdir ):
794795 target = tmpdir / "proj"
795796 target .mkdir ()
796797 cons = _quiet_console ()
797- assert install_openspec .verify_installation (target , cons ) == 1
798+ assert iospec .verify_installation (target , cons ) == 1
798799 assert "missing" in cons .err .getvalue ()
799800
800801
801802def test_openspec_resolve_target (tmpdir ):
802- assert install_openspec .resolve_target_dir (str (tmpdir )) == tmpdir .resolve ()
803+ assert iospec .resolve_target_dir (str (tmpdir )) == tmpdir .resolve ()
803804
804805
805806# ═══════════════════════════════════════════════════════════════════════════
0 commit comments