diff --git a/src/aipass/api/.aipass/aipass_local_prompt.md b/src/aipass/api/.aipass/aipass_local_prompt.md index 1599e92a..c55fbffa 100644 --- a/src/aipass/api/.aipass/aipass_local_prompt.md +++ b/src/aipass/api/.aipass/aipass_local_prompt.md @@ -13,3 +13,34 @@ API is the **centralized external API gateway** for AIPass. Provides authenticat - **Thread-safe mode:** `get_drive_service(thread_safe=True)` loads fresh creds from disk per call for concurrent workers. - **Google libs are optional deps** — guarded by `GOOGLE_AUTH_AVAILABLE` flag, commands fail explicitly with install instructions. - **After building:** Run `drone @seedgo audit aipass @api` before reporting complete. + +## Commands + +| Command | Description | +|---|---| +| `get-key [provider]` | Retrieve API key (default: openrouter) | +| `validate [provider]` | Validate API key (default: openrouter) | +| `validate google` | Validate Google OAuth2 credentials | +| `reauth google` | Re-authenticate Google OAuth2 | +| `test` | Test OpenRouter connection | +| `models [--all]` | List available models | +| `status` | OpenRouter client status | +| `call "prompt" --model MODEL` | Make API call | +| `list-providers` | List available providers | +| `init` | Create .env template | +| `track [caller]` | Track generation usage | +| `stats` | Usage statistics | +| `session` | Session usage summary | +| `caller-usage ` | Usage by caller | +| `cleanup [days]` | Clean old usage data (default: 30) | + +## Architecture + +``` +api.py (entry, routing) + → modules/ (orchestration, CLI) + → handlers/ (business logic) +``` + +**Modules:** `api_key`, `openrouter_client`, `usage_tracker`, `google_client` +**Handlers:** `auth/`, `config/`, `openrouter/`, `usage/`, `json/`, `google/` diff --git a/src/aipass/api/apps/handlers/openrouter/provision.py b/src/aipass/api/apps/handlers/openrouter/provision.py index 8758ad10..9e17fe8a 100644 --- a/src/aipass/api/apps/handlers/openrouter/provision.py +++ b/src/aipass/api/apps/handlers/openrouter/provision.py @@ -20,10 +20,9 @@ Business logic for provisioning OpenRouter API configs: - Ensure caller has complete 3-file JSON structure """ -from pathlib import Path - import json from datetime import datetime +from pathlib import Path from typing import Dict, Any, Optional from aipass.prax import logger diff --git a/src/aipass/drone/apps/drone.py b/src/aipass/drone/apps/drone.py index ee87bcdc..27f06f5c 100644 --- a/src/aipass/drone/apps/drone.py +++ b/src/aipass/drone/apps/drone.py @@ -18,6 +18,8 @@ import sys from pathlib import Path from typing import List +from rich.text import Text + from aipass.prax import logger from aipass.cli.apps.modules import console, err_console from aipass.drone.apps.modules import BranchNotFoundError, CommandExecutionError, RegistryError @@ -176,7 +178,9 @@ def _handle_module(name: str, args: List[str]) -> int: if not args: intro_text = get_module_introspective(name) if intro_text: - console.print(intro_text, end="") + # Text.from_ansi handles both pre-formatted ANSI (external modules) + # and plain text (internal modules) correctly + console.print(Text.from_ansi(intro_text), end="") else: console.print(f"No information available for @{name}.") return 0 @@ -184,7 +188,7 @@ def _handle_module(name: str, args: List[str]) -> int: if args == ["--help"]: help_text = get_module_help(name) if help_text: - console.print(help_text, end="") + console.print(Text.from_ansi(help_text), end="") else: console.print(f"No help available for @{name}.") return 0 diff --git a/src/aipass/drone/apps/handlers/git/sync_handler.py b/src/aipass/drone/apps/handlers/git/sync_handler.py index 3c5aaeeb..a1354fb1 100644 --- a/src/aipass/drone/apps/handlers/git/sync_handler.py +++ b/src/aipass/drone/apps/handlers/git/sync_handler.py @@ -41,7 +41,7 @@ def sync_main() -> dict: return {"success": False, "message": msg, "stdout": result.stdout} result = subprocess.run( - ["git", "pull"], + ["git", "pull", "--rebase"], capture_output=True, text=True, cwd=str(repo_root), ) if result.returncode != 0: diff --git a/src/commons/apps/modules/artifact.py b/src/commons/apps/modules/artifact.py index 859b9378..a750668b 100644 --- a/src/commons/apps/modules/artifact.py +++ b/src/commons/apps/modules/artifact.py @@ -63,9 +63,6 @@ def handle_command(command: str, args: List[str]) -> bool: return False if command == "craft": - if not args: - print_introspection() - return True result = _handle_craft(args) elif command == "artifacts": result = _handle_list(args) diff --git a/src/commons/apps/modules/capsule.py b/src/commons/apps/modules/capsule.py index 05224031..22bfb7ac 100644 --- a/src/commons/apps/modules/capsule.py +++ b/src/commons/apps/modules/capsule.py @@ -59,9 +59,6 @@ def handle_command(command: str, args: List[str]) -> bool: return False if command == "capsule": - if not args: - print_introspection() - return True result = _handle_seal(args) elif command == "capsules": result = _handle_list(args) diff --git a/src/commons/apps/modules/central.py b/src/commons/apps/modules/central.py index 90c0cb19..70c2526c 100644 --- a/src/commons/apps/modules/central.py +++ b/src/commons/apps/modules/central.py @@ -61,10 +61,6 @@ def handle_command(command: str, args: List[str]) -> bool: if command != "push-central": return False - if not args: - print_introspection() - return True - try: stats = update_central() branch_count = len(stats.get("branch_stats", {})) diff --git a/src/commons/apps/modules/comment.py b/src/commons/apps/modules/comment.py index 506b9bf3..9b7001d0 100644 --- a/src/commons/apps/modules/comment.py +++ b/src/commons/apps/modules/comment.py @@ -62,9 +62,6 @@ def handle_command(command: str, args: List[str]) -> bool: True if command handled, False otherwise. """ if command == "comment": - if not args: - print_introspection() - return True result = _handle_comment(args) elif command == "vote": result = _handle_vote(args) diff --git a/src/commons/apps/modules/post.py b/src/commons/apps/modules/post.py index 7bd11a96..ae363302 100644 --- a/src/commons/apps/modules/post.py +++ b/src/commons/apps/modules/post.py @@ -66,9 +66,6 @@ def handle_command(command: str, args: List[str]) -> bool: True if command handled, False otherwise. """ if command == "post": - if not args: - print_introspection() - return True result = _handle_create_post(args) elif command == "thread": result = _handle_view_thread(args) diff --git a/src/commons/apps/modules/profile.py b/src/commons/apps/modules/profile.py index 3b2a1abc..d227235d 100644 --- a/src/commons/apps/modules/profile.py +++ b/src/commons/apps/modules/profile.py @@ -62,9 +62,6 @@ def handle_command(command: str, args: List[str]) -> bool: True if command handled, False otherwise """ if command == "profile": - if not args: - print_introspection() - return True result = _handle_profile(args) elif command == "who": result = _handle_who(args) diff --git a/src/commons/apps/modules/trade.py b/src/commons/apps/modules/trade.py index 8581188f..b9694733 100644 --- a/src/commons/apps/modules/trade.py +++ b/src/commons/apps/modules/trade.py @@ -65,9 +65,6 @@ def handle_command(command: str, args: List[str]) -> bool: return False if command == "gift": - if not args: - print_introspection() - return True result = _handle_gift(args) elif command == "trade": result = _handle_trade(args)