From 012fe17e17e6c1456214aaf86ea52058e37d9c2b Mon Sep 17 00:00:00 2001 From: Rohit Agrawal Date: Tue, 18 Aug 2026 16:40:59 -0700 Subject: [PATCH] status: show full managed-config box; abridge the launch banner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `ucode status` now renders the workspace-managed config as one box (enabled agents, provider/model, MCPs, skills, budget tiers) whenever the feature is on and a config exists for the current workspace — reusing the same `_print_managed_summary` panel launch/configure already show, read from the local cache so status stays offline-fast. Bare `ucode` launch traded its full box for a one-line banner, since it runs every session and re-enumerating the whole config each time is noise: • Using managed config — launching Claude Code as the default agent with "as the default agent" only appears when the launched agent really is the config's default; a budget-tier override drops it (the tier note in `_launch_tool` explains the swap). The model clause is omitted when none is set. The full box stays for `status` and `configure`. Co-authored-by: Isaac --- src/ucode/cli.py | 45 ++++++++++++++++++++++++++-- tests/test_cli.py | 74 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+), 2 deletions(-) diff --git a/src/ucode/cli.py b/src/ucode/cli.py index 0cbbe14..ce70a99 100644 --- a/src/ucode/cli.py +++ b/src/ucode/cli.py @@ -175,13 +175,23 @@ def _policy_summary_lines(managed: dict) -> list[str]: return lines -def _print_managed_summary(managed: dict, state: dict, tool: str | None) -> None: +def _print_managed_summary( + managed: dict, state: dict, tool: str | None, *, abridged: bool = False +) -> None: """Show which of the admin's settings are in force. With ``tool`` set (launch path) the per-agent Agent/Provider/Model lines are included; with ``tool=None`` (e.g. ``ucode configure`` under a managed config) they are skipped since no single agent has been chosen yet. + + ``abridged`` prints only what changes launch-to-launch — the agent and model this run will use, + and the policy in force — with a pointer to ``ucode status`` for the rest. Bare ``ucode`` runs + every session, so re-enumerating the workspace's full MCP/skills/tier list each time is noise; + the full box stays for ``status`` and ``configure``, where the reader asked to see it. """ + if abridged: + _print_managed_summary_abridged(managed, state, tool) + return lines = [f"[bold]Workspace:[/bold] [cyan]{state.get('workspace', '?')}[/cyan]"] if tool is not None: lines.append(f"[bold]Agent:[/bold] [green]{TOOL_SPECS[tool]['display']}[/green]") @@ -220,6 +230,27 @@ def _print_managed_summary(managed: dict, state: dict, tool: str | None) -> None ) +def _print_managed_summary_abridged(managed: dict, state: dict, tool: str | None) -> None: + """One-line launch banner: which agent (and model) this managed run is launching. + + Bare ``ucode`` runs every session, so the full box's MCP/skills/policy enumeration is noise + each time; ``ucode status`` still shows all of it. See ``_print_managed_summary``'s ``abridged`` + note. ``tool`` is always set on the launch path, but is guarded for callers that pass None.""" + if tool is None: + print_note("Using managed config.") + return + agent = TOOL_SPECS[tool]["display"] + model = managed_default_model(managed, tool) + model_suffix = f" with [magenta]{model}[/magenta]" if model else "" + # "as the default agent" only when this really is the config's default: a budget tier can + # override the default and launch a different agent, and the tier note in `_launch_tool` already + # explains that case — so claiming "default" here would contradict it. + role = " as the default agent" if tool == managed.get("default_agent") else "" + console.print( + f"[dim]•[/dim] Using managed config — launching [green]{agent}[/green]{role}{model_suffix}" + ) + + def _resolve_workspace_then_maybe_reject( workspace_entries: list[tuple[str, str | None]] | None, ) -> list[tuple[str, str | None]] | None: @@ -926,6 +957,16 @@ def status() -> int: if profile: print_kv("CLI profile", profile) + # When the workspace publishes a managed config and this run has the feature switched on, that + # admin-authored config is what launches actually apply — so surface the whole setup as one box + # here too, rather than leaving a developer to infer it from the per-agent rows below. Read from + # the local cache (no network): status is a quick, offline-safe glance, and the cache is what the + # last launch persisted for this workspace. + if workspace and managed_agent_config_enabled(): + managed = load_managed_state(workspace) + if managed: + _print_managed_summary(managed, state, None) + print_heading("Coding Agents") for tool, spec in TOOL_SPECS.items(): configured = tool in configured_tools @@ -2008,7 +2049,7 @@ def _launch_managed_default( "Your workspace's managed config names no agent to launch. Ask an admin to set a " "default agent, or run `ucode ` directly." ) - _print_managed_summary(managed, state, tool) + _print_managed_summary(managed, state, tool, abridged=True) _launch_tool( tool, ctx, diff --git a/tests/test_cli.py b/tests/test_cli.py index 2069cd2..170f842 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -553,6 +553,50 @@ def test_status_treats_available_tools_as_configured_agents(self): assert "https://example.databricks.com/ai-gateway/anthropic" not in result.output assert "https://example.databricks.com/ai-gateway/gemini" not in result.output + def test_status_shows_managed_config_box_when_present_and_enabled(self, monkeypatch): + monkeypatch.setenv("ENABLE_MANAGED_AGENT_CONFIG", "1") + managed = { + "enabled_agents": {"claude": {}, "codex": {}}, + "mcp_servers": [{"name": "github-mcp", "type": "external"}], + "skills": {"names": ["debug-ci"]}, + } + with ( + patch("ucode.cli.load_state", return_value=MINIMAL_STATE), + patch("ucode.cli.load_managed_state", return_value=managed), + ): + result = runner.invoke(app, ["status"]) + + assert result.exit_code == 0, result.output + assert "Workspace-managed config" in result.output + assert "Enabled agents:" in result.output + assert "github-mcp" in result.output + assert "debug-ci" in result.output + + def test_status_hides_managed_config_box_when_feature_disabled(self, monkeypatch): + monkeypatch.delenv("ENABLE_MANAGED_AGENT_CONFIG", raising=False) + managed = {"enabled_agents": {"claude": {}}} + with ( + patch("ucode.cli.load_state", return_value=MINIMAL_STATE), + patch("ucode.cli.load_managed_state", return_value=managed) as load_managed, + ): + result = runner.invoke(app, ["status"]) + + assert result.exit_code == 0, result.output + assert "Workspace-managed config" not in result.output + # Feature off: the managed cache is never consulted. + load_managed.assert_not_called() + + def test_status_hides_managed_config_box_when_none_present(self, monkeypatch): + monkeypatch.setenv("ENABLE_MANAGED_AGENT_CONFIG", "1") + with ( + patch("ucode.cli.load_state", return_value=MINIMAL_STATE), + patch("ucode.cli.load_managed_state", return_value=None), + ): + result = runner.invoke(app, ["status"]) + + assert result.exit_code == 0, result.output + assert "Workspace-managed config" not in result.output + class TestConfigureSkillsCommand: def test_mcp_flag_dispatches_location_set(self): @@ -2801,6 +2845,36 @@ def test_falls_back_to_the_first_enabled_agent(self, monkeypatch): assert result.exit_code == 0, result.output assert launched[0][0] == "opencode" + def test_launch_banner_is_abridged_not_the_full_box(self, monkeypatch): + managed = { + "default_agent": "claude", + "enabled_agents": {"claude": {"model_config": {"default_model": "system.ai.opus"}}}, + "mcp_servers": [{"name": "system.ai.slack", "type": "mcp-service"}], + "skills": {"names": ["main.default.my_skill"]}, + } + result, _ = self._run(monkeypatch, managed=managed) + assert result.exit_code == 0, result.output + # One-line banner: the agent it launches, and the model. + assert "launching Claude Code as the default agent" in result.output + assert "system.ai.opus" in result.output + # The full box's per-config enumeration is left to `ucode status`. + assert "Enabled agents:" not in result.output + assert "system.ai.slack" not in result.output + assert "main.default.my_skill" not in result.output + + def test_launch_banner_omits_default_agent_when_a_tier_overrides(self, monkeypatch): + # A budget tier can launch a different agent than the config's default; the banner must not + # then call it "the default agent" (the tier note in _launch_tool explains the swap). + managed = {"default_agent": "claude", "enabled_agents": {"claude": {}, "opencode": {}}} + monkeypatch.setattr( + "ucode.cli._fetch_budget_recommendation", lambda state, m: {"agent": "opencode"} + ) + result, launched = self._run(monkeypatch, managed=managed) + assert result.exit_code == 0, result.output + assert launched[0][0] == "opencode" + assert "launching OpenCode" in result.output + assert "as the default agent" not in result.output + def test_admin_without_a_config_is_pointed_at_setup(self, monkeypatch): result, launched = self._run(monkeypatch, managed=None, is_admin=True) assert result.exit_code == 0, result.output