feat: Enhance command documentation and usage information

- Updated the `generate_html` function to include detailed command usage information, including syntax, examples, and parameters for better user guidance.
- Added CSS styles for improved presentation of command usage and parameters in the generated website documentation.
- Enhanced command classes with structured documentation fields, allowing for consistent and informative command descriptions across the platform.
This commit is contained in:
agessaman
2026-01-15 20:04:58 -08:00
parent 2b3f3489bd
commit d2abc49048
31 changed files with 581 additions and 43 deletions
+89 -5
View File
@@ -455,7 +455,6 @@ def generate_html(bot_name: str, title: str, introduction: str, commands: List[T
for cmd_name, cmd_instance in category_commands:
primary_name = cmd_instance.name if hasattr(cmd_instance, 'name') else cmd_name
description = getattr(cmd_instance, 'description', 'No description available')
keywords = getattr(cmd_instance, 'keywords', [])
# Filter out the primary name from keywords to avoid duplication
@@ -464,6 +463,23 @@ def generate_html(bot_name: str, title: str, introduction: str, commands: List[T
# Get channel restriction info
channel_info = get_channel_info(cmd_instance, monitor_channels)
# Get usage information including usage syntax, examples, parameters, and sub-commands
try:
usage_info = cmd_instance.get_usage_info()
usage_syntax = usage_info.get('usage', '')
examples = usage_info.get('examples', [])
parameters = usage_info.get('parameters', [])
subcommands = usage_info.get('subcommands', [])
# Use short_description for website if available, otherwise fallback to description
short_desc = usage_info.get('short_description', '')
description = short_desc if short_desc else usage_info.get('description', 'No description available')
except Exception:
usage_syntax = ''
examples = []
parameters = []
subcommands = []
description = getattr(cmd_instance, 'description', 'No description available')
commands_html += f' <div class="command-card">\n'
commands_html += f' <div class="command-header">\n'
commands_html += f' <h3 class="command-name">{escape_html(primary_name)}</h3>\n'
@@ -485,11 +501,28 @@ def generate_html(bot_name: str, title: str, introduction: str, commands: List[T
commands_html += f' </div>\n'
commands_html += f' <p class="command-description">{escape_html(description)}</p>\n'
# Get usage information including sub-commands
# Render usage, examples, parameters, subcommands
try:
usage_info = cmd_instance.get_usage_info()
subcommands = usage_info.get('subcommands', [])
# Render usage syntax
if usage_syntax:
commands_html += f' <div class="command-usage"><code>{escape_html(usage_syntax)}</code></div>\n'
# Render parameters
if parameters:
commands_html += f' <div class="command-params">\n'
commands_html += f' <div class="params-header">Parameters:</div>\n'
for param in parameters:
param_name = param.get('name', '')
param_desc = param.get('description', '')
if param_name and param_desc:
commands_html += f' <div class="param-item">\n'
commands_html += f' <span class="param-name">{escape_html(param_name)}</span>\n'
commands_html += f' <span class="param-desc">{escape_html(param_desc)}</span>\n'
commands_html += f' </div>\n'
commands_html += f' </div>\n'
# Render subcommands
if subcommands:
commands_html += f' <div class="command-subcommands">\n'
commands_html += f' <div class="subcommands-header">Sub-commands:</div>\n'
@@ -569,7 +602,7 @@ def generate_html(bot_name: str, title: str, introduction: str, commands: List[T
--accent-yellow: #ffd700;
--text-primary: #e8edf4;
--text-secondary: #8892a4;
--text-muted: #4a5568;
--text-muted: #6b7280;
--border-subtle: rgba(255,255,255,0.06);
--glow-blue: rgba(0, 212, 255, 0.15);
--glow-cyan: rgba(0, 255, 200, 0.1);
@@ -1067,6 +1100,57 @@ def generate_html(bot_name: str, title: str, introduction: str, commands: List[T
font-size: 0.95rem;
}}
.command-usage {{
margin: 0.75rem 0;
padding: 0.6rem 0.9rem;
background: rgba(0, 0, 0, 0.3);
border-radius: 8px;
border-left: 3px solid var(--accent-blue);
}}
.command-usage code {{
font-family: 'JetBrains Mono', monospace;
font-size: 0.85rem;
color: var(--accent-cyan);
}}
.command-params {{
margin-top: 0.75rem;
padding-top: 0.75rem;
border-top: 1px solid var(--border-subtle);
}}
.params-header {{
font-size: 0.8rem;
font-weight: 600;
color: var(--text-muted);
margin-bottom: 0.5rem;
text-transform: uppercase;
letter-spacing: 0.05em;
}}
.param-item {{
display: flex;
gap: 0.5rem;
margin-bottom: 0.4rem;
font-size: 0.85rem;
align-items: flex-start;
}}
.param-name {{
font-family: 'JetBrains Mono', monospace;
color: var(--accent-orange);
font-weight: 500;
min-width: 80px;
flex-shrink: 0;
}}
.param-desc {{
color: var(--text-secondary);
flex: 1;
line-height: 1.4;
}}
.command-subcommands {{
margin-top: 1rem;
padding-top: 1rem;
+10
View File
@@ -29,6 +29,16 @@ class AirplanesCommand(BaseCommand):
cooldown_seconds = 2 # Respect API rate limit of 1 req/sec with buffer
requires_internet = True
# Documentation
short_description = "Get aircraft overhead using ADS-B data"
usage = "airplanes [lat,lon|here] [radius=N] [options]"
examples = ["airplanes", "overhead 47.6,-122.3"]
parameters = [
{"name": "location", "description": "Coordinates or here for your companion's location if advertised"},
{"name": "radius", "description": "Search radius in nautical miles (default: 25)"},
{"name": "filters", "description": "alt=, type=, military, closest, etc."}
]
def __init__(self, bot):
super().__init__(bot)
self.airplanes_enabled = self.get_config_value('Airplanes_Command', 'enabled', fallback=True, value_type='bool')
+9
View File
@@ -178,6 +178,15 @@ class AlertCommand(BaseCommand):
description = "Get active emergency incidents (usage: alert seattle, alert 98258, alert 178th seattle, alert seattle all)"
category = "emergency"
cooldown_seconds = 10 # 10 second cooldown to prevent API abuse
# Documentation
short_description = "Get active emergency incidents from PulsePoint"
usage = "alert <location> [all]"
examples = ["alert seattle", "alert 98101 all"]
parameters = [
{"name": "location", "description": "City, zip code, or street address"},
{"name": "all", "description": "Show all incidents (not just nearby)"}
]
requires_internet = True # Requires internet access for PulsePoint API
def __init__(self, bot):
@@ -25,6 +25,15 @@ class GlobalWxCommand(BaseCommand):
cooldown_seconds = 5 # 5 second cooldown per user to prevent API abuse
requires_internet = True # Requires internet access for Open-Meteo API and geocoding
# Documentation
short_description = "Get weather for any global location using Open-Meteo API"
usage = "gwx <location> [tomorrow|7d|hourly]"
examples = ["gwx Tokyo", "gwx Paris, France"]
parameters = [
{"name": "location", "description": "City name, country, or coordinates"},
{"name": "option", "description": "tomorrow, 7d, or hourly (optional)"}
]
# Error constants - will use translations instead
ERROR_FETCHING_DATA = "ERROR_FETCHING_DATA" # Placeholder, will use translate()
NO_ALERTS = "No weather alerts available"
+8
View File
@@ -31,6 +31,14 @@ class AqiCommand(BaseCommand):
cooldown_seconds = 5 # 5 second cooldown per user to prevent API abuse
requires_internet = True # Requires internet access for OpenMeteo API and geocoding
# Documentation
short_description = "Get Air Quality Index for a location"
usage = "aqi <city|neighborhood|coordinates|help>"
examples = ["aqi seattle", "aqi 47.6,-122.3"]
parameters = [
{"name": "location", "description": "City, neighborhood, lat/lon, or 'help'"}
]
# Error constants
ERROR_FETCHING_DATA = "Error fetching AQI data"
NO_DATA_AVAILABLE = "No AQI data available"
+26 -12
View File
@@ -31,6 +31,7 @@ class BaseCommand(ABC):
category: str = "general"
# Documentation fields - to be overridden by subclasses for website generation
short_description: str = "" # Brief description for website (without usage syntax)
usage: str = "" # Usage syntax, e.g., "wx <zipcode|city> [tomorrow|7d|hourly|alerts]"
examples: List[str] = [] # Example commands, e.g., ["wx 98101", "wx seattle tomorrow"]
parameters: List[Dict[str, str]] = [] # Parameter definitions, e.g., [{"name": "location", "description": "US zip code or city name"}]
@@ -176,21 +177,28 @@ class BaseCommand(ABC):
def get_usage_info(self) -> Dict[str, Any]:
"""Get structured usage information including sub-commands and options.
Uses class attributes as defaults, with translation overrides for i18n support.
Returns:
Dict with keys:
- 'description': Main command description
- 'description': Main command description (for help text)
- 'short_description': Brief description for website (without usage syntax)
- 'usage': Usage syntax string (e.g., "wx <zipcode|city> [option]")
- 'subcommands': List of dicts with 'name' and 'description'
- 'usage_patterns': List of usage pattern strings
- 'examples': List of example strings
- 'parameters': List of dicts with 'name' and 'description'
"""
# Start with class attribute defaults
usage_info = {
'description': self.description or "No description available",
'short_description': self.short_description or "",
'usage': self.usage or "",
'subcommands': [],
'usage_patterns': [],
'examples': []
'examples': list(self.examples) if self.examples else [],
'parameters': list(self.parameters) if self.parameters else []
}
# Try to get structured data from translations
# Try to get structured data from translations (i18n overrides)
if hasattr(self.bot, 'translator'):
try:
# Get subcommands from translations
@@ -199,17 +207,23 @@ class BaseCommand(ABC):
if subcommands_data and isinstance(subcommands_data, list):
usage_info['subcommands'] = subcommands_data
# Get usage patterns from translations
usage_patterns_key = f"commands.{self.name}.usage_patterns"
usage_patterns_data = self.translate_get_value(usage_patterns_key)
if usage_patterns_data and isinstance(usage_patterns_data, list):
usage_info['usage_patterns'] = usage_patterns_data
# Get examples from translations
# Get examples from translations (override class attribute)
examples_key = f"commands.{self.name}.examples"
examples_data = self.translate_get_value(examples_key)
if examples_data and isinstance(examples_data, list):
usage_info['examples'] = examples_data
# Get usage from translations (override class attribute)
usage_key = f"commands.{self.name}.usage_syntax"
usage_data = self.translate_get_value(usage_key)
if usage_data and isinstance(usage_data, str):
usage_info['usage'] = usage_data
# Get parameters from translations (override class attribute)
params_key = f"commands.{self.name}.parameters"
params_data = self.translate_get_value(params_key)
if params_data and isinstance(params_data, list):
usage_info['parameters'] = params_data
except Exception as e:
self.logger.debug(f"Could not load usage info from translations for {self.name}: {e}")
+10
View File
@@ -24,6 +24,16 @@ class ChannelsCommand(BaseCommand):
description = "Lists hashtag channels with sub-categories. Use 'channels' for general, 'channels list' for all categories, 'channels <category>' for specific categories, 'channels #channel' for specific channel info."
category = "basic"
# Documentation
short_description = "Lists hashtag channels with sub-categories"
usage = "channels [list|category|#channel]"
examples = ["channels", "channels list"]
parameters = [
{"name": "list", "description": "Show all channel categories"},
{"name": "category", "description": "Filter by category name"},
{"name": "#channel", "description": "Get info on a specific channel"}
]
def __init__(self, bot):
"""Initialize the channels command.
+5
View File
@@ -18,6 +18,11 @@ class CmdCommand(BaseCommand):
description = "Lists available commands in compact format"
category = "basic"
# Documentation
short_description = "Lists available commands"
usage = "cmd"
examples = ["cmd"]
def __init__(self, bot):
"""Initialize the cmd command.
+5
View File
@@ -24,6 +24,11 @@ class DadJokeCommand(BaseCommand):
cooldown_seconds = 3
requires_internet = True # Requires internet access for API calls
# Documentation
short_description = "Get a random dad joke"
usage = "dadjoke"
examples = ["dadjoke"]
# API configuration
DAD_JOKE_API_URL = "https://icanhazdadjoke.com/"
TIMEOUT = 10 # seconds
+14
View File
@@ -18,6 +18,20 @@ class DiceCommand(BaseCommand):
description = "Roll dice for D&D and tabletop games. Use 'dice' for d6, 'dice d20' for d20, 'dice 2d6' for 2d6, 'dice d10 d6' for mixed dice, 'dice decade' for decade die (00-90), etc."
category = "games"
# Documentation
short_description = "Roll dice for tabletop games"
usage = "dice [NdX|dX|decade]"
examples = [
"dice",
"dice d20",
"dice 2d6",
"dice d10 d6",
"dice decade"
]
parameters = [
{"name": "dice", "description": "Dice notation: d6, 2d8, d10 d6, decade"}
]
# Standard D&D dice types
DICE_TYPES = {
'd4': 4,
+5
View File
@@ -22,6 +22,11 @@ class HackerCommand(BaseCommand):
description = "Simulates hacking a supervillain's mainframe with hilarious error messages"
category = "fun"
# Documentation
short_description = "Try Linux commands and get supervillain mainframe errors"
usage = "<linux_command>"
examples = ["sudo make me a sandwich", "rm -rf /"]
def __init__(self, bot: Any):
"""Initialize the hacker command.
+5
View File
@@ -19,6 +19,11 @@ class HelloCommand(BaseCommand):
description = "Responds to greetings with robot-themed responses"
category = "basic"
# Documentation
short_description = "Responds to greetings with robot-themed responses"
usage = "hello"
examples = ["hello", "hi", "hey"]
def __init__(self, bot: Any):
"""Initialize the hello command.
+8
View File
@@ -25,6 +25,14 @@ class HelpCommand(BaseCommand):
description = "Shows commands. Use 'help <command>' for details."
category = "basic"
# Documentation
short_description = "Get help on available commands"
usage = "help [command]"
examples = ["help", "help wx"]
parameters = [
{"name": "command", "description": "Command name for detailed help (optional)"}
]
def __init__(self, bot):
"""Initialize the help command.
+5
View File
@@ -22,6 +22,11 @@ class HfcondCommand(BaseCommand):
category = "solar"
requires_internet = True # Requires internet access for hamqsl.com API
# Documentation
short_description = "Get HF band conditions for ham radio"
usage = "hfcond"
examples = ["hfcond"]
def __init__(self, bot):
"""Initialize the hfcond command.
+8
View File
@@ -24,6 +24,14 @@ class JokeCommand(BaseCommand):
requires_dm = False # Works in both channels and DMs
requires_internet = True # Requires internet access for API calls
# Documentation
short_description = "Get a random joke"
usage = "joke [category]"
examples = ["joke", "joke programming"]
parameters = [
{"name": "category", "description": "programming, pun, misc, dark (optional)"}
]
# Supported categories
SUPPORTED_CATEGORIES = {
'programming': 'Programming',
+5
View File
@@ -27,6 +27,11 @@ class Magic8Command(BaseCommand):
description = "Emulates the classic Magic 8-ball toy'"
category = "games"
# Documentation
short_description = "Ask the Magic 8-Ball a yes/no question"
usage = "magic8 <question>"
examples = ["magic8 Will it rain tomorrow?"]
def __init__(self, bot):
"""Initialize the magic8 command.
+5
View File
@@ -17,6 +17,11 @@ class MoonCommand(BaseCommand):
description = "Get moon phase, rise/set times and position"
category = "solar"
# Documentation
short_description = "Get moon phase and rise/set times"
usage = "moon"
examples = ["moon"]
def __init__(self, bot):
"""Initialize the moon command.
+5
View File
@@ -21,6 +21,11 @@ class MultitestCommand(BaseCommand):
description = "Listens for 6 seconds and collects all unique paths from incoming messages"
category = "meshcore_info"
# Documentation
short_description = "Listens for 6 seconds and collects all unique paths your incoming messages took to reach the bot"
usage = "multitest"
examples = ["multitest", "mt"]
def __init__(self, bot):
super().__init__(bot)
self.multitest_enabled = self.get_config_value('Multitest_Command', 'enabled', fallback=True, value_type='bool')
+5
View File
@@ -24,6 +24,11 @@ class PathCommand(BaseCommand):
cooldown_seconds = 1
category = "meshcore_info"
# Documentation
short_description = "Decode path data to show repeaters involved in message routing"
usage = "path [hex_data]"
examples = ["path", "decode"]
def __init__(self, bot):
super().__init__(bot)
self.path_enabled = self.get_config_value('Path_Command', 'enabled', fallback=True, value_type='bool')
+5
View File
@@ -22,6 +22,11 @@ class PingCommand(BaseCommand):
description = "Responds to 'ping' with 'Pong!'"
category = "basic"
# Documentation
short_description = "Get a quick 'pong'response from the bot"
usage = "ping"
examples = ["ping"]
def __init__(self, bot):
"""Initialize the ping command.
+9
View File
@@ -27,6 +27,15 @@ class PrefixCommand(BaseCommand):
cooldown_seconds = 2
requires_internet = False # Will be set to True in __init__ if API is configured
# Documentation
short_description = "Look up repeaters by two-character prefix and show their locations (if known)"
usage = "prefix <XX|free|refresh>"
examples = ["prefix 1A", "prefix free"]
parameters = [
{"name": "prefix", "description": "Two-character prefix (e.g., 1A, 2B)"},
{"name": "free", "description": "Show available/unused prefixes"}
]
def __init__(self, bot: Any):
"""Initialize the prefix command.
+8
View File
@@ -24,6 +24,14 @@ class RollCommand(BaseCommand):
description = "Roll a random number between 1 and X (default 100). Use 'roll' for 1-100, 'roll 50' for 1-50, etc."
category = "games"
# Documentation
short_description = "Roll a random number between 1 and X"
usage = "roll [max]"
examples = ["roll", "roll 50"]
parameters = [
{"name": "max", "description": "Maximum value (default: 100, max: 10000)"}
]
def __init__(self, bot):
"""Initialize the roll command.
+9
View File
@@ -18,6 +18,15 @@ class SatpassCommand(BaseCommand):
category = "solar"
requires_internet = True # Requires internet access for N2YO API
# Documentation
short_description = "Get satellite pass predictions"
usage = "satpass <NORAD_number|shortcut> [visual]"
examples = ["satpass iss", "satpass 25544 visual"]
parameters = [
{"name": "satellite", "description": "NORAD ID or shortcut (iss, hst, starlink)"},
{"name": "visual", "description": "Add 'visual' for visible passes only"}
]
# Common satellite shortcuts
SATELLITE_SHORTCUTS = {
'iss': '25544',
+5
View File
@@ -22,6 +22,11 @@ class SolarCommand(BaseCommand):
category = "solar"
requires_internet = True # Requires internet access for hamqsl.com API
# Documentation
short_description = "Get current solar conditions and HF band info"
usage = "solar"
examples = ["solar"]
def __init__(self, bot):
"""Initialize the solar command.
+11
View File
@@ -29,6 +29,17 @@ class SolarforecastCommand(BaseCommand):
cooldown_seconds = 10 # 10 second cooldown per user
requires_internet = True # Requires internet access for Forecast.Solar API and geocoding
# Documentation
short_description = "Get solar panel production forecast for a location or repeater"
usage = "sf <location> [watts] [azimuth] [angle]"
examples = ["sf seattle", "sf 47.6,-122.3 200"]
parameters = [
{"name": "location", "description": "City, coordinates, or repeater name"},
{"name": "watts", "description": "Panel size in watts (default: 100)"},
{"name": "azimuth", "description": "Panel direction, 0=south (default: 0)"},
{"name": "angle", "description": "Panel tilt in degrees (default: 30)"}
]
# Error constants - will use translations instead
ERROR_FETCHING_DATA = "Error fetching forecast" # Deprecated - use translate
NO_DATA_AVAILABLE = "No forecast data" # Deprecated - use translate
+9
View File
@@ -44,6 +44,15 @@ class SportsCommand(BaseCommand):
cooldown_seconds = 3 # 3 second cooldown per user to prevent API abuse
requires_internet = True # Requires internet access for ESPN API
# Documentation
short_description = "Get sports scores and schedules"
usage = "sports [team|league]"
examples = ["sports", "sports seahawks", "sports nfl"]
parameters = [
{"name": "team", "description": "Team name (e.g., seahawks, mariners)"},
{"name": "league", "description": "League code (nfl, mlb, nba, nhl, mls)"}
]
# ESPN client
espn_client: Optional[ESPNClient] = None
+8
View File
@@ -25,6 +25,14 @@ class StatsCommand(BaseCommand):
description = "Show statistics for past 24 hours. Use 'stats messages', 'stats channels', or 'stats paths' for specific stats."
category = "analytics"
# Documentation
short_description = "Show bot usage statistics for past 24 hours"
usage = "stats [messages|channels|paths]"
examples = ["stats", "stats channels"]
parameters = [
{"name": "type", "description": "messages, channels, or paths (optional)"}
]
def __init__(self, bot: Any):
"""Initialize the stats command.
+5
View File
@@ -21,6 +21,11 @@ class SunCommand(BaseCommand):
description = "Get sunrise/sunset times"
category = "solar"
# Documentation
short_description = "Get sunrise and sunset times"
usage = "sun"
examples = ["sun"]
def __init__(self, bot):
"""Initialize the sun command.
+5
View File
@@ -26,6 +26,11 @@ class TestCommand(BaseCommand):
description = "Responds to 'test' or 't' with connection info"
category = "basic"
# Documentation
short_description = "Get test response with connection info"
usage = "test [phrase]"
examples = ["test", "t hello world"]
def __init__(self, bot):
super().__init__(bot)
self.test_enabled = self.get_config_value('Test_Command', 'enabled', fallback=True, value_type='bool')
+9
View File
@@ -38,6 +38,15 @@ class WxCommand(BaseCommand):
cooldown_seconds = 5 # 5 second cooldown per user to prevent API abuse
requires_internet = True # Requires internet access for NOAA API and geocoding
# Documentation
short_description = "Get weather for a US location using NOAA weather data"
usage = "wx <zipcode|city> [tomorrow|7d|hourly|alerts]"
examples = ["wx 98101", "wx seattle", "wx 90210 7d"]
parameters = [
{"name": "location", "description": "US zip code or city name"},
{"name": "option", "description": "tomorrow, 7d, hourly, or alerts (optional)"}
]
# Error constants
NO_DATA_NOGPS = "No GPS data available"
ERROR_FETCHING_DATA = "Error fetching weather data"
+262 -26
View File
@@ -21,7 +21,7 @@
--accent-yellow: #ffd700;
--text-primary: #e8edf4;
--text-secondary: #8892a4;
--text-muted: #4a5568;
--text-muted: #6b7280;
--border-subtle: rgba(255,255,255,0.06);
--glow-blue: rgba(0, 212, 255, 0.15);
--glow-cyan: rgba(0, 255, 200, 0.1);
@@ -519,6 +519,57 @@
font-size: 0.95rem;
}
.command-usage {
margin: 0.75rem 0;
padding: 0.6rem 0.9rem;
background: rgba(0, 0, 0, 0.3);
border-radius: 8px;
border-left: 3px solid var(--accent-blue);
}
.command-usage code {
font-family: 'JetBrains Mono', monospace;
font-size: 0.85rem;
color: var(--accent-cyan);
}
.command-params {
margin-top: 0.75rem;
padding-top: 0.75rem;
border-top: 1px solid var(--border-subtle);
}
.params-header {
font-size: 0.8rem;
font-weight: 600;
color: var(--text-muted);
margin-bottom: 0.5rem;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.param-item {
display: flex;
gap: 0.5rem;
margin-bottom: 0.4rem;
font-size: 0.85rem;
align-items: flex-start;
}
.param-name {
font-family: 'JetBrains Mono', monospace;
color: var(--accent-orange);
font-weight: 500;
min-width: 80px;
flex-shrink: 0;
}
.param-desc {
color: var(--text-secondary);
flex: 1;
line-height: 1.4;
}
.command-subcommands {
margin-top: 1rem;
padding-top: 1rem;
@@ -884,7 +935,8 @@
<span class="keyword-badge">t</span>
</div>
</div>
<p class="command-description">Responds to &#x27;test&#x27; or &#x27;t&#x27; with connection info</p>
<p class="command-description">Get test response with connection info</p>
<div class="command-usage"><code>test [phrase]</code></div>
</div>
<div class="command-card">
<div class="command-header">
@@ -899,18 +951,28 @@
</div>
</div>
<p class="command-description">Responds to greetings with robot-themed responses</p>
<div class="command-usage"><code>hello</code></div>
</div>
<div class="command-card">
<div class="command-header">
<h3 class="command-name">ping</h3>
</div>
<p class="command-description">Responds to &#x27;ping&#x27; with &#x27;Pong!&#x27;</p>
<p class="command-description">Get a quick &#x27;pong&#x27;response from the bot</p>
<div class="command-usage"><code>ping</code></div>
</div>
<div class="command-card">
<div class="command-header">
<h3 class="command-name">help</h3>
</div>
<p class="command-description">Shows commands. Use &#x27;help &lt;command&gt;&#x27; for details.</p>
<p class="command-description">Get help on available commands</p>
<div class="command-usage"><code>help [command]</code></div>
<div class="command-params">
<div class="params-header">Parameters:</div>
<div class="param-item">
<span class="param-name">command</span>
<span class="param-desc">Command name for detailed help (optional)</span>
</div>
</div>
</div>
<div class="command-card">
<div class="command-header">
@@ -919,7 +981,23 @@
<span class="keyword-badge">channel</span>
</div>
</div>
<p class="command-description">Lists hashtag channels with sub-categories. Use &#x27;channels&#x27; for general, &#x27;channels list&#x27; for all categories, &#x27;channels &lt;category&gt;&#x27; for specific categories, &#x27;channels #channel&#x27; for specific channel info.</p>
<p class="command-description">Lists hashtag channels with sub-categories</p>
<div class="command-usage"><code>channels [list|category|#channel]</code></div>
<div class="command-params">
<div class="params-header">Parameters:</div>
<div class="param-item">
<span class="param-name">list</span>
<span class="param-desc">Show all channel categories</span>
</div>
<div class="param-item">
<span class="param-name">category</span>
<span class="param-desc">Filter by category name</span>
</div>
<div class="param-item">
<span class="param-name">#channel</span>
<span class="param-desc">Get info on a specific channel</span>
</div>
</div>
</div>
<div class="command-card">
<div class="command-header">
@@ -928,7 +1006,8 @@
<span class="keyword-badge">commands</span>
</div>
</div>
<p class="command-description">Lists available commands in compact format</p>
<p class="command-description">Lists available commands</p>
<div class="command-usage"><code>cmd</code></div>
</div>
</div>
</div>
@@ -939,7 +1018,15 @@
<div class="command-header">
<h3 class="command-name">stats</h3>
</div>
<p class="command-description">Show statistics for past 24 hours. Use &#x27;stats messages&#x27;, &#x27;stats channels&#x27;, or &#x27;stats paths&#x27; for specific stats.</p>
<p class="command-description">Show bot usage statistics for past 24 hours</p>
<div class="command-usage"><code>stats [messages|channels|paths]</code></div>
<div class="command-params">
<div class="params-header">Parameters:</div>
<div class="param-item">
<span class="param-name">type</span>
<span class="param-desc">messages, channels, or paths (optional)</span>
</div>
</div>
</div>
</div>
</div>
@@ -955,7 +1042,19 @@
<span class="keyword-badge">incidents</span>
</div>
</div>
<p class="command-description">Get active emergency incidents (usage: alert seattle, alert 98258, alert 178th seattle, alert seattle all)</p>
<p class="command-description">Get active emergency incidents from PulsePoint</p>
<div class="command-usage"><code>alert &lt;location&gt; [all]</code></div>
<div class="command-params">
<div class="params-header">Parameters:</div>
<div class="param-item">
<span class="param-name">location</span>
<span class="param-desc">City, zip code, or street address</span>
</div>
<div class="param-item">
<span class="param-name">all</span>
<span class="param-desc">Show all incidents (not just nearby)</span>
</div>
</div>
</div>
</div>
</div>
@@ -969,7 +1068,15 @@
<span class="keyword-badge">jokes</span>
</div>
</div>
<p class="command-description">Get a random joke or joke from specific category (usage: joke [category])</p>
<p class="command-description">Get a random joke</p>
<div class="command-usage"><code>joke [category]</code></div>
<div class="command-params">
<div class="params-header">Parameters:</div>
<div class="param-item">
<span class="param-name">category</span>
<span class="param-desc">programming, pun, misc, dark (optional)</span>
</div>
</div>
<div class="command-channels">Channel: #jokes</div>
</div>
</div>
@@ -986,7 +1093,8 @@
<span class="keyword-badge">dad jokes</span>
</div>
</div>
<p class="command-description">Get a random dad joke from icanhazdadjoke.com</p>
<p class="command-description">Get a random dad joke</p>
<div class="command-usage"><code>dadjoke</code></div>
<div class="command-channels">Channel: #jokes</div>
</div>
<div class="command-card">
@@ -1001,7 +1109,8 @@
<span class="keyword-badge keyword-expand" data-hidden="echo $PATH,rm,rm -rf,cat,whoami,top,htop,netstat,ss,kill,killall,chmod,find,history,passwd,su,ssh,wget,curl,df -h,free,ifconfig,ip addr,uname -a" data-command="hacker">+24 more</span>
</div>
</div>
<p class="command-description">Simulates hacking a supervillain&#x27;s mainframe with hilarious error messages</p>
<p class="command-description">Try Linux commands and get supervillain mainframe errors</p>
<div class="command-usage"><code>&lt;linux_command&gt;</code></div>
</div>
</div>
</div>
@@ -1012,19 +1121,36 @@
<div class="command-header">
<h3 class="command-name">dice</h3>
</div>
<p class="command-description">Roll dice for D&amp;D and tabletop games. Use &#x27;dice&#x27; for d6, &#x27;dice d20&#x27; for d20, &#x27;dice 2d6&#x27; for 2d6, &#x27;dice d10 d6&#x27; for mixed dice, &#x27;dice decade&#x27; for decade die (00-90), etc.</p>
<p class="command-description">Roll dice for tabletop games</p>
<div class="command-usage"><code>dice [NdX|dX|decade]</code></div>
<div class="command-params">
<div class="params-header">Parameters:</div>
<div class="param-item">
<span class="param-name">dice</span>
<span class="param-desc">Dice notation: d6, 2d8, d10 d6, decade</span>
</div>
</div>
</div>
<div class="command-card">
<div class="command-header">
<h3 class="command-name">magic8</h3>
</div>
<p class="command-description">Emulates the classic Magic 8-ball toy&#x27;</p>
<p class="command-description">Ask the Magic 8-Ball a yes/no question</p>
<div class="command-usage"><code>magic8 &lt;question&gt;</code></div>
</div>
<div class="command-card">
<div class="command-header">
<h3 class="command-name">roll</h3>
</div>
<p class="command-description">Roll a random number between 1 and X (default 100). Use &#x27;roll&#x27; for 1-100, &#x27;roll 50&#x27; for 1-50, etc.</p>
<p class="command-description">Roll a random number between 1 and X</p>
<div class="command-usage"><code>roll [max]</code></div>
<div class="command-params">
<div class="params-header">Parameters:</div>
<div class="param-item">
<span class="param-name">max</span>
<span class="param-desc">Maximum value (default: 100, max: 10000)</span>
</div>
</div>
</div>
</div>
</div>
@@ -1041,7 +1167,23 @@
<span class="keyword-badge">overhead</span>
</div>
</div>
<p class="command-description">Get aircraft overhead (usage: airplanes [location] [options] or overhead [lat,lon])</p>
<p class="command-description">Get aircraft overhead using ADS-B data</p>
<div class="command-usage"><code>airplanes [lat,lon|here] [radius=N] [options]</code></div>
<div class="command-params">
<div class="params-header">Parameters:</div>
<div class="param-item">
<span class="param-name">location</span>
<span class="param-desc">Coordinates or here for your companion&#x27;s location if advertised</span>
</div>
<div class="param-item">
<span class="param-name">radius</span>
<span class="param-desc">Search radius in nautical miles (default: 25)</span>
</div>
<div class="param-item">
<span class="param-name">filters</span>
<span class="param-desc">alt=, type=, military, closest, etc.</span>
</div>
</div>
</div>
</div>
</div>
@@ -1057,7 +1199,8 @@
<span class="keyword-badge">p</span>
</div>
</div>
<p class="command-description">Decode hex path data to show which repeaters were involved in message routing</p>
<p class="command-description">Decode path data to show repeaters involved in message routing</p>
<div class="command-usage"><code>path [hex_data]</code></div>
</div>
<div class="command-card">
<div class="command-header">
@@ -1067,7 +1210,19 @@
<span class="keyword-badge">lookup</span>
</div>
</div>
<p class="command-description">Look up repeaters by two-character prefix (e.g., &#x27;prefix 1A&#x27;)</p>
<p class="command-description">Look up repeaters by two-character prefix and show their locations (if known)</p>
<div class="command-usage"><code>prefix &lt;XX|free|refresh&gt;</code></div>
<div class="command-params">
<div class="params-header">Parameters:</div>
<div class="param-item">
<span class="param-name">prefix</span>
<span class="param-desc">Two-character prefix (e.g., 1A, 2B)</span>
</div>
<div class="param-item">
<span class="param-name">free</span>
<span class="param-desc">Show available/unused prefixes</span>
</div>
</div>
</div>
<div class="command-card">
<div class="command-header">
@@ -1076,7 +1231,8 @@
<span class="keyword-badge">mt</span>
</div>
</div>
<p class="command-description">Listens for 6 seconds and collects all unique paths from incoming messages</p>
<p class="command-description">Listens for 6 seconds and collects all unique paths your incoming messages took to reach the bot</p>
<div class="command-usage"><code>multitest</code></div>
</div>
</div>
</div>
@@ -1088,30 +1244,46 @@
<h3 class="command-name">hfcond</h3>
</div>
<p class="command-description">Get HF band conditions for ham radio</p>
<div class="command-usage"><code>hfcond</code></div>
</div>
<div class="command-card">
<div class="command-header">
<h3 class="command-name">moon</h3>
</div>
<p class="command-description">Get moon phase, rise/set times and position</p>
<p class="command-description">Get moon phase and rise/set times</p>
<div class="command-usage"><code>moon</code></div>
</div>
<div class="command-card">
<div class="command-header">
<h3 class="command-name">solar</h3>
</div>
<p class="command-description">Get current solar conditions and HF band info</p>
<div class="command-usage"><code>solar</code></div>
</div>
<div class="command-card">
<div class="command-header">
<h3 class="command-name">satpass</h3>
</div>
<p class="command-description">Get satellite pass info: satpass &lt;NORAD_number_or_shortcut&gt; [visual]</p>
<p class="command-description">Get satellite pass predictions</p>
<div class="command-usage"><code>satpass &lt;NORAD_number|shortcut&gt; [visual]</code></div>
<div class="command-params">
<div class="params-header">Parameters:</div>
<div class="param-item">
<span class="param-name">satellite</span>
<span class="param-desc">NORAD ID or shortcut (iss, hst, starlink)</span>
</div>
<div class="param-item">
<span class="param-name">visual</span>
<span class="param-desc">Add &#x27;visual&#x27; for visible passes only</span>
</div>
</div>
</div>
<div class="command-card">
<div class="command-header">
<h3 class="command-name">sun</h3>
</div>
<p class="command-description">Get sunrise/sunset times</p>
<p class="command-description">Get sunrise and sunset times</p>
<div class="command-usage"><code>sun</code></div>
</div>
<div class="command-card">
<div class="command-header">
@@ -1120,7 +1292,27 @@
<span class="keyword-badge">sf</span>
</div>
</div>
<p class="command-description">Get solar panel production forecast (usage: sf &lt;location|repeater_name|coordinates|zipcode&gt; [panel_size] [azimuth, 0=south] [angle])</p>
<p class="command-description">Get solar panel production forecast for a location or repeater</p>
<div class="command-usage"><code>sf &lt;location&gt; [watts] [azimuth] [angle]</code></div>
<div class="command-params">
<div class="params-header">Parameters:</div>
<div class="param-item">
<span class="param-name">location</span>
<span class="param-desc">City, coordinates, or repeater name</span>
</div>
<div class="param-item">
<span class="param-name">watts</span>
<span class="param-desc">Panel size in watts (default: 100)</span>
</div>
<div class="param-item">
<span class="param-name">azimuth</span>
<span class="param-desc">Panel direction, 0=south (default: 0)</span>
</div>
<div class="param-item">
<span class="param-name">angle</span>
<span class="param-desc">Panel tilt in degrees (default: 30)</span>
</div>
</div>
</div>
</div>
</div>
@@ -1135,7 +1327,19 @@
<span class="keyword-badge">scores</span>
</div>
</div>
<p class="command-description">Get sports scores and schedules (usage: sports [team/league])</p>
<p class="command-description">Get sports scores and schedules</p>
<div class="command-usage"><code>sports [team|league]</code></div>
<div class="command-params">
<div class="params-header">Parameters:</div>
<div class="param-item">
<span class="param-name">team</span>
<span class="param-desc">Team name (e.g., seahawks, mariners)</span>
</div>
<div class="param-item">
<span class="param-name">league</span>
<span class="param-desc">League code (nfl, mlb, nba, nhl, mls)</span>
</div>
</div>
<div class="command-channels">Channels: #BotTest, #bot, #sounders, #seahawks</div>
</div>
</div>
@@ -1152,7 +1356,19 @@
<span class="keyword-badge">wxalert</span>
</div>
</div>
<p class="command-description">Get weather information for a zip code (usage: wx 12345)</p>
<p class="command-description">Get weather for a US location using NOAA weather data</p>
<div class="command-usage"><code>wx &lt;zipcode|city&gt; [tomorrow|7d|hourly|alerts]</code></div>
<div class="command-params">
<div class="params-header">Parameters:</div>
<div class="param-item">
<span class="param-name">location</span>
<span class="param-desc">US zip code or city name</span>
</div>
<div class="param-item">
<span class="param-name">option</span>
<span class="param-desc">tomorrow, 7d, hourly, or alerts (optional)</span>
</div>
</div>
</div>
<div class="command-card">
<div class="command-header">
@@ -1162,7 +1378,19 @@
<span class="keyword-badge">gwxa</span>
</div>
</div>
<p class="command-description">Get weather information for any global location (usage: gwx Tokyo)</p>
<p class="command-description">Get weather for any global location using Open-Meteo API</p>
<div class="command-usage"><code>gwx &lt;location&gt; [tomorrow|7d|hourly]</code></div>
<div class="command-params">
<div class="params-header">Parameters:</div>
<div class="param-item">
<span class="param-name">location</span>
<span class="param-desc">City name, country, or coordinates</span>
</div>
<div class="param-item">
<span class="param-name">option</span>
<span class="param-desc">tomorrow, 7d, or hourly (optional)</span>
</div>
</div>
</div>
<div class="command-card">
<div class="command-header">
@@ -1173,7 +1401,15 @@
<span class="keyword-badge">air_quality</span>
</div>
</div>
<p class="command-description">Get Air Quality Index for a location (usage: aqi seattle, aqi greenwood, aqi vancouver canada, aqi 47.6,-122.3, or aqi help)</p>
<p class="command-description">Get Air Quality Index for a location</p>
<div class="command-usage"><code>aqi &lt;city|neighborhood|coordinates|help&gt;</code></div>
<div class="command-params">
<div class="params-header">Parameters:</div>
<div class="param-item">
<span class="param-name">location</span>
<span class="param-desc">City, neighborhood, lat/lon, or &#x27;help&#x27;</span>
</div>
</div>
</div>
</div>
</div>