Skip to content

Commit 812001a

Browse files
committed
feat: overhaul button UX - Continue actually works, cleaner layout
- Continue button now invokes onContinue() instead of showing text - Buttons reduced to 1 clean row: Continue | Git Status | Prompt History - Removed Cancel from completion (useless after session ends) - Removed Session ID button (already shown in completion embed) - Renamed 'Jump to Previous' to 'Prompt History' for clarity - Renamed 'Use This Message' to 'Run This Prompt' - Removed verbose Usage/Navigation fields from history view - Added jump-previous legacy alias for old messages - Kept copy-session handler for backwards compat with old messages
1 parent 4cf2dc9 commit 812001a

File tree

5 files changed

+82
-132
lines changed

5 files changed

+82
-132
lines changed

claude/discord-sender.ts

Lines changed: 18 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -10,53 +10,35 @@ export interface DiscordSender {
1010
// Store full content for expand functionality
1111
export const expandableContent = new Map<string, string>();
1212

13-
// Helper function to create common action buttons
13+
// Helper function to create action buttons for completed sessions
1414
function createActionButtons(sessionId?: string): ComponentData[] {
1515
const buttons: ComponentData[] = [];
1616

1717
if (sessionId) {
18-
buttons.push(
19-
{
20-
type: 'button',
21-
customId: `continue:${sessionId}`,
22-
label: '➡️ Continue',
23-
style: 'primary'
24-
},
25-
{
26-
type: 'button',
27-
customId: `copy-session:${sessionId}`,
28-
label: '📋 Session ID',
29-
style: 'secondary'
30-
},
31-
{
32-
type: 'button',
33-
customId: 'jump-previous',
34-
label: '⬆️ Jump to Previous',
35-
style: 'secondary'
36-
}
37-
);
18+
buttons.push({
19+
type: 'button',
20+
customId: `continue:${sessionId}`,
21+
label: '▶️ Continue',
22+
style: 'primary'
23+
});
3824
}
3925

40-
buttons.push({
41-
type: 'button',
42-
customId: 'cancel-claude',
43-
label: '❌ Cancel',
44-
style: 'danger'
45-
});
46-
47-
return buttons;
48-
}
49-
50-
// Helper function to create workflow buttons
51-
function createWorkflowButtons(): ComponentData[] {
52-
return [
26+
buttons.push(
5327
{
5428
type: 'button',
5529
customId: 'workflow:git-status',
5630
label: '📊 Git Status',
5731
style: 'secondary'
32+
},
33+
{
34+
type: 'button',
35+
customId: 'prompt-history',
36+
label: '📜 Prompt History',
37+
style: 'secondary'
5838
}
59-
];
39+
);
40+
41+
return buttons;
6042
}
6143

6244
// Helper function to truncate content with smart preview
@@ -345,11 +327,9 @@ export function createClaudeSender(sender: DiscordSender) {
345327

346328
if (msg.metadata?.subtype === 'completion' && msg.metadata?.session_id) {
347329
const actionButtons = createActionButtons(msg.metadata.session_id);
348-
const workflowButtons = createWorkflowButtons();
349330

350331
messageContent.components = [
351-
{ type: 'actionRow', components: actionButtons },
352-
{ type: 'actionRow', components: workflowButtons }
332+
{ type: 'actionRow', components: actionButtons }
353333
];
354334
}
355335

core/button-handlers.ts

Lines changed: 26 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,12 @@ export function createButtonHandlers(
4848
deps: ButtonHandlerDeps,
4949
expandableContent: ExpandableContentMap
5050
): ButtonHandlers {
51-
const { messageHistory, handlers, getClaudeSessionId } = deps;
51+
const { messageHistory, handlers } = deps;
5252
const { addToHistory, getPreviousMessage, getNextMessage, getState } = messageHistory;
5353
const { claude: claudeHandlers, git: gitHandlers } = handlers;
5454

5555
const buttonHandlers: ButtonHandlers = new Map([
56-
// Cancel Claude session
56+
// Cancel Claude session (kept for programmatic use, no longer on completion buttons)
5757
['cancel-claude', async (ctx: InteractionContext) => {
5858
const cancelled = claudeHandlers.onClaudeCancel(ctx);
5959
await ctx.update({
@@ -66,52 +66,34 @@ export function createButtonHandlers(
6666
});
6767
}],
6868

69-
// Copy session ID button
70-
['copy-session', async (ctx: InteractionContext) => {
71-
const sessionId = getClaudeSessionId();
72-
await ctx.update({
73-
embeds: [{
74-
color: 0x00ff00,
75-
title: 'Session ID',
76-
description: sessionId ? `\`${sessionId}\`` : 'No active session',
77-
timestamp: true
78-
}]
79-
});
80-
}],
81-
82-
// Jump to previous message button
83-
['jump-previous', async (ctx: InteractionContext) => {
69+
// Prompt history — replaces old "jump-previous"
70+
['prompt-history', async (ctx: InteractionContext) => {
8471
const previousMessage = getPreviousMessage();
8572

8673
if (!previousMessage) {
8774
await ctx.update({
8875
embeds: [{
8976
color: 0xffaa00,
90-
title: '⬆️ No Previous Messages',
91-
description: 'No previous messages found in history.',
77+
title: '📜 No Prompt History',
78+
description: 'No previous prompts found.',
9279
fields: [
93-
{ name: 'Tip', value: 'Send some Claude commands to build up your message history!', inline: false }
80+
{ name: 'Tip', value: 'Use `/claude` to send prompts — they\'ll appear here for reuse.', inline: false }
9481
],
9582
timestamp: true
9683
}]
9784
});
9885
return;
9986
}
10087

101-
// Show the previous message with navigation options
10288
const historyState = getState();
10389
const historyPosition = historyState.currentIndex + 1;
10490
const totalMessages = historyState.history.length;
10591

10692
await ctx.update({
10793
embeds: [{
10894
color: 0x0099ff,
109-
title: `⬆️ Previous Message (${historyPosition}/${totalMessages})`,
95+
title: `📜 Prompt History (${historyPosition}/${totalMessages})`,
11096
description: `\`\`\`\n${previousMessage}\n\`\`\``,
111-
fields: [
112-
{ name: 'Usage', value: 'Copy this message to use with `/claude prompt:...`', inline: false },
113-
{ name: 'Navigation', value: `Position ${historyPosition} of ${totalMessages} messages in history`, inline: false }
114-
],
11597
timestamp: true
11698
}],
11799
components: [
@@ -120,40 +102,19 @@ export function createButtonHandlers(
120102
components: [
121103
{ type: 'button', customId: 'history-previous', label: '⬅️ Older', style: 'secondary' },
122104
{ type: 'button', customId: 'history-next', label: '➡️ Newer', style: 'secondary' },
123-
{ type: 'button', customId: 'history-use', label: '🔄 Use This Message', style: 'primary' },
105+
{ type: 'button', customId: 'history-use', label: '▶️ Run This Prompt', style: 'primary' },
124106
{ type: 'button', customId: 'history-close', label: '❌ Close', style: 'danger' }
125107
]
126108
}
127109
]
128110
});
129111
}],
130112

131-
// Continue button with session ID
132-
['continue', async (ctx: InteractionContext) => {
133-
const sessionId = getClaudeSessionId();
134-
if (!sessionId) {
135-
await ctx.update({
136-
embeds: [{
137-
color: 0xff0000,
138-
title: '❌ No Session Available',
139-
description: 'No active session found. Use `/claude` to start a new conversation.',
140-
timestamp: true
141-
}]
142-
});
143-
return;
144-
}
145-
146-
await ctx.update({
147-
embeds: [{
148-
color: 0xffff00,
149-
title: '➡️ Continue Session',
150-
description: `Use \`/continue\` or \`/claude session_id:${sessionId}\` to continue the conversation.`,
151-
fields: [
152-
{ name: 'Session ID', value: `\`${sessionId}\``, inline: false }
153-
],
154-
timestamp: true
155-
}]
156-
});
113+
// Legacy alias — old messages may still have jump-previous buttons
114+
['jump-previous', async (ctx: InteractionContext) => {
115+
// Delegate to prompt-history handler
116+
const handler = buttonHandlers.get('prompt-history');
117+
if (handler) await handler(ctx);
157118
}],
158119

159120
// History navigation - older
@@ -164,8 +125,8 @@ export function createButtonHandlers(
164125
await ctx.update({
165126
embeds: [{
166127
color: 0xffaa00,
167-
title: '⬅️ No Older Messages',
168-
description: 'You\'ve reached the beginning of your message history.',
128+
title: '⬅️ No Older Prompts',
129+
description: 'You\'ve reached the beginning of your prompt history.',
169130
timestamp: true
170131
}],
171132
components: []
@@ -180,12 +141,8 @@ export function createButtonHandlers(
180141
await ctx.update({
181142
embeds: [{
182143
color: 0x0099ff,
183-
title: `⬅️ Older Message (${historyPosition}/${totalMessages})`,
144+
title: `📜 Prompt History (${historyPosition}/${totalMessages})`,
184145
description: `\`\`\`\n${olderMessage}\n\`\`\``,
185-
fields: [
186-
{ name: 'Usage', value: 'Copy this message to use with `/claude prompt:...`', inline: false },
187-
{ name: 'Navigation', value: `Position ${historyPosition} of ${totalMessages} messages in history`, inline: false }
188-
],
189146
timestamp: true
190147
}],
191148
components: [
@@ -194,7 +151,7 @@ export function createButtonHandlers(
194151
components: [
195152
{ type: 'button', customId: 'history-previous', label: '⬅️ Older', style: 'secondary' },
196153
{ type: 'button', customId: 'history-next', label: '➡️ Newer', style: 'secondary' },
197-
{ type: 'button', customId: 'history-use', label: '🔄 Use This Message', style: 'primary' },
154+
{ type: 'button', customId: 'history-use', label: '▶️ Run This Prompt', style: 'primary' },
198155
{ type: 'button', customId: 'history-close', label: '❌ Close', style: 'danger' }
199156
]
200157
}
@@ -210,8 +167,8 @@ export function createButtonHandlers(
210167
await ctx.update({
211168
embeds: [{
212169
color: 0xffaa00,
213-
title: '➡️ No Newer Messages',
214-
description: 'You\'ve reached the end of your message history.',
170+
title: '➡️ No Newer Prompts',
171+
description: 'You\'ve reached the end of your prompt history.',
215172
timestamp: true
216173
}],
217174
components: []
@@ -226,12 +183,8 @@ export function createButtonHandlers(
226183
await ctx.update({
227184
embeds: [{
228185
color: 0x0099ff,
229-
title: `➡️ Newer Message (${historyPosition}/${totalMessages})`,
186+
title: `📜 Prompt History (${historyPosition}/${totalMessages})`,
230187
description: `\`\`\`\n${newerMessage}\n\`\`\``,
231-
fields: [
232-
{ name: 'Usage', value: 'Copy this message to use with `/claude prompt:...`', inline: false },
233-
{ name: 'Navigation', value: `Position ${historyPosition} of ${totalMessages} messages in history`, inline: false }
234-
],
235188
timestamp: true
236189
}],
237190
components: [
@@ -240,7 +193,7 @@ export function createButtonHandlers(
240193
components: [
241194
{ type: 'button', customId: 'history-previous', label: '⬅️ Older', style: 'secondary' },
242195
{ type: 'button', customId: 'history-next', label: '➡️ Newer', style: 'secondary' },
243-
{ type: 'button', customId: 'history-use', label: '🔄 Use This Message', style: 'primary' },
196+
{ type: 'button', customId: 'history-use', label: '▶️ Run This Prompt', style: 'primary' },
244197
{ type: 'button', customId: 'history-close', label: '❌ Close', style: 'danger' }
245198
]
246199
}
@@ -256,8 +209,8 @@ export function createButtonHandlers(
256209
await ctx.update({
257210
embeds: [{
258211
color: 0xff0000,
259-
title: '❌ No Message Selected',
260-
description: 'No message available to use.',
212+
title: '❌ No Prompt Selected',
213+
description: 'No prompt available to run.',
261214
timestamp: true
262215
}],
263216
components: []
@@ -268,11 +221,8 @@ export function createButtonHandlers(
268221
await ctx.update({
269222
embeds: [{
270223
color: 0x00ff00,
271-
title: '🔄 Using Previous Message',
272-
description: `Running Claude Code with:\n\`\`\`\n${currentMessage}\n\`\`\``,
273-
fields: [
274-
{ name: 'Status', value: 'Executing...', inline: false }
275-
],
224+
title: '▶️ Running Prompt',
225+
description: `\`\`\`\n${currentMessage}\n\`\`\``,
276226
timestamp: true
277227
}],
278228
components: []

discord/bot.ts

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -336,33 +336,48 @@ export async function createDiscordBot(
336336

337337
// Handle continue with session ID pattern: "continue:sessionId"
338338
if (buttonId.startsWith('continue:')) {
339-
const sessionId = buttonId.split(':')[1];
340-
try {
341-
await ctx.update({
342-
embeds: [{
343-
color: 0xffff00,
344-
title: '\u27a1\ufe0f Continue Session',
345-
description: `Use \`/continue\` or \`/claude session_id:${sessionId}\` to continue this conversation.`,
346-
fields: [
347-
{ name: 'Session ID', value: `\`${sessionId}\``, inline: false }
348-
],
349-
timestamp: true
350-
}]
351-
});
352-
} catch (error) {
353-
console.error(`Error handling continue button:`, error);
339+
if (dependencies.onContinueSession) {
340+
try {
341+
await dependencies.onContinueSession(ctx);
342+
} catch (error) {
343+
console.error('Error handling continue button:', error);
344+
try {
345+
await ctx.followUp({
346+
content: `Error continuing session: ${error instanceof Error ? error.message : 'Unknown error'}`,
347+
ephemeral: true
348+
});
349+
} catch { /* ignore follow-up errors */ }
350+
}
351+
} else {
352+
// Fallback: show session ID text if callback not wired
353+
const sessionId = buttonId.split(':')[1];
354+
try {
355+
await ctx.update({
356+
embeds: [{
357+
color: 0xffff00,
358+
title: '\u27a1\ufe0f Continue Session',
359+
description: `Use \`/continue\` or \`/claude session_id:${sessionId}\` to continue this conversation.`,
360+
fields: [
361+
{ name: 'Session ID', value: `\`${sessionId}\``, inline: false }
362+
],
363+
timestamp: true
364+
}]
365+
});
366+
} catch (error) {
367+
console.error(`Error handling continue button fallback:`, error);
368+
}
354369
}
355370
return;
356371
}
357372

358-
// Handle copy session ID pattern: "copy-session:sessionId"
373+
// Handle copy session ID pattern: "copy-session:sessionId" (legacy — kept for old messages)
359374
if (buttonId.startsWith('copy-session:')) {
360375
const sessionId = buttonId.split(':')[1];
361376
try {
362377
await ctx.update({
363378
embeds: [{
364379
color: 0x00ff00,
365-
title: '📋 Session ID',
380+
title: '\ud83d\udccb Session ID',
366381
description: `\`${sessionId}\``,
367382
fields: [
368383
{ name: 'Usage', value: 'Copy this ID to use with `/claude session_id:...`', inline: false }

discord/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,6 @@ export interface BotDependencies {
9393
cleanSessionId?: (sessionId: string) => string;
9494
/** Optional bot settings for mention functionality */
9595
botSettings?: BotSettings;
96+
/** Callback to actually continue a Claude session from a button click */
97+
onContinueSession?: (ctx: InteractionContext) => Promise<void>;
9698
}

index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,10 @@ export async function createClaudeCodeBot(config: BotConfig) {
181181
const dependencies: BotDependencies = {
182182
commands: getAllCommands(),
183183
cleanSessionId,
184-
botSettings
184+
botSettings,
185+
onContinueSession: async (ctx) => {
186+
await allHandlers.claude.onContinue(ctx);
187+
},
185188
};
186189

187190
// Create Discord bot

0 commit comments

Comments
 (0)