-
Notifications
You must be signed in to change notification settings - Fork 2
Health Status Command #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
790d208
auto-claude: subtask-1-1 - Create health monitoring module with uptim…
BillChirico 8eaad58
auto-claude: subtask-1-2 - Integrate health monitoring into main bot …
BillChirico 285e153
auto-claude: subtask-2-1 - Create command deployment script to regist…
BillChirico 99ff0b5
auto-claude: subtask-2-2 - Add interactionCreate event handler to mai…
BillChirico c16d0bf
auto-claude: subtask-3-1 - Create /status command handler with basic …
BillChirico f4dd508
auto-claude: subtask-3-2 - Wire status command into interaction handler
BillChirico c39a958
auto-claude: subtask-4-1 - End-to-end verification of /status command
BillChirico 6f0c331
fix: add admin permission check for detailed diagnostics (qa-requested)
BillChirico d69c2c2
Merge branch 'main' into auto-claude/001-health-status-command
BillChirico eb89ea6
chore: remove auto-claude metadata and verification scripts from trac…
BillChirico bed8a8d
docs: add CLIENT_ID and GUILD_ID to .env.example
BillChirico 05f9119
fix: throw error in HealthMonitor constructor instead of returning in…
BillChirico b09842d
fix: read process.uptime as property instead of function call
BillChirico 30bece7
fix: use memberPermissions with PermissionFlagsBits for safer permiss…
BillChirico 980ce42
refactor: use ApplicationCommandOptionType enum instead of magic number
BillChirico File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,13 @@ | ||
| # Discord bot token | ||
| DISCORD_TOKEN=your_discord_bot_token | ||
|
|
||
| # Discord application client ID (for slash command registration) | ||
| CLIENT_ID=your_discord_client_id | ||
|
|
||
| # Discord guild/server ID (optional - for faster command deployment during development) | ||
| # If not set, commands deploy globally (takes up to 1 hour to propagate) | ||
| GUILD_ID=your_discord_guild_id | ||
|
|
||
| # OpenClaw API (routes through your Claude subscription) | ||
| OPENCLAW_URL=http://localhost:18789/v1/chat/completions | ||
| OPENCLAW_TOKEN=your_openclaw_gateway_token |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,118 @@ | ||
| /** | ||
| * Status Command - Display bot health metrics | ||
| * | ||
| * Shows uptime, memory usage, API status, and last AI request | ||
| * Admin mode (detailed: true) shows additional diagnostics | ||
| */ | ||
|
|
||
| import { EmbedBuilder, PermissionFlagsBits } from 'discord.js'; | ||
| import { HealthMonitor } from '../utils/health.js'; | ||
|
|
||
| /** | ||
| * Format timestamp as relative time | ||
| */ | ||
| function formatRelativeTime(timestamp) { | ||
| if (!timestamp) return 'Never'; | ||
|
|
||
| const now = Date.now(); | ||
| const diff = now - timestamp; | ||
| const seconds = Math.floor(diff / 1000); | ||
| const minutes = Math.floor(seconds / 60); | ||
| const hours = Math.floor(minutes / 60); | ||
| const days = Math.floor(hours / 24); | ||
|
|
||
| if (diff < 1000) return 'Just now'; | ||
| if (seconds < 60) return `${seconds}s ago`; | ||
| if (minutes < 60) return `${minutes}m ago`; | ||
| if (hours < 24) return `${hours}h ago`; | ||
| return `${days}d ago`; | ||
| } | ||
|
|
||
| /** | ||
| * Get status emoji based on API status | ||
| */ | ||
| function getStatusEmoji(status) { | ||
| switch (status) { | ||
| case 'ok': return '🟢'; | ||
| case 'error': return '🔴'; | ||
| case 'unknown': return '🟡'; | ||
| default: return '⚪'; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Execute the status command | ||
| */ | ||
| export async function execute(interaction) { | ||
| try { | ||
| const detailed = interaction.options.getBoolean('detailed') || false; | ||
| const healthMonitor = HealthMonitor.getInstance(); | ||
|
|
||
| if (detailed) { | ||
| // Check if user has admin permissions | ||
| if (!interaction.memberPermissions?.has(PermissionFlagsBits.Administrator)) { | ||
| await interaction.reply({ | ||
| content: '❌ Detailed diagnostics are only available to administrators.', | ||
| ephemeral: true | ||
| }); | ||
| return; | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| // Detailed mode - admin diagnostics | ||
| const status = healthMonitor.getDetailedStatus(); | ||
|
|
||
| const embed = new EmbedBuilder() | ||
| .setColor(0x5865F2) | ||
| .setTitle('🔍 Bot Status - Detailed Diagnostics') | ||
| .addFields( | ||
| { name: '⏱️ Uptime', value: status.uptimeFormatted, inline: true }, | ||
| { name: '🧠 Memory', value: status.memory.formatted, inline: true }, | ||
| { name: '🌐 API', value: `${getStatusEmoji(status.api.status)} ${status.api.status}`, inline: true }, | ||
| { name: '🤖 Last AI Request', value: formatRelativeTime(status.lastAIRequest), inline: true }, | ||
| { name: '📊 Process ID', value: `${status.process.pid}`, inline: true }, | ||
| { name: '🖥️ Platform', value: status.process.platform, inline: true }, | ||
| { name: '📦 Node Version', value: status.process.nodeVersion, inline: true }, | ||
| { name: '⚙️ Process Uptime', value: `${Math.floor(status.process.uptime)}s`, inline: true }, | ||
| { name: '🔢 Heap Used', value: `${status.memory.heapUsed}MB`, inline: true }, | ||
| { name: '💾 RSS', value: `${status.memory.rss}MB`, inline: true }, | ||
| { name: '📡 External', value: `${status.memory.external}MB`, inline: true }, | ||
| { name: '🔢 Array Buffers', value: `${status.memory.arrayBuffers}MB`, inline: true } | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ) | ||
| .setTimestamp() | ||
| .setFooter({ text: 'Detailed diagnostics mode' }); | ||
|
|
||
| await interaction.reply({ embeds: [embed], ephemeral: true }); | ||
| } else { | ||
| // Basic mode - user-friendly status | ||
| const status = healthMonitor.getStatus(); | ||
|
|
||
| const embed = new EmbedBuilder() | ||
| .setColor(0x57F287) | ||
| .setTitle('📊 Bot Status') | ||
| .setDescription('Current health and performance metrics') | ||
| .addFields( | ||
| { name: '⏱️ Uptime', value: status.uptimeFormatted, inline: true }, | ||
| { name: '🧠 Memory', value: status.memory.formatted, inline: true }, | ||
| { name: '🌐 API Status', value: `${getStatusEmoji(status.api.status)} ${status.api.status.toUpperCase()}`, inline: true }, | ||
| { name: '🤖 Last AI Request', value: formatRelativeTime(status.lastAIRequest), inline: false } | ||
| ) | ||
| .setTimestamp() | ||
| .setFooter({ text: 'Use /status detailed:true for more info' }); | ||
|
|
||
| await interaction.reply({ embeds: [embed] }); | ||
| } | ||
| } catch (err) { | ||
| console.error('Status command error:', err.message); | ||
|
|
||
| const reply = { | ||
| content: 'Sorry, I couldn\'t retrieve the status. Try again in a moment!', | ||
| ephemeral: true | ||
| }; | ||
|
|
||
| if (interaction.replied || interaction.deferred) { | ||
| await interaction.followUp(reply).catch(() => {}); | ||
| } else { | ||
| await interaction.reply(reply).catch(() => {}); | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| /** | ||
| * Deploy Discord Slash Commands | ||
| * | ||
| * Registers bot commands with Discord API | ||
| * Run with: node src/deploy-commands.js | ||
| */ | ||
|
|
||
| import { REST, Routes, ApplicationCommandOptionType } from 'discord.js'; | ||
| import { config as dotenvConfig } from 'dotenv'; | ||
|
|
||
| dotenvConfig(); | ||
|
|
||
| const DISCORD_TOKEN = process.env.DISCORD_TOKEN; | ||
| const CLIENT_ID = process.env.CLIENT_ID; | ||
| const GUILD_ID = process.env.GUILD_ID; // Optional: for faster guild-only deployment | ||
|
|
||
| if (!DISCORD_TOKEN) { | ||
| console.error('❌ Missing DISCORD_TOKEN in .env'); | ||
| process.exit(1); | ||
| } | ||
|
|
||
| if (!CLIENT_ID) { | ||
| console.error('❌ Missing CLIENT_ID in .env'); | ||
| process.exit(1); | ||
| } | ||
|
|
||
| // Define commands | ||
| const commands = [ | ||
| { | ||
| name: 'status', | ||
| description: 'Check bot health and status', | ||
| options: [ | ||
| { | ||
| name: 'detailed', | ||
| description: 'Show detailed diagnostics (admin only)', | ||
| type: ApplicationCommandOptionType.Boolean, | ||
| required: false, | ||
| }, | ||
| ], | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| }, | ||
| ]; | ||
|
|
||
| const rest = new REST({ version: '10' }).setToken(DISCORD_TOKEN); | ||
|
|
||
| /** | ||
| * Deploy commands to Discord | ||
| */ | ||
| async function deployCommands() { | ||
| try { | ||
| console.log('🔄 Registering slash commands...'); | ||
|
|
||
| let route; | ||
| let scope; | ||
|
|
||
| if (GUILD_ID) { | ||
| // Guild-specific deployment (faster for testing) | ||
| route = Routes.applicationGuildCommands(CLIENT_ID, GUILD_ID); | ||
| scope = `guild ${GUILD_ID}`; | ||
| } else { | ||
| // Global deployment (takes up to 1 hour to propagate) | ||
| route = Routes.applicationCommands(CLIENT_ID); | ||
| scope = 'globally'; | ||
| } | ||
|
|
||
| const data = await rest.put(route, { body: commands }); | ||
|
|
||
| console.log(`✅ Successfully registered ${data.length} command(s) ${scope}`); | ||
| console.log(` Commands: ${data.map(cmd => `/${cmd.name}`).join(', ')}`); | ||
|
|
||
| if (!GUILD_ID) { | ||
| console.log('⏱️ Note: Global commands may take up to 1 hour to appear'); | ||
| } | ||
| } catch (error) { | ||
| console.error('❌ Failed to register commands:', error); | ||
| process.exit(1); | ||
| } | ||
| } | ||
|
|
||
| deployCommands(); | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.