Improve type safety and fix minor issues in beads-mcp

Type Safety Improvements:
- Change dict → dict[str, Any] throughout codebase for explicit typing
- Add PEP 561 py.typed marker file to export type information
- Add types-requests to dev dependencies
- Improve signal handler typing (FrameType | None)
- Improve decorator typing (Callable[..., Awaitable[T]])
- Add quickstart() abstract method to BdClientBase for interface completeness

Bug Fixes:
- Fix variable shadowing: beads_dir → local_beads_dir in bd_client.py
- Improve error handling in mail.py:_call_agent_mail() to prevent undefined error
- Make working_dir required (not Optional) in BdDaemonClient
- Remove unnecessary 'or' defaults for required Pydantic fields

Validation:
- mypy passes with no errors
- All unit tests passing
- Daemon quickstart returns helpful static text (RPC doesn't support this command)
This commit is contained in:
Steve Yegge
2025-11-20 19:26:44 -05:00
parent e1c8853748
commit 9e57cb69d8
9 changed files with 96 additions and 54 deletions

View File

@@ -21,7 +21,7 @@ AGENT_MAIL_RETRIES = 2
class MailError(Exception):
"""Base exception for Agent Mail errors."""
def __init__(self, code: str, message: str, data: Optional[dict] = None):
def __init__(self, code: str, message: str, data: Optional[dict[str, Any]] = None):
self.code = code
self.message = message
self.data = data or {}
@@ -97,9 +97,9 @@ def _get_project_key() -> str:
def _call_agent_mail(
method: str,
endpoint: str,
json_data: Optional[dict] = None,
params: Optional[dict] = None,
) -> dict[str, Any]:
json_data: Optional[dict[str, Any]] = None,
params: Optional[dict[str, Any]] = None,
) -> Any:
"""Make HTTP request to Agent Mail server with retries.
Args:
@@ -205,7 +205,9 @@ def _call_agent_mail(
time.sleep(0.5 * (2**attempt))
# All retries exhausted
raise last_error
if last_error:
raise last_error
raise MailError("INTERNAL_ERROR", "Request failed with no error details")
def mail_send(
@@ -350,7 +352,7 @@ def mail_inbox(
)
# Agent Mail returns list of messages directly
messages = result if isinstance(result, list) else []
messages: list[dict[str, Any]] = result if isinstance(result, list) else []
# Transform to our format and filter unread if requested
formatted_messages = []