""" Trello Plugin — Hermes Agent tool definitions. Each function decorated with ``@tool`` registers itself as a Hermes tool that the agent can invoke during a conversation. """ from __future__ import annotations import json import os from typing import Any from trello_plugin.client import TrelloClient # --------------------------------------------------------------------------- # Module-level client (lazily initialised so env vars can be overridden) # --------------------------------------------------------------------------- _client: TrelloClient | None = None def _get_client() -> TrelloClient: global _client # noqa: PLW0603 api_key = os.environ.get("TRELLO_API_KEY", "") token = os.environ.get("TRELLO_TOKEN", "") if _client is None or _client.api_key != api_key or _client.token != token: _client = TrelloClient(api_key=api_key, token=token) return _client # --------------------------------------------------------------------------- # Tool helpers # --------------------------------------------------------------------------- def _respond(data: dict[str, Any]) -> str: """Wrap a result dict in a JSON string, the Hermes tool contract.""" return json.dumps(data, indent=2) # --------------------------------------------------------------------------- # Tools # --------------------------------------------------------------------------- def trello_verify_credentials() -> str: """Verify that the Trello API key and token are valid. Checks the ``TRELLO_API_KEY`` and ``TRELLO_TOKEN`` environment variables and attempts a test call to the Trello API. Returns the authenticated user's Trello username on success. """ client = _get_client() result = client.verify_credentials() return _respond(result) def trello_list_boards() -> str: """List all Trello boards accessible to the authenticated user. Requires ``TRELLO_API_KEY`` and ``TRELLO_TOKEN`` to be set. Returns board id, name, URL, and whether the board is closed/starred. """ client = _get_client() result = client.list_boards() return _respond(result) def trello_disconnect() -> str: """Disconnect from Trello by clearing credentials from memory. This does NOT revoke the Trello token — invalidate it via Trello's account settings if full revocation is desired. """ global _client # noqa: PLW0603 _client = None return _respond({"success": True, "message": "Trello credentials cleared from memory. Next tool call will re-read TRELLO_API_KEY and TRELLO_TOKEN from environment and reconnect automatically."}) # --------------------------------------------------------------------------- # Tools — Board Management # --------------------------------------------------------------------------- def trello_create_board(name: str, default_lists: bool = True) -> str: # noqa: FBT001, FBT002 """Create a new Trello board. Parameters ---------- name : str The name for the new board. default_lists : bool, optional Whether to create default lists (default: True). Returns ------- str JSON with board id, name, and URL on success. """ client = _get_client() result = client.create_board(name=name, default_lists=default_lists) return _respond(result) def trello_rename_board(board_id: str, name: str) -> str: """Rename an existing Trello board. Parameters ---------- board_id : str Board ID or name. name : str The new name for the board. Returns ------- str JSON with updated board details on success. """ client = _get_client() result = client.rename_board(board_id=board_id, name=name) return _respond(result) def trello_archive_board(board_id: str) -> str: """Close/archive a Trello board. Parameters ---------- board_id : str Board ID or name. Returns ------- str JSON with success message. """ client = _get_client() result = client.archive_board(board_id=board_id) return _respond(result) def trello_open_board(board_id: str) -> str: """Re-open a closed/archived Trello board. Parameters ---------- board_id : str Board ID or name. Returns ------- str JSON with success message. """ client = _get_client() result = client.open_board(board_id=board_id) return _respond(result) def trello_board_details(board_id: str) -> str: """View details of a Trello board, including its lists and members. Parameters ---------- board_id : str Board ID or name. Returns ------- str JSON with board details including lists and members. """ client = _get_client() result = client.board_details(board_id=board_id) return _respond(result) # --------------------------------------------------------------------------- # Tools — List Management # --------------------------------------------------------------------------- def trello_create_list(name: str, board_id: str, pos: str = "bottom") -> str: """Create a new list on a Trello board. Parameters ---------- name : str The name for the new list. board_id : str Board ID or name. pos : str, optional Position: ``"top"``, ``"bottom"``, or a number (default: ``"bottom"``). Returns ------- str JSON with list details on success. """ client = _get_client() result = client.create_list(name=name, board_id=board_id, pos=pos) return _respond(result) def trello_rename_list(list_id: str, name: str) -> str: """Rename an existing list. Parameters ---------- list_id : str Trello list ID. name : str The new name. Returns ------- str JSON with updated list details on success. """ client = _get_client() result = client.rename_list(list_id=list_id, name=name) return _respond(result) def trello_archive_list(list_id: str) -> str: """Archive a list. Parameters ---------- list_id : str Trello list ID. Returns ------- str JSON with success message. """ client = _get_client() result = client.archive_list(list_id=list_id) return _respond(result) def trello_move_list(list_id: str, pos: str = "bottom") -> str: """Move a list to a different position on the board. Parameters ---------- list_id : str Trello list ID. pos : str, optional Position: ``"top"``, ``"bottom"``, or a number (default: ``"bottom"``). Returns ------- str JSON with success message. """ client = _get_client() result = client.move_list(list_id=list_id, pos=pos) return _respond(result) # --------------------------------------------------------------------------- # Tools — Card Management # --------------------------------------------------------------------------- def trello_create_card(name: str, list_id: str, desc: str = "", due: str | None = None) -> str: """Create a new card on a Trello list. Parameters ---------- name : str Card title. list_id : str List ID. desc : str, optional Card description. due : str, optional Due date in ISO 8601 format. Returns ------- str JSON with card details. """ client = _get_client() result = client.create_card(name=name, list_id=list_id, desc=desc, due=due) return _respond(result) def trello_card_details(card_id: str) -> str: """View detailed information about a Trello card. Parameters ---------- card_id : str Card ID. Returns ------- str JSON with full card details including members, checklists, and comments. """ client = _get_client() result = client.card_details(card_id=card_id) return _respond(result) def trello_update_card(card_id: str, name: str | None = None, desc: str | None = None, due: str | None = None) -> str: """Update a card's core attributes (title, description, due date). Parameters ---------- card_id : str Card ID. name : str, optional New title. desc : str, optional New description. due : str, optional New due date ISO 8601. Returns ------- str JSON with updated card details. """ client = _get_client() result = client.update_card(card_id=card_id, name=name, desc=desc, due=due) return _respond(result) def trello_move_card(card_id: str, list_id: str) -> str: """Move a card to a different list. Parameters ---------- card_id : str Card ID. list_id : str Target list ID. Returns ------- str JSON with success message. """ client = _get_client() result = client.move_card(card_id=card_id, list_id=list_id) return _respond(result) def trello_archive_card(card_id: str) -> str: """Archive a Trello card. Parameters ---------- card_id : str Card ID. Returns ------- str JSON with success message. """ client = _get_client() result = client.archive_card(card_id=card_id) return _respond(result) def trello_assign_member(card_id: str, member_id: str) -> str: """Add a member to a Trello card. Parameters ---------- card_id : str Card ID. member_id : str Trello member ID. Returns ------- str JSON with success message. """ client = _get_client() result = client.assign_member(card_id=card_id, member_id=member_id) return _respond(result) def trello_remove_member(card_id: str, member_id: str) -> str: """Remove a member from a Trello card. Parameters ---------- card_id : str Card ID. member_id : str Trello member ID. Returns ------- str JSON with success message. """ client = _get_client() result = client.remove_member(card_id=card_id, member_id=member_id) return _respond(result) def trello_add_comment(card_id: str, text: str) -> str: """Add a comment to a Trello card. Parameters ---------- card_id : str Card ID. text : str Comment text. Returns ------- str JSON with comment ID. """ client = _get_client() result = client.add_comment(card_id=card_id, text=text) return _respond(result) def trello_delete_comment(card_id: str, comment_id: str) -> str: """Delete a comment from a Trello card. Parameters ---------- card_id : str Card ID. comment_id : str Comment/action ID. Returns ------- str JSON with success message. """ client = _get_client() result = client.delete_comment(card_id=card_id, comment_id=comment_id) return _respond(result) def trello_add_checklist_item(card_id: str, name: str, checklist_id: str | None = None) -> str: """Add a checklist item to a Trello card. Parameters ---------- card_id : str Card ID. name : str Checklist item text. checklist_id : str, optional Specific checklist ID (auto-discovers the first if omitted). Returns ------- str JSON with item details. """ client = _get_client() result = client.add_checklist_item(card_id=card_id, name=name, checklist_id=checklist_id) return _respond(result) def trello_toggle_checklist_item(card_id: str, item_id: str, checked: bool) -> str: # noqa: FBT001 """Mark a checklist item as complete or incomplete. Parameters ---------- card_id : str Card ID. item_id : str Checklist item ID. checked : bool True = complete, False = incomplete. Returns ------- str JSON with updated item state. """ client = _get_client() result = client.toggle_checklist_item(card_id=card_id, item_id=item_id, checked=checked) return _respond(result) def trello_delete_checklist_item(card_id: str, item_id: str) -> str: """Remove a checklist item from a Trello card. Parameters ---------- card_id : str Card ID. item_id : str Checklist item ID. Returns ------- str JSON with success message. """ client = _get_client() result = client.delete_checklist_item(card_id=card_id, item_id=item_id) return _respond(result) # --------------------------------------------------------------------------- # Plugin metadata (used by Hermes plugin loader) # --------------------------------------------------------------------------- PLUGIN_NAME = "trello-plugin" PLUGIN_DESCRIPTION = "Hermes Agent plugin for Trello board integration" PLUGIN_VERSION = "0.1.0" PLUGIN_TOOLS = [ trello_verify_credentials, trello_list_boards, trello_disconnect, trello_create_board, trello_rename_board, trello_archive_board, trello_open_board, trello_board_details, trello_create_list, trello_rename_list, trello_archive_list, trello_move_list, trello_create_card, trello_card_details, trello_update_card, trello_move_card, trello_archive_card, trello_assign_member, trello_remove_member, trello_add_comment, trello_delete_comment, trello_add_checklist_item, trello_toggle_checklist_item, trello_delete_checklist_item, ] PLUGIN_REQUIRES_ENV = ["TRELLO_API_KEY", "TRELLO_TOKEN"] def check_requirements() -> bool: """Return True when both Trello env vars are present.""" return TrelloClient.check_requirements()