From 457c972a0f49467ea3a153d7e52dc35faf766286 Mon Sep 17 00:00:00 2001 From: ajspig Date: Mon, 13 Apr 2026 13:13:27 -0400 Subject: [PATCH] fix: delete key generation commands and fixing session ID --- honcho-cli/README.md | 6 - honcho-cli/src/honcho_cli/commands/key.py | 119 ------------------ honcho-cli/src/honcho_cli/commands/peer.py | 17 ++- honcho-cli/src/honcho_cli/commands/session.py | 15 +-- honcho-cli/src/honcho_cli/main.py | 2 - honcho-cli/src/honcho_cli/skills/CONTEXT.md | 1 - .../src/honcho_cli/skills/honcho-admin.md | 40 ------ 7 files changed, 13 insertions(+), 187 deletions(-) delete mode 100644 honcho-cli/src/honcho_cli/commands/key.py delete mode 100644 honcho-cli/src/honcho_cli/skills/honcho-admin.md diff --git a/honcho-cli/README.md b/honcho-cli/README.md index 1da6a562..7f6a9dab 100644 --- a/honcho-cli/README.md +++ b/honcho-cli/README.md @@ -101,12 +101,6 @@ honcho # show banner + command list | `honcho conclusion create` | Create a conclusion | | `honcho conclusion delete ` | Delete a conclusion | -### Keys - -| Command | Description | -|---------|-------------| -| `honcho key generate` | Generate a scoped JWT (workspace/peer/session) | - ### Config | Command | Description | diff --git a/honcho-cli/src/honcho_cli/commands/key.py b/honcho-cli/src/honcho_cli/commands/key.py deleted file mode 100644 index b025a1d5..00000000 --- a/honcho-cli/src/honcho_cli/commands/key.py +++ /dev/null @@ -1,119 +0,0 @@ -"""Key management commands: generate scoped JWTs.""" - -from __future__ import annotations - -import re -from datetime import datetime, timedelta, timezone -from typing import Optional - -import typer - -from honcho_cli.output import print_error, print_result, status - -from honcho_cli.common import add_common_options - -app = typer.Typer(help="JWT key management.") -add_common_options(app) - - -def _parse_duration(duration: str) -> datetime: - """Parse duration string like '30d', '24h', '90d' into expiry datetime.""" - match = re.match(r"^(\d+)([dhm])$", duration) - if not match: - print_error( - "INVALID_DURATION", - f"Invalid duration format: '{duration}'. Use format like '30d', '24h', '60m'.", - {"duration": duration}, - ) - raise typer.Exit(1) - - value = int(match.group(1)) - unit = match.group(2) - - delta = { - "d": timedelta(days=value), - "h": timedelta(hours=value), - "m": timedelta(minutes=value), - }[unit] - - return datetime.now(timezone.utc) + delta - - -@app.command() -def generate( - workspace: Optional[str] = typer.Option(None, "--workspace", help="Scope to workspace"), - peer: Optional[str] = typer.Option(None, "--peer", help="Scope to peer"), - session: Optional[str] = typer.Option(None, "--session", help="Scope to session"), - admin: bool = typer.Option(False, "--admin", help="Generate admin key"), - expires: str = typer.Option("90d", "--expires", help="Expiry duration (e.g., 30d, 24h)"), - no_expire: bool = typer.Option(False, "--no-expire", help="No expiration (use with caution)"), - json_output: bool = typer.Option(False, "--json", help="Force JSON output"), -) -> None: - """Generate a scoped JWT key. - - Requires an admin JWT in config. Generated keys are scoped down from admin. - """ - from honcho_cli.common import handle_cmd_flags - from honcho_cli.main import get_resolved_config - - handle_cmd_flags(json_output=json_output) - - config = get_resolved_config() - - if not config.api_key: - print_error("NO_API_KEY", "Admin API key required in config. Run `honcho config set api_key `.") - raise typer.Exit(3) - - if not admin and not workspace and not peer and not session: - # Default to current workspace - workspace = config.workspace_id - if not workspace: - print_error( - "NO_SCOPE", - "Must specify at least one scope: --workspace, --peer, --session, or --admin", - ) - raise typer.Exit(1) - - # Build expiry - expires_at = None - if not no_expire: - expires_at = _parse_duration(expires) - - # Use raw HTTP to call the /keys endpoint - import httpx - - base_url = config.base_url.rstrip("/") - params: dict = {} - if workspace: - params["workspace_id"] = workspace - if peer: - params["peer_id"] = peer - if session: - params["session_id"] = session - if expires_at: - params["expires_at"] = expires_at.isoformat() - - if admin: - params = {"admin": "true"} - if expires_at: - params["expires_at"] = expires_at.isoformat() - - try: - resp = httpx.post( - f"{base_url}/v3/keys", - params=params, - headers={"Authorization": f"Bearer {config.api_key}"}, - timeout=30, - ) - resp.raise_for_status() - data = resp.json() - print_result(data) - except httpx.HTTPStatusError as e: - if e.response.status_code == 401 or e.response.status_code == 403: - print_error("AUTH_ERROR", "Admin authentication required for key generation", {}) - raise typer.Exit(3) - print_error("KEY_ERROR", f"Failed to generate key: {e.response.text}", {}) - raise typer.Exit(1) - except Exception as e: - print_error("KEY_ERROR", f"Failed to generate key: {e}", {}) - raise typer.Exit(1) diff --git a/honcho-cli/src/honcho_cli/commands/peer.py b/honcho-cli/src/honcho_cli/commands/peer.py index 91fcbb23..396f26f7 100644 --- a/honcho-cli/src/honcho_cli/commands/peer.py +++ b/honcho-cli/src/honcho_cli/commands/peer.py @@ -123,11 +123,10 @@ def card( @app.command() def chat( query: str = typer.Argument(help="Question to ask about the peer"), - peer_id: Optional[str] = typer.Option(None, help="Peer ID (uses default if omitted)"), target: Optional[str] = typer.Option(None, help="Target peer for perspective"), session: Optional[str] = typer.Option(None, help="Session context"), workspace: Optional[str] = typer.Option(None, "--workspace", "-w", help="Override workspace ID"), - peer: Optional[str] = typer.Option(None, "--peer", "-p", help="Override peer ID"), + peer: Optional[str] = typer.Option(None, "--peer", "-p", help="Peer ID (uses default if omitted)"), json_output: bool = typer.Option(False, "--json", help="Force JSON output"), ) -> None: """Query the dialectic about a peer.""" @@ -135,7 +134,7 @@ def chat( from honcho_cli.main import get_client handle_cmd_flags(json_output=json_output, workspace=workspace, peer=peer) - pid = _get_peer_id(peer_id) + pid = _get_peer_id(None) client, config = get_client() p = client.peer(pid) @@ -149,10 +148,9 @@ def chat( @app.command() def search( query: str = typer.Argument(help="Search query"), - peer_id: Optional[str] = typer.Option(None, help="Peer ID (uses default if omitted)"), limit: int = typer.Option(10, help="Max results"), workspace: Optional[str] = typer.Option(None, "--workspace", "-w", help="Override workspace ID"), - peer: Optional[str] = typer.Option(None, "--peer", "-p", help="Override peer ID"), + peer: Optional[str] = typer.Option(None, "--peer", "-p", help="Peer ID (uses default if omitted)"), json_output: bool = typer.Option(False, "--json", help="Force JSON output"), ) -> None: """Search a peer's messages.""" @@ -160,7 +158,7 @@ def search( from honcho_cli.main import get_client handle_cmd_flags(json_output=json_output, workspace=workspace, peer=peer) - pid = _get_peer_id(peer_id) + pid = _get_peer_id(None) client, config = get_client() p = client.peer(pid) @@ -245,10 +243,9 @@ def get_metadata( @app.command("set-metadata") def set_metadata( - peer_id: Optional[str] = typer.Argument(None, help="Peer ID (uses default if omitted)"), - metadata: str = typer.Option(..., "--metadata", "-m", help="JSON metadata to set (e.g. '{\"key\": \"value\"}')"), + metadata: str = typer.Argument(help="JSON metadata to set (e.g. '{\"key\": \"value\"}')"), workspace: Optional[str] = typer.Option(None, "--workspace", "-w", help="Override workspace ID"), - peer: Optional[str] = typer.Option(None, "--peer", "-p", help="Override peer ID"), + peer: Optional[str] = typer.Option(None, "--peer", "-p", help="Peer ID (uses default if omitted)"), json_output: bool = typer.Option(False, "--json", help="Force JSON output"), ) -> None: """Set metadata for a peer.""" @@ -256,7 +253,7 @@ def set_metadata( from honcho_cli.main import get_client handle_cmd_flags(json_output=json_output, workspace=workspace, peer=peer) - pid = _get_peer_id(peer_id) + pid = _get_peer_id(None) client, config = get_client() try: diff --git a/honcho-cli/src/honcho_cli/commands/session.py b/honcho-cli/src/honcho_cli/commands/session.py index 047d3b4a..d8569a52 100644 --- a/honcho-cli/src/honcho_cli/commands/session.py +++ b/honcho-cli/src/honcho_cli/commands/session.py @@ -302,10 +302,9 @@ def remove_peers( @app.command() def search( query: str = typer.Argument(help="Search query"), - session_id: Optional[str] = typer.Option(None, help="Session ID (uses default if omitted)"), limit: int = typer.Option(10, help="Max results"), workspace: Optional[str] = typer.Option(None, "--workspace", "-w", help="Override workspace ID"), - session: Optional[str] = typer.Option(None, "--session", "-s", help="Override session ID"), + session: Optional[str] = typer.Option(None, "--session", "-s", help="Session ID (uses default if omitted)"), json_output: bool = typer.Option(False, "--json", help="Force JSON output"), ) -> None: """Search messages in a session.""" @@ -313,7 +312,7 @@ def search( from honcho_cli.main import get_client handle_cmd_flags(json_output=json_output, workspace=workspace, session=session) - sid = _get_session_id(session_id) + sid = _get_session_id(None) client, config = get_client() sess = client.session(sid) @@ -336,12 +335,11 @@ def search( @app.command() def representation( peer_id: str = typer.Argument(help="Peer ID to get representation for"), - session_id: Optional[str] = typer.Option(None, help="Session ID (uses default if omitted)"), target: Optional[str] = typer.Option(None, help="Target peer (what peer_id knows about target)"), search_query: Optional[str] = typer.Option(None, help="Semantic search query to filter conclusions"), max_conclusions: Optional[int] = typer.Option(None, help="Maximum number of conclusions to include"), workspace: Optional[str] = typer.Option(None, "--workspace", "-w", help="Override workspace ID"), - session: Optional[str] = typer.Option(None, "--session", "-s", help="Override session ID"), + session: Optional[str] = typer.Option(None, "--session", "-s", help="Session ID (uses default if omitted)"), json_output: bool = typer.Option(False, "--json", help="Force JSON output"), ) -> None: """Get the representation of a peer within a session.""" @@ -349,7 +347,7 @@ def representation( from honcho_cli.main import get_client handle_cmd_flags(json_output=json_output, workspace=workspace, session=session) - sid = _get_session_id(session_id) + sid = _get_session_id(None) client, config = get_client() sess = client.session(sid) @@ -391,9 +389,8 @@ def get_metadata( @app.command("set-metadata") def set_metadata( metadata: str = typer.Argument(help="JSON metadata to set (e.g. '{\"key\": \"value\"}')"), - session_id: Optional[str] = typer.Option(None, help="Session ID (uses default if omitted)"), workspace: Optional[str] = typer.Option(None, "--workspace", "-w", help="Override workspace ID"), - session: Optional[str] = typer.Option(None, "--session", "-s", help="Override session ID"), + session: Optional[str] = typer.Option(None, "--session", "-s", help="Session ID (uses default if omitted)"), json_output: bool = typer.Option(False, "--json", help="Force JSON output"), ) -> None: """Set metadata for a session.""" @@ -401,7 +398,7 @@ def set_metadata( from honcho_cli.main import get_client handle_cmd_flags(json_output=json_output, workspace=workspace, session=session) - sid = _get_session_id(session_id) + sid = _get_session_id(None) client, config = get_client() try: diff --git a/honcho-cli/src/honcho_cli/main.py b/honcho-cli/src/honcho_cli/main.py index 3eadb75a..687c714b 100644 --- a/honcho-cli/src/honcho_cli/main.py +++ b/honcho-cli/src/honcho_cli/main.py @@ -108,7 +108,6 @@ app.command()(doctor) # Register command groups from honcho_cli.commands.config_cmd import app as config_app from honcho_cli.commands.conclusion import app as conclusion_app -from honcho_cli.commands.key import app as key_app from honcho_cli.commands.message import app as message_app from honcho_cli.commands.peer import app as peer_app from honcho_cli.commands.session import app as session_app @@ -120,7 +119,6 @@ app.add_typer(peer_app, name="peer") app.add_typer(session_app, name="session") app.add_typer(message_app, name="message") app.add_typer(conclusion_app, name="conclusion") -app.add_typer(key_app, name="key") if __name__ == "__main__": diff --git a/honcho-cli/src/honcho_cli/skills/CONTEXT.md b/honcho-cli/src/honcho_cli/skills/CONTEXT.md index d676d36e..ff0973e1 100644 --- a/honcho-cli/src/honcho_cli/skills/CONTEXT.md +++ b/honcho-cli/src/honcho_cli/skills/CONTEXT.md @@ -41,4 +41,3 @@ honcho config set peer_id my-peer - `honcho session` — Inspect, messages, context, summaries - `honcho message` — List and get messages - `honcho conclusion` — List, search, create, delete conclusions -- `honcho key` — Generate scoped JWT keys diff --git a/honcho-cli/src/honcho_cli/skills/honcho-admin.md b/honcho-cli/src/honcho_cli/skills/honcho-admin.md deleted file mode 100644 index 3719d67b..00000000 --- a/honcho-cli/src/honcho_cli/skills/honcho-admin.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -name: honcho-cli-admin -version: 0.1.0 -description: Admin operations for Honcho workspaces ---- - -# Honcho CLI — Admin Skills - -## Rules - -- Always inspect before deleting: `honcho workspace inspect` then `honcho workspace delete` -- Use `--dry-run` for destructive operations to preview impact -- Generated keys default to 90-day expiry; use `--no-expire` only when intentional -- Admin JWT required for key generation and workspace deletion - -## Key Generation - -```bash -# Workspace-scoped key (90-day default) -honcho key generate --workspace my-ws --json - -# Peer-scoped key with custom expiry -honcho key generate --peer --expires 30d --json - -# No-expiry key (use with caution) -honcho key generate --workspace my-ws --no-expire --json -``` - -## Workspace Lifecycle - -```bash -# Inspect first -honcho workspace inspect --json - -# Check queue status -honcho workspace queue-status --json - -# Delete (requires --yes for non-interactive) -honcho workspace delete --yes -```