refactor(cli): trim _common to a PROG constants leaf; inline os.getcwd()
tracker-policy-pr / check-pr (pull_request) Successful in 16s
test / integration-docker (pull_request) Successful in 21s
lint / lint (push) Failing after 58s
test / unit (pull_request) Successful in 2m11s
test / integration-firecracker (pull_request) Successful in 3m27s
test / coverage (pull_request) Successful in 16s
test / publish-infra (pull_request) Has been skipped

_common had rotted into a junk drawer. Trim it to what actually
justifies a shared leaf module and rename for legibility:

  * REPO_DIR: deleted (dead — nothing imported it).
  * read_tty_line: dropped the pointless re-export; cleanup/start/init
    now import it straight from bot_bottle.util.
  * USER_CWD: deleted. It captured os.getcwd() at import time, but
    nothing chdirs and no test patched it, so it was equivalent to a
    live os.getcwd() — inlined at the six call sites.
  * PROG: kept, now the sole member. It's still a leaf (both the
    dispatcher and the commands it imports need it) so it can't move
    into __init__ without a circular import.

_common.py -> constants.py. Full unit suite green (2243); CLI dispatch
verified.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-24 17:31:14 -04:00
parent 50a67c04bd
commit a21f2358c6
14 changed files with 33 additions and 33 deletions
+1 -1
View File
@@ -11,7 +11,7 @@ from ..errors import MissingEnvVarError
from ..log import Die, die, error
from ..manifest import ManifestError
from ..orchestrator.store.store_manager import StoreManager
from ._common import PROG
from .constants import PROG
from .commands import list as _list_mod
from .commands.backend import cmd_backend
from .commands.cleanup import cmd_cleanup
-12
View File
@@ -1,12 +0,0 @@
"""Shared constants and tty helper for cli subcommands."""
from __future__ import annotations
import os
from pathlib import Path
from ..util import read_tty_line as read_tty_line
PROG = "cli.py"
USER_CWD = os.getcwd()
REPO_DIR = str(Path(__file__).resolve().parent.parent.parent)
+1 -1
View File
@@ -2,5 +2,5 @@
Each module exposes a `cmd_<name>(argv)` handler that the dispatcher
(`bot_bottle.cli`) registers in its COMMANDS table. Shared CLI helpers
(`_common`, `tui`) stay one level up in the `cli` package.
(`constants`, `tui`) stay one level up in the `cli` package.
"""
+1 -1
View File
@@ -16,7 +16,7 @@ from __future__ import annotations
import argparse
from ...backend import get_bottle_backend, known_backend_names
from .._common import PROG
from ..constants import PROG
def cmd_backend(args: list[str]) -> int:
+1 -1
View File
@@ -23,7 +23,7 @@ import sys
from ...backend import get_bottle_backend, has_backend, known_backend_names
from ...log import info
from .._common import read_tty_line
from ...util import read_tty_line
def cmd_cleanup(_argv: list[str]) -> int:
+1 -1
View File
@@ -16,7 +16,7 @@ from ...backend import enumerate_active_agents
from ...backend.freeze import CommitCancelled, get_freezer
from ...bottle_state import read_metadata
from ...log import die
from .._common import PROG
from ..constants import PROG
from .. import tui
+2 -2
View File
@@ -8,7 +8,7 @@ import os
from pathlib import Path
from ...log import die
from .._common import PROG, USER_CWD
from ..constants import PROG
def cmd_edit(argv: list[str]) -> int:
@@ -20,7 +20,7 @@ def cmd_edit(argv: list[str]) -> int:
if args.scope == "user":
target_file = Path(os.environ["HOME"]) / "bot-bottle.json"
else:
target_file = Path(USER_CWD) / "bot-bottle.json"
target_file = Path(os.getcwd()) / "bot-bottle.json"
if not target_file.is_file():
die(f"{target_file} does not exist")
+3 -2
View File
@@ -3,10 +3,11 @@
from __future__ import annotations
import argparse
import os
from ...log import info
from ...manifest import ManifestIndex
from .._common import PROG, USER_CWD
from ..constants import PROG
def cmd_info(argv: list[str]) -> int:
@@ -14,7 +15,7 @@ def cmd_info(argv: list[str]) -> int:
parser.add_argument("name", help="agent name defined in bot-bottle.json")
args = parser.parse_args(argv)
names = ManifestIndex.resolve(USER_CWD)
names = ManifestIndex.resolve(os.getcwd())
names.require_agent(args.name)
manifest = names.load_for_agent(args.name)
+3 -2
View File
@@ -11,7 +11,8 @@ from pathlib import Path
from typing import Any
from ...log import die, info, warn
from .._common import PROG, USER_CWD, read_tty_line
from ..constants import PROG
from ...util import read_tty_line
def cmd_init(argv: list[str]) -> int:
@@ -22,7 +23,7 @@ def cmd_init(argv: list[str]) -> int:
if args.scope == "user":
target_file = Path(os.environ["HOME"]) / "bot-bottle.json"
else:
target_file = Path(USER_CWD) / "bot-bottle.json"
target_file = Path(os.getcwd()) / "bot-bottle.json"
print(file=sys.stderr)
info(f"bot-bottle init — adding a new agent to {target_file}")
+2 -2
View File
@@ -8,7 +8,7 @@ import sys
from ...backend import enumerate_active_agents
from ...manifest import ManifestIndex
from .._common import PROG, USER_CWD
from ..constants import PROG
_ANSI_COLOR_CODES: dict[str, str] = {
"red": "\033[91m",
@@ -40,7 +40,7 @@ def cmd_list(argv: list[str]) -> int:
args = parser.parse_args(argv)
if args.scope == "available":
manifest = ManifestIndex.resolve(USER_CWD)
manifest = ManifestIndex.resolve(os.getcwd())
for name in manifest.all_agent_names:
print(name)
return 0
+4 -3
View File
@@ -15,12 +15,13 @@ to bring up the replacement from the recorded state.
from __future__ import annotations
import argparse
import os
from ...backend import BottleSpec
from ...bottle_state import read_metadata
from ...log import die
from ...manifest import ManifestIndex
from .._common import PROG, USER_CWD
from ..constants import PROG
from .start import _launch_bottle
@@ -40,14 +41,14 @@ def cmd_resume(argv: list[str]) -> int:
f"check ~/.bot-bottle/state/ or run `cli.py start` to create a new bottle"
)
manifest = ManifestIndex.resolve(USER_CWD)
manifest = ManifestIndex.resolve(os.getcwd())
manifest.require_agent(metadata.agent_name)
spec = BottleSpec(
manifest=manifest,
agent_name=metadata.agent_name,
copy_cwd=metadata.copy_cwd,
user_cwd=metadata.cwd or USER_CWD,
user_cwd=metadata.cwd or os.getcwd(),
identity=metadata.identity,
bottle_names=tuple(metadata.bottle_names),
)
+5 -4
View File
@@ -39,7 +39,8 @@ from ...bottle_state import (
from ...image_cache import StaleImageError
from ...log import info, die
from ...manifest import Manifest, ManifestIndex
from .._common import PROG, USER_CWD, read_tty_line
from ..constants import PROG
from ...util import read_tty_line
from .. import tui
@@ -116,7 +117,7 @@ def cmd_start(argv: list[str]) -> int:
# threading a no_cache field through every backend's plan dataclass.
os.environ["BOT_BOTTLE_NO_CACHE"] = "1"
manifest = ManifestIndex.resolve(USER_CWD)
manifest = ManifestIndex.resolve(os.getcwd())
if args.headless:
return _start_headless(
@@ -167,7 +168,7 @@ def cmd_start(argv: list[str]) -> int:
manifest=manifest,
agent_name=agent_name,
copy_cwd=args.cwd,
user_cwd=USER_CWD,
user_cwd=os.getcwd(),
label=label,
color=color,
bottle_names=bottle_names,
@@ -235,7 +236,7 @@ def _start_headless(
manifest=manifest,
agent_name=agent_name,
copy_cwd=args.cwd,
user_cwd=USER_CWD,
user_cwd=os.getcwd(),
label=label,
color=args.color or "",
bottle_names=bottle_names,
+1 -1
View File
@@ -34,7 +34,7 @@ from ...supervisor.types import (
TOOL_GITLEAKS_ALLOW,
TOOL_EGRESS_TOKEN_ALLOW,
)
from .._common import PROG
from ..constants import PROG
_REFRESH_INTERVAL_MS = 1000
+8
View File
@@ -0,0 +1,8 @@
"""Shared CLI constants.
Kept as a leaf module (imports nothing from the `cli` package) so both the
dispatcher (`cli/__init__.py`) and the command modules it imports can share
`PROG` without a circular import.
"""
PROG = "cli.py"