Skip to content

Commit 01957bf

Browse files
authored
feat(discord-app): add delete command to remove a message by ID (#976)
* feat(discord-app): add delete command to remove a message by ID Adds a new `delete` command for the discord-app CLI that deletes a message in the active channel by its snowflake ID. Uses the UI strategy to hover the message, open the "More" menu, click "Delete Message", and confirm the deletion dialog. * docs: add binance adapter doc and update discord doc with delete command
1 parent 315cc59 commit 01957bf

File tree

3 files changed

+134
-0
lines changed

3 files changed

+134
-0
lines changed

clis/discord-app/delete.js

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import { cli, Strategy } from '@jackwener/opencli/registry';
2+
import { CommandExecutionError } from '@jackwener/opencli/errors';
3+
4+
function buildDeleteScript(messageId) {
5+
return `(async () => {
6+
try {
7+
const messageId = ${JSON.stringify(messageId)};
8+
9+
// Find the message element by its ID attribute (format: chat-messages-{channelId}-{messageId})
10+
const msgEl = document.querySelector('[id$="-' + messageId + '"]');
11+
if (!msgEl) {
12+
return { ok: false, message: 'Could not find a message with ID ' + messageId + ' in the current channel.' };
13+
}
14+
15+
// Find the closest list item wrapper that Discord uses for messages
16+
const listItem = msgEl.closest('[id^="chat-messages-"]') || msgEl;
17+
18+
// Hover over the message to reveal the action toolbar
19+
listItem.dispatchEvent(new MouseEvent('mouseenter', { bubbles: true }));
20+
listItem.dispatchEvent(new MouseEvent('mouseover', { bubbles: true }));
21+
await new Promise(r => setTimeout(r, 500));
22+
23+
// Look for the "More" button in the message toolbar
24+
// Discord shows a toolbar with buttons when hovering over a message
25+
const toolbar = listItem.querySelector('[class*="toolbar"]') ||
26+
document.querySelector('[id^="message-actions-"]');
27+
if (!toolbar) {
28+
return { ok: false, message: 'Could not find the message action toolbar. Try scrolling so the message is fully visible.' };
29+
}
30+
31+
const buttons = Array.from(toolbar.querySelectorAll('button, [role="button"], div[class*="button"]'));
32+
const moreBtn = buttons.find(btn => {
33+
const label = (btn.getAttribute('aria-label') || '').toLowerCase();
34+
return label === 'more' || label.includes('more');
35+
});
36+
if (!moreBtn) {
37+
return { ok: false, message: 'Could not find the "More" button on the message toolbar.' };
38+
}
39+
40+
moreBtn.click();
41+
await new Promise(r => setTimeout(r, 500));
42+
43+
// Find "Delete Message" in the context menu
44+
const menuItems = Array.from(document.querySelectorAll('[role="menuitem"], [id*="message-actions"]'));
45+
const deleteItem = menuItems.find(item => {
46+
const text = (item.textContent || '').trim().toLowerCase();
47+
return text.includes('delete message') || text === 'delete';
48+
});
49+
50+
if (!deleteItem) {
51+
// Close the menu by pressing Escape
52+
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
53+
return { ok: false, message: 'No "Delete Message" option found. You may not have permission to delete this message.' };
54+
}
55+
56+
deleteItem.click();
57+
await new Promise(r => setTimeout(r, 500));
58+
59+
// Confirm deletion in the modal dialog
60+
const confirmBtn = document.querySelector('[type="submit"], button[class*="colorRed"], button[class*="danger"]');
61+
if (!confirmBtn) {
62+
return { ok: false, message: 'Delete confirmation dialog did not appear.' };
63+
}
64+
65+
confirmBtn.click();
66+
return { ok: true, message: 'Message ' + messageId + ' deleted successfully.' };
67+
} catch (e) {
68+
return { ok: false, message: e.toString() };
69+
}
70+
})()`;
71+
}
72+
73+
cli({
74+
site: 'discord-app',
75+
name: 'delete',
76+
description: 'Delete a message by its ID in the active Discord channel',
77+
domain: 'localhost',
78+
strategy: Strategy.UI,
79+
browser: true,
80+
args: [
81+
{
82+
name: 'message_id',
83+
type: 'string',
84+
required: true,
85+
positional: true,
86+
help: 'The ID of the message to delete (visible via Developer Mode or the read command)',
87+
},
88+
],
89+
columns: ['status', 'message'],
90+
func: async (page, kwargs) => {
91+
if (!page)
92+
throw new CommandExecutionError('Browser session required for discord-app delete');
93+
const messageId = kwargs.message_id;
94+
if (!/^\d+$/.test(messageId)) {
95+
throw new CommandExecutionError(
96+
`Invalid message ID: "${messageId}". A Discord message ID is a numeric snowflake (e.g. 1234567890123456789).`
97+
);
98+
}
99+
// Wait a moment for the chat to be fully loaded
100+
await page.wait(0.5);
101+
const result = await page.evaluate(buildDeleteScript(messageId));
102+
if (result.ok) {
103+
await page.wait(1);
104+
}
105+
return [{
106+
status: result.ok ? 'success' : 'failed',
107+
message: result.message,
108+
}];
109+
},
110+
});
111+
112+
export const __test__ = {
113+
buildDeleteScript,
114+
};

docs/adapters/browser/binance.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Binance
2+
3+
Access **Binance** market data from the terminal via the public API (no authentication required).
4+
5+
## Commands
6+
7+
| Command | Description |
8+
|---------|-------------|
9+
| `opencli binance price SYMBOL` | Quick price check for a trading pair |
10+
| `opencli binance prices` | Latest prices for all trading pairs |
11+
| `opencli binance ticker` | 24h ticker statistics for top pairs by volume |
12+
| `opencli binance top` | Top trading pairs by 24h volume |
13+
| `opencli binance gainers` | Top gaining pairs by 24h price change |
14+
| `opencli binance losers` | Top losing pairs by 24h price change |
15+
| `opencli binance pairs` | List active trading pairs |
16+
| `opencli binance klines SYMBOL` | Candlestick/kline data for a trading pair |
17+
| `opencli binance depth SYMBOL` | Order book bid prices |
18+
| `opencli binance asks SYMBOL` | Order book ask prices |
19+
| `opencli binance trades SYMBOL` | Recent trades for a trading pair |

docs/adapters/desktop/discord.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,4 @@ export OPENCLI_CDP_ENDPOINT="http://127.0.0.1:9232"
2626
| `opencli discord-app servers` | List all joined servers |
2727
| `opencli discord-app search "query"` | Search messages (Cmd+F) |
2828
| `opencli discord-app members` | List online members |
29+
| `opencli discord-app delete MESSAGE_ID` | Delete a message by its ID |

0 commit comments

Comments
 (0)