Skip to content

Commit 91fcbce

Browse files
authored
Removes MCP (this is now remote) (#1194)
1 parent 043d947 commit 91fcbce

File tree

11 files changed

+164
-124
lines changed

11 files changed

+164
-124
lines changed

src/codegen/cli/auth/constants.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from pathlib import Path
22

33
# Base directories
4-
CONFIG_DIR = Path("~/.config/codegen-sh").expanduser()
4+
CONFIG_DIR = Path("~/.codegen").expanduser()
55
CODEGEN_DIR = Path(".codegen")
66
PROMPTS_DIR = CODEGEN_DIR / "prompts"
77

src/codegen/cli/auth/login.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,6 @@ def login_routine(token: str | None = None) -> str:
4040
token_manager = TokenManager()
4141
token_manager.authenticate_token(token)
4242
rich.print(f"[green]✓ Stored token to:[/green] {token_manager.token_file}")
43-
rich.print("[cyan]📊 Hey![/cyan] We collect anonymous usage data to improve your experience 🔒")
44-
rich.print("To opt out, set [green]telemetry_enabled = false[/green] in [cyan]~/.config/codegen-sh/analytics.json[/cyan] ✨")
4543
return token
4644
except AuthError as e:
4745
rich.print(f"[red]Error:[/red] {e!s}")

src/codegen/cli/cli.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,16 @@
33

44
from codegen import __version__
55

6+
# Import config command (still a Typer app)
7+
from codegen.cli.commands.agents.main import agents_app
8+
69
# Import the actual command functions
710
from codegen.cli.commands.claude.main import claude
8-
9-
# Import config command (still a Typer app)
1011
from codegen.cli.commands.config.main import config_command
1112
from codegen.cli.commands.init.main import init
1213
from codegen.cli.commands.integrations.main import integrations_app
1314
from codegen.cli.commands.login.main import login
1415
from codegen.cli.commands.logout.main import logout
15-
from codegen.cli.commands.mcp.main import mcp
1616
from codegen.cli.commands.profile.main import profile
1717
from codegen.cli.commands.style_debug.main import style_debug
1818
from codegen.cli.commands.tools.main import tools
@@ -29,27 +29,27 @@ def version_callback(value: bool):
2929

3030

3131
# Create the main Typer app
32-
main = typer.Typer(name="codegen", help="Codegen CLI - Transform your code with AI.", rich_markup_mode="rich")
32+
main = typer.Typer(name="codegen", help="Codegen - the Operating System for Code Agents.", rich_markup_mode="rich")
3333

3434
# Add individual commands to the main app
3535
main.command("claude", help="Run Claude Code with OpenTelemetry monitoring and logging.")(claude)
3636
main.command("init", help="Initialize or update the Codegen folder.")(init)
3737
main.command("login", help="Store authentication token.")(login)
3838
main.command("logout", help="Clear stored authentication token.")(logout)
39-
main.command("mcp", help="Start the Codegen MCP server.")(mcp)
4039
main.command("profile", help="Display information about the currently authenticated user.")(profile)
4140
main.command("style-debug", help="Debug command to visualize CLI styling (spinners, etc).")(style_debug)
4241
main.command("tools", help="List available tools from the Codegen API.")(tools)
4342
main.command("update", help="Update Codegen to the latest or specified version")(update)
4443

4544
# Add Typer apps as sub-applications
45+
main.add_typer(agents_app, name="agents")
4646
main.add_typer(config_command, name="config")
4747
main.add_typer(integrations_app, name="integrations")
4848

4949

5050
@main.callback()
5151
def main_callback(version: bool = typer.Option(False, "--version", callback=version_callback, is_eager=True, help="Show version and exit")):
52-
"""Codegen CLI - Transform your code with AI."""
52+
"""Codegen - the Operating System for Code Agents"""
5353
pass
5454

5555

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Agents command module."""
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
"""Agents command for the Codegen CLI."""
2+
3+
import requests
4+
import typer
5+
from rich.console import Console
6+
from rich.table import Table
7+
8+
from codegen.cli.api.endpoints import API_ENDPOINT
9+
from codegen.cli.auth.token_manager import get_current_token
10+
from codegen.cli.rich.spinners import create_spinner
11+
from codegen.cli.utils.org import resolve_org_id
12+
13+
console = Console()
14+
15+
# Create the agents app
16+
agents_app = typer.Typer(help="Manage Codegen agents")
17+
18+
19+
@agents_app.command("list")
20+
def list_agents(org_id: int | None = typer.Option(None, help="Organization ID (defaults to CODEGEN_ORG_ID/REPOSITORY_ORG_ID or auto-detect)")):
21+
"""List agent runs from the Codegen API."""
22+
# Get the current token
23+
token = get_current_token()
24+
if not token:
25+
console.print("[red]Error:[/red] Not authenticated. Please run 'codegen login' first.")
26+
raise typer.Exit(1)
27+
28+
try:
29+
# Resolve org id
30+
resolved_org_id = resolve_org_id(org_id)
31+
if resolved_org_id is None:
32+
console.print("[red]Error:[/red] Organization ID not provided. Pass --org-id, set CODEGEN_ORG_ID, or REPOSITORY_ORG_ID.")
33+
raise typer.Exit(1)
34+
35+
# Make API request to list agent runs with spinner
36+
spinner = create_spinner("Fetching agent runs...")
37+
spinner.start()
38+
39+
try:
40+
headers = {"Authorization": f"Bearer {token}"}
41+
url = f"{API_ENDPOINT.rstrip('/')}/v1/organizations/{resolved_org_id}/agent/runs"
42+
response = requests.get(url, headers=headers)
43+
response.raise_for_status()
44+
response_data = response.json()
45+
finally:
46+
spinner.stop()
47+
48+
# Extract agent runs from the response structure
49+
agent_runs = response_data.get("items", [])
50+
total = response_data.get("total", 0)
51+
page = response_data.get("page", 1)
52+
page_size = response_data.get("page_size", 10)
53+
54+
if not agent_runs:
55+
console.print("[yellow]No agent runs found.[/yellow]")
56+
return
57+
58+
# Create a table to display agent runs
59+
table = Table(
60+
title=f"Agent Runs (Page {page}, Total: {total})",
61+
border_style="blue",
62+
show_header=True,
63+
title_justify="center",
64+
)
65+
table.add_column("ID", style="cyan", no_wrap=True)
66+
table.add_column("Status", style="white", justify="center")
67+
table.add_column("Source", style="magenta")
68+
table.add_column("Created", style="dim")
69+
table.add_column("Result", style="green")
70+
71+
# Add agent runs to table
72+
for agent_run in agent_runs:
73+
run_id = str(agent_run.get("id", "Unknown"))
74+
status = agent_run.get("status", "Unknown")
75+
source_type = agent_run.get("source_type", "Unknown")
76+
created_at = agent_run.get("created_at", "Unknown")
77+
result = agent_run.get("result", "")
78+
79+
# Status with emoji
80+
status_display = status
81+
if status == "COMPLETE":
82+
status_display = "✅ Complete"
83+
elif status == "RUNNING":
84+
status_display = "🏃 Running"
85+
elif status == "FAILED":
86+
status_display = "❌ Failed"
87+
elif status == "STOPPED":
88+
status_display = "⏹️ Stopped"
89+
elif status == "PENDING":
90+
status_display = "⏳ Pending"
91+
92+
# Format created date (just show date and time, not full timestamp)
93+
if created_at and created_at != "Unknown":
94+
try:
95+
# Parse and format the timestamp to be more readable
96+
from datetime import datetime
97+
98+
dt = datetime.fromisoformat(created_at.replace("Z", "+00:00"))
99+
created_display = dt.strftime("%m/%d %H:%M")
100+
except (ValueError, TypeError):
101+
created_display = created_at[:16] if len(created_at) > 16 else created_at
102+
else:
103+
created_display = created_at
104+
105+
# Truncate result if too long
106+
result_display = result[:50] + "..." if result and len(result) > 50 else result or "No result"
107+
108+
table.add_row(run_id, status_display, source_type, created_display, result_display)
109+
110+
console.print(table)
111+
console.print(f"\n[green]Showing {len(agent_runs)} of {total} agent runs[/green]")
112+
113+
except requests.RequestException as e:
114+
console.print(f"[red]Error fetching agent runs:[/red] {e}", style="bold red")
115+
raise typer.Exit(1)
116+
except Exception as e:
117+
console.print(f"[red]Unexpected error:[/red] {e}", style="bold red")
118+
raise typer.Exit(1)
119+
120+
121+
# Default callback for the agents app
122+
@agents_app.callback(invoke_without_command=True)
123+
def agents_callback(ctx: typer.Context):
124+
"""Manage Codegen agents."""
125+
if ctx.invoked_subcommand is None:
126+
# If no subcommand is provided, run list by default
127+
list_agents(org_id=None)

src/codegen/cli/commands/integrations/main.py

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99

1010
from codegen.cli.api.endpoints import API_ENDPOINT
1111
from codegen.cli.auth.token_manager import get_current_token
12-
from codegen.cli.utils.url import generate_webapp_url
12+
from codegen.cli.rich.spinners import create_spinner
1313
from codegen.cli.utils.org import resolve_org_id
14+
from codegen.cli.utils.url import generate_webapp_url
1415

1516
console = Console()
1617

@@ -21,8 +22,6 @@
2122
@integrations_app.command("list")
2223
def list_integrations(org_id: int | None = typer.Option(None, help="Organization ID (defaults to CODEGEN_ORG_ID/REPOSITORY_ORG_ID or auto-detect)")):
2324
"""List organization integrations from the Codegen API."""
24-
console.print("🔌 Fetching organization integrations...", style="bold blue")
25-
2625
# Get the current token
2726
token = get_current_token()
2827
if not token:
@@ -36,13 +35,18 @@ def list_integrations(org_id: int | None = typer.Option(None, help="Organization
3635
console.print("[red]Error:[/red] Organization ID not provided. Pass --org-id, set CODEGEN_ORG_ID, or REPOSITORY_ORG_ID.")
3736
raise typer.Exit(1)
3837

39-
# Make API request to list integrations
40-
headers = {"Authorization": f"Bearer {token}"}
41-
url = f"{API_ENDPOINT.rstrip('/')}/v1/organizations/{resolved_org_id}/integrations"
42-
response = requests.get(url, headers=headers)
43-
response.raise_for_status()
38+
# Make API request to list integrations with spinner
39+
spinner = create_spinner("Fetching organization integrations...")
40+
spinner.start()
4441

45-
response_data = response.json()
42+
try:
43+
headers = {"Authorization": f"Bearer {token}"}
44+
url = f"{API_ENDPOINT.rstrip('/')}/v1/organizations/{resolved_org_id}/integrations"
45+
response = requests.get(url, headers=headers)
46+
response.raise_for_status()
47+
response_data = response.json()
48+
finally:
49+
spinner.stop()
4650

4751
# Extract integrations from the response structure
4852
integrations_data = response_data.get("integrations", [])
@@ -138,6 +142,5 @@ def add_integration():
138142
def integrations_callback(ctx: typer.Context):
139143
"""Manage Codegen integrations."""
140144
if ctx.invoked_subcommand is None:
141-
# If no subcommand is provided, show help
142-
print(ctx.get_help())
143-
raise typer.Exit()
145+
# If no subcommand is provided, run list by default
146+
list_integrations(org_id=None)

src/codegen/cli/commands/login/main.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ def login(token: str | None = typer.Option(None, help="API token for authenticat
99
"""Store authentication token."""
1010
# Check if already authenticated
1111
if get_current_token():
12-
rich.print("[yellow]Warning:[/yellow] Already authenticated. Use 'codegen logout' to clear the token.")
13-
raise typer.Exit(1)
12+
rich.print("[yellow]Info:[/yellow] You already have a token stored. Proceeding with re-authentication...")
1413

1514
login_routine(token)

src/codegen/cli/commands/mcp/__init__.py

Lines changed: 0 additions & 1 deletion
This file was deleted.

src/codegen/cli/commands/mcp/main.py

Lines changed: 0 additions & 90 deletions
This file was deleted.

src/codegen/cli/commands/tools/main.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,14 @@
77

88
from codegen.cli.api.endpoints import API_ENDPOINT
99
from codegen.cli.auth.token_manager import get_current_token
10+
from codegen.cli.rich.spinners import create_spinner
1011
from codegen.cli.utils.org import resolve_org_id
1112

1213
console = Console()
1314

1415

1516
def tools(org_id: int | None = typer.Option(None, help="Organization ID (defaults to CODEGEN_ORG_ID/REPOSITORY_ORG_ID or auto-detect)")):
1617
"""List available tools from the Codegen API."""
17-
console.print("🔧 Fetching available tools...", style="bold blue")
18-
1918
# Get the current token
2019
token = get_current_token()
2120
if not token:
@@ -29,13 +28,18 @@ def tools(org_id: int | None = typer.Option(None, help="Organization ID (default
2928
console.print("[red]Error:[/red] Organization ID not provided. Pass --org-id, set CODEGEN_ORG_ID, or REPOSITORY_ORG_ID.")
3029
raise typer.Exit(1)
3130

32-
# Make API request to list tools
33-
headers = {"Authorization": f"Bearer {token}"}
34-
url = f"{API_ENDPOINT.rstrip('/')}/v1/organizations/{resolved_org_id}/tools"
35-
response = requests.get(url, headers=headers)
36-
response.raise_for_status()
37-
38-
response_data = response.json()
31+
# Make API request to list tools with spinner
32+
spinner = create_spinner("Fetching available tools...")
33+
spinner.start()
34+
35+
try:
36+
headers = {"Authorization": f"Bearer {token}"}
37+
url = f"{API_ENDPOINT.rstrip('/')}/v1/organizations/{resolved_org_id}/tools"
38+
response = requests.get(url, headers=headers)
39+
response.raise_for_status()
40+
response_data = response.json()
41+
finally:
42+
spinner.stop()
3943

4044
# Extract tools from the response structure
4145
if isinstance(response_data, dict) and "tools" in response_data:

0 commit comments

Comments
 (0)