Skip to content

feat: add /remind command with natural language time parsing#153

Merged
BillChirico merged 15 commits intomainfrom
feat/remind-command
Mar 1, 2026
Merged

feat: add /remind command with natural language time parsing#153
BillChirico merged 15 commits intomainfrom
feat/remind-command

Conversation

@BillChirico
Copy link
Collaborator

Summary

Personal reminder system with natural language time parsing, recurring reminders, and snooze buttons.

New Commands

  • /remind me <time> <message> — set a reminder with natural language time
  • /remind list — view active reminders in an embed
  • /remind cancel <id> — cancel an owned reminder

Features

  • Zero-dependency time parser — supports in 5 minutes, tomorrow at 3pm, next monday, 5m, 2h, 30s, etc.
  • Snooze buttons — 15m, 1h, Tomorrow, Dismiss on fired reminders
  • DM delivery with channel mention fallback if DMs are closed
  • Recurring reminders via cron expressions
  • Per-user limits — configurable max (default 25)
  • Config gatingconfig.reminders.enabled controls the feature
  • Persistent snooze — survives bot restarts (DB-backed)

New Files

File Purpose
migrations/015_reminders.cjs Reminders table + partial index on remind_at
src/commands/remind.js Slash command handler (me/list/cancel)
src/utils/timeParser.js Natural language time parser (zero deps)
src/modules/reminderHandler.js Check/fire/snooze/dismiss logic

Integration Points

  • Scheduler polls reminders every 60s tick
  • Button handler registered in events.js
  • reminders added to SAFE_CONFIG_KEYS allowlist
  • config.json updated with reminders section

Tests

65 new tests across 3 test files:

  • tests/utils/timeParser.test.js — 41 tests (edge cases, all formats)
  • tests/modules/reminderHandler.test.js — 14 tests (fire, snooze, dismiss, recurring)
  • tests/commands/remind.test.js — 10 tests (create, list, cancel, limits, config gate)

All 2712 tests pass. Zero lint errors.

Closes #137

Copilot AI review requested due to automatic review settings February 28, 2026 21:42
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 28, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 92e7a42 and 1bd6271.

📒 Files selected for processing (13)
  • config.json
  • migrations/015_reminders.cjs
  • src/api/utils/configAllowlist.js
  • src/api/utils/configValidation.js
  • src/commands/remind.js
  • src/modules/events.js
  • src/modules/reminderHandler.js
  • src/modules/scheduler.js
  • src/utils/cronParser.js
  • src/utils/timeParser.js
  • tests/commands/remind.test.js
  • tests/modules/reminderHandler.test.js
  • tests/utils/timeParser.test.js

📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Added /remind command to create, list, and cancel personal reminders with natural language time parsing support
    • Added snooze and dismiss actions for reminders via interactive buttons
    • Added support for recurring reminders using cron expressions
    • Added AI thread mode configuration options for enhanced chat organization

Walkthrough

Introduces a personal reminder system enabling users to create, list, and cancel reminders with natural language time parsing, recurring cron support, snooze buttons, and database persistence. Integrates with the scheduler for polling and includes configuration management, migrations, and comprehensive test coverage.

Changes

Cohort / File(s) Summary
Configuration & Allowlist
config.json, src/api/utils/configAllowlist.js, src/api/utils/configValidation.js
Added reminders top-level config object with enabled and maxPerUser fields; added remind to permissions.allowedCommands; updated allowlist and validation schemas.
Database Migration
migrations/015_reminders.cjs
Created reminders table with id, guild_id, user_id, channel_id, message, remind_at, recurring_cron, snoozed_count, failed_delivery_count, completed, created_at; added three optimized indexes for due/active reminder queries.
Time Parsing Utilities
src/utils/timeParser.js, src/utils/cronParser.js
Added zero-dependency natural language time parser supporting shorthand durations, relative expressions, and weekday references; added cron expression parser with next-run calculation via minute-by-minute iteration.
Reminder Command & Handler
src/commands/remind.js, src/modules/reminderHandler.js
Implemented /remind me/list/cancel command with per-user limits and advisory locks; added reminder delivery, snooze/dismiss button handlers, and recurring reminder scheduling via cron.
Event & Scheduler Integration
src/modules/events.js, src/modules/scheduler.js
Registered reminder button interaction handler; integrated checkReminders polling into scheduler cycle; re-exported cron utilities for backward compatibility.
Test Suites
tests/commands/remind.test.js, tests/modules/reminderHandler.test.js, tests/utils/timeParser.test.js
Added 1,081 lines of test coverage for command execution, time parsing formats, reminder delivery, snooze logic, and edge cases including database errors and permission validation.

Possibly related PRs

Suggested reviewers

  • claude
✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/remind-command

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@claude
Copy link

claude bot commented Feb 28, 2026

Claude finished @BillChirico's task in 3m 23s —— View job


Code Review — PR #153: feat: add /remind command

  • Read AGENTS.md and CLAUDE.md for project conventions
  • Review all changed files (15 files, 2004 additions)
  • Post inline comments for issues found
  • Post summary with verdict

2 issues remaining (0 critical, 2 warnings). Most feedback from previous rounds has been addressed — nice iteration.

# Severity File Issue
1 🟡 Warning config.json:139-168 Missing remind entry in permissions.allowedCommands — defaults to admin-only
2 🟡 Warning src/commands/remind.js:118-142 Race condition: COUNT + INSERT not atomic — concurrent calls can bypass maxPerUser

Verdict: Request changes. See inline comment and review body for details and fix instructions.

@claude
Copy link

claude bot commented Feb 28, 2026

Review Summary

5 issues found across the PR (0 critical, 4 warnings, 1 nitpick).

# Severity File Issue
1 🟡 Warning config.json:265 reminders.enabled defaults to true — inconsistent with all other features which default to false
2 🟡 Warning config.json Missing remind entry in permissions.allowedCommands
3 🟡 Warning src/modules/reminderHandler.js:131-133 checkReminders doesn't null-check getPool() — will crash if DB is unavailable
4 🟡 Warning src/api/utils/configValidation.js Missing reminders schema in CONFIG_SCHEMA — API config writes won't be validated
5 🔵 Nitpick config.json:267 maxRecurring config value exists but is never enforced (dead config)

Not flagged (acceptable): Documentation (AGENTS.md, README) not updated — required per AGENTS.md conventions for new commands/modules/tables, but can be done as a follow-up.

📋 AI-friendly fix prompt (click to expand)
Fix the following issues in the volvox-bot repo on branch feat/remind-command:

1. In config.json, change reminders.enabled from true to false (line 265)
   to match the convention of all other optional features defaulting to disabled.

2. In config.json, add "remind": "everyone" to the permissions.allowedCommands
   object (after the "showcase" entry around line 167) to match the pattern
   used by all other slash commands.

3. In src/modules/reminderHandler.js, add a null check for pool in checkReminders()
   after line 132. Change:
     export async function checkReminders(client) {
       const pool = getPool();
       const { rows } = await pool.query(
   To:
     export async function checkReminders(client) {
       const pool = getPool();
       if (!pool) return;
       const { rows } = await pool.query(

4. In src/api/utils/configValidation.js, add a reminders schema entry to
   CONFIG_SCHEMA (after the triage entry, before the closing brace around line 144):
     reminders: {
       type: 'object',
       properties: {
         enabled: { type: 'boolean' },
         maxPerUser: { type: 'number' },
         maxRecurring: { type: 'number' },
       },
     },

5. (Optional) In config.json, either remove the maxRecurring key (line 267)
   since it is never enforced, or add enforcement in the remind command for
   recurring reminder creation. Currently dead config.

6. Update AGENTS.md:
   - Add to Key Files table:
     | src/commands/remind.js | Remind command — /remind me/list/cancel with natural language time parsing |
     | src/utils/timeParser.js | Zero-dependency natural language time parser for reminder scheduling |
     | src/modules/reminderHandler.js | Reminder check/fire/snooze/dismiss logic, called by scheduler |
   - Add to Database Tables:
     | reminders | Personal reminders — guild/user/channel scoped, supports recurring via cron, snooze tracking |

Copy link

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5 issues found: reminders.enabled defaults to true (should be false per convention), missing 'remind' in permissions.allowedCommands, checkReminders() missing null pool check, missing reminders schema in CONFIG_SCHEMA for API validation, and dead maxRecurring config. See inline comments and summary comment for details.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new /remind feature to the bot, introducing personal reminders with a zero-dependency natural-language time parser and a scheduler-driven delivery loop.

Changes:

  • Implement /remind command (me/list/cancel) backed by a new reminders DB table.
  • Add a natural language time parser utility and comprehensive tests.
  • Integrate reminder polling into the existing scheduler and register button handlers for snooze/dismiss actions.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
migrations/015_reminders.cjs Adds reminders table and a due-reminders partial index.
src/utils/timeParser.js Implements zero-dependency parsing for relative/weekday/tomorrow formats.
src/modules/reminderHandler.js Fires due reminders, builds snooze/dismiss buttons, handles button interactions.
src/commands/remind.js Implements /remind me, /remind list, /remind cancel.
src/modules/scheduler.js Calls checkReminders() from the existing 60s polling loop.
src/modules/events.js Registers an InteractionCreate handler for reminder buttons.
src/api/utils/configAllowlist.js Allowlists reminders config for API usage.
src/api/utils/configValidation.js Formatting-only change to error push line wrapping.
src/modules/welcomeOnboarding.js Formatting-only change (multi-line ternaries).
config.json Adds reminders config section and minor prompt/message encoding changes.
tests/utils/timeParser.test.js Adds unit tests for time parsing and parsing+message splitting.
tests/modules/reminderHandler.test.js Adds tests for firing, fallback delivery, snooze, dismiss, and recurring reschedule behavior.
tests/commands/remind.test.js Adds tests for command flow, config gate, limits, list, cancel.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

coderabbitai[bot]
coderabbitai bot previously approved these changes Feb 28, 2026
coderabbitai[bot]
coderabbitai bot previously approved these changes Feb 28, 2026
Copy link

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

7 issues found (0 critical, 6 warnings, 1 nitpick). See inline comments for details.

Summary of issues:

  1. 🟡 config.json: Missing remind entry in permissions.allowedCommands — every other command has one (AGENTS.md step 5)
  2. 🟡 src/modules/reminderHandler.js:12: Circular dependency between scheduler.jsreminderHandler.js — works at runtime but fragile
  3. 🟡 src/modules/reminderHandler.js:141: Reminder marked completed even when notification delivery fails silently (both DM + channel fail)
  4. 🟡 src/modules/reminderHandler.js:186: handleReminderSnooze missing pool null check — crashes if DB unavailable
  5. 🟡 src/modules/reminderHandler.js:239: handleReminderDismiss missing pool null check — crashes if DB unavailable
  6. 🟡 migrations/015_reminders.cjs:32: Missing composite index on (guild_id, user_id) WHERE completed = false for per-user queries
  7. 🔵 config.json:267: Dead config maxRecurring — defined but never enforced

Not flagged: AGENTS.md/README documentation updates — required per conventions but acceptable as follow-up.

@greptile-apps
Copy link

greptile-apps bot commented Feb 28, 2026

Greptile Summary

Adds a personal reminder system with natural language time parsing (in 5 minutes, tomorrow at 3pm, next monday), snooze buttons (15m/1h/Tomorrow/Dismiss), and DM delivery with channel fallback. The implementation includes comprehensive test coverage (65 tests) and proper database schema with optimized indexes.

Key changes:

  • New slash command /remind me/list/cancel with proper transaction handling and advisory locks to prevent race conditions
  • Zero-dependency time parser supporting multiple natural language formats with 41 comprehensive tests
  • Persistent snooze via database-backed state that survives bot restarts
  • Per-user limits (default 25) enforced atomically via transactions
  • Config gating via config.reminders.enabled flag

Issues found:

  • Critical: src/modules/reminderHandler.js violates the error-handling rule — multiple database queries lack try/catch blocks (lines 143-145, 240, 266-269, 309, 323), which will cause unhandled errors to bubble up without contextual logging when DB operations fail

Confidence Score: 3/5

  • Safe to merge after fixing error handling violations in reminderHandler.js
  • Score reflects solid implementation with comprehensive tests and proper architecture, but critical error-handling violations in reminderHandler.js must be resolved before merge — DB query failures will currently bubble up without proper logging or user-friendly error responses
  • src/modules/reminderHandler.js requires error handling fixes for all database queries

Important Files Changed

Filename Overview
src/modules/reminderHandler.js reminder polling, notification delivery, and button handlers — missing try/catch blocks around database queries violate error-handling rule
src/commands/remind.js slash command handler for /remind me/list/cancel — proper error handling with transactions and advisory locks for race condition prevention
src/utils/timeParser.js zero-dependency natural language time parser supporting shorthand, "in N unit", "tomorrow", and "next " formats with comprehensive test coverage
migrations/015_reminders.cjs creates reminders table with appropriate partial indexes on (remind_at) and (guild_id, user_id) for active reminders
src/modules/scheduler.js adds checkReminders() call to 60-second polling loop
src/modules/events.js registers reminder snooze/dismiss button handler with proper error handling wrapper

Last reviewed commit: 1bd6271

Copy link

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 issues found (0 critical, 3 warnings, 1 nitpick). Most issues from previous reviews have been addressed. Remaining:

  1. 🟡 config.json: Missing remind entry in permissions.allowedCommands — defaults to admin-only when permissions enabled
  2. 🟡 src/commands/remind.js:30: No setMaxLength on message string option — reminder delivery can fail if message exceeds embed 4096-char limit
  3. 🟡 src/modules/reminderHandler.js:143: checkReminders doesn't respect per-guild reminders.enabled — fires reminders for guilds that disabled the feature
  4. 🔵 src/api/utils/configValidation.js:149: maxRecurring in schema but removed from config.json — dead schema property

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Pip Build added 12 commits February 28, 2026 18:18
Implement personal reminder system with:
- /remind me <time> <message> — set reminders with natural language
- /remind list — view active reminders in an embed
- /remind cancel <id> — cancel owned reminders

Features:
- Zero-dependency natural language time parser (src/utils/timeParser.js)
  supports: 'in 5 minutes', 'tomorrow at 3pm', 'next monday', '5m', etc.
- Snooze buttons (15m, 1h, Tomorrow, Dismiss) on fired reminders
- DM delivery with channel mention fallback
- Recurring reminders via cron expressions
- Per-user reminder limits (configurable, default 25)
- Config gating via config.reminders.enabled
- Persistent snooze across bot restarts (DB-backed)

New files:
- migrations/015_reminders.cjs — reminders table + partial index
- src/commands/remind.js — slash command handler
- src/utils/timeParser.js — natural language time parser
- src/modules/reminderHandler.js — check/fire/snooze/dismiss logic

Integration:
- Scheduler polls reminders every 60s tick
- Button handler registered in events.js
- 'reminders' added to SAFE_CONFIG_KEYS allowlist
- config.json updated with reminders section

Tests: 65 new tests (timeParser: 41, reminderHandler: 14, command: 10)

Closes #137
- Import getConfig from config.js
- Check if reminders are disabled for a guild before processing
- Skip reminders that belong to guilds with reminders disabled
- This prevents pending reminders from firing if guild admin disables feature
- Add .setMaxLength(200) to 'when' option (e.g., 'tomorrow at 3pm')
- Add .setMaxLength(500) to 'message' option
- Prevents oversized inputs that would exceed Discord embed description limit (4096 chars)
- Provides better validation at input time
- Add idx_reminders_user composite index on (guild_id, user_id, completed)
- Improves performance for frequent /remind list, /remind cancel, and count queries
- These queries filter by (guild_id, user_id) with completed=false
- Complements existing idx_reminders_user_active filtered index
- Update 'tomorrow at' regex to capture '3 pm' and '3:30 am' (with spaces)
- Update 'next <day> at' regex to capture spaced am/pm suffix
- Change regex from (.+?) to (.+?(?:\s+[ap]m)?) for time capture groups
- Add tests for 'tomorrow at 3 pm', 'tomorrow at 9:30 am'
- Add tests for 'next fri at 9 am', 'next monday at 2:30 pm'
- Fixes issue where spaced am/pm was not properly captured
- Remove maxRecurring property from reminders schema
- This property was removed from config.json but remained in schema
- Schema now only validates enabled and maxPerUser properties
- Prevents validation errors for removed config option
coderabbitai[bot]
coderabbitai bot previously approved these changes Feb 28, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@BillChirico BillChirico disabled auto-merge March 1, 2026 00:55
@BillChirico BillChirico merged commit ac05e0f into main Mar 1, 2026
9 of 13 checks passed
@BillChirico BillChirico deleted the feat/remind-command branch March 1, 2026 00:59
Comment on lines +143 to +145
const { rows } = await pool.query(
'SELECT * FROM reminders WHERE completed = false AND remind_at <= NOW()',
);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wrap in try/catch per error-handling rule — if query fails, error bubbles up without context

Suggested change
const { rows } = await pool.query(
'SELECT * FROM reminders WHERE completed = false AND remind_at <= NOW()',
);
try {
const { rows } = await pool.query(
'SELECT * FROM reminders WHERE completed = false AND remind_at <= NOW()',
);
for (const reminder of rows) {
// ... existing reminder processing ...
}
} catch (err) {
logError('Failed to fetch due reminders', {
error: err instanceof Error ? err.message : String(err),
});
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/modules/reminderHandler.js
Line: 143-145

Comment:
wrap in try/catch per error-handling rule — if query fails, error bubbles up without context

```suggestion
  try {
    const { rows } = await pool.query(
      'SELECT * FROM reminders WHERE completed = false AND remind_at <= NOW()',
    );
    
    for (const reminder of rows) {
      // ... existing reminder processing ...
    }
  } catch (err) {
    logError('Failed to fetch due reminders', {
      error: err instanceof Error ? err.message : String(err),
    });
  }
```

How can I resolve this? If you propose a fix, please make it concise.

return;
}

const { rows } = await pool.query('SELECT * FROM reminders WHERE id = $1', [reminderId]);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wrap in try/catch per error-handling rule

Suggested change
const { rows } = await pool.query('SELECT * FROM reminders WHERE id = $1', [reminderId]);
try {
const { rows } = await pool.query('SELECT * FROM reminders WHERE id = $1', [reminderId]);
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/modules/reminderHandler.js
Line: 240

Comment:
wrap in try/catch per error-handling rule

```suggestion
  try {
    const { rows } = await pool.query('SELECT * FROM reminders WHERE id = $1', [reminderId]);
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +266 to +269
await pool.query(
'UPDATE reminders SET remind_at = $1, completed = false, snoozed_count = snoozed_count + 1 WHERE id = $2',
[newRemindAt.toISOString(), reminderId],
);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wrap in try/catch per error-handling rule

Suggested change
await pool.query(
'UPDATE reminders SET remind_at = $1, completed = false, snoozed_count = snoozed_count + 1 WHERE id = $2',
[newRemindAt.toISOString(), reminderId],
);
try {
await pool.query(
'UPDATE reminders SET remind_at = $1, completed = false, snoozed_count = snoozed_count + 1 WHERE id = $2',
[newRemindAt.toISOString(), reminderId],
);
} catch (err) {
logError('Failed to snooze reminder', {
reminderId,
userId: interaction.user.id,
error: err instanceof Error ? err.message : String(err),
});
await interaction.reply({
content: '❌ Failed to snooze reminder. Please try again.',
ephemeral: true,
});
return;
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/modules/reminderHandler.js
Line: 266-269

Comment:
wrap in try/catch per error-handling rule

```suggestion
  try {
    await pool.query(
      'UPDATE reminders SET remind_at = $1, completed = false, snoozed_count = snoozed_count + 1 WHERE id = $2',
      [newRemindAt.toISOString(), reminderId],
    );
  } catch (err) {
    logError('Failed to snooze reminder', {
      reminderId,
      userId: interaction.user.id,
      error: err instanceof Error ? err.message : String(err),
    });
    
    await interaction.reply({
      content: '❌ Failed to snooze reminder. Please try again.',
      ephemeral: true,
    });
    return;
  }
```

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

return;
}

const { rows } = await pool.query('SELECT * FROM reminders WHERE id = $1', [reminderId]);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wrap in try/catch per error-handling rule

Suggested change
const { rows } = await pool.query('SELECT * FROM reminders WHERE id = $1', [reminderId]);
try {
const { rows } = await pool.query('SELECT * FROM reminders WHERE id = $1', [reminderId]);
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/modules/reminderHandler.js
Line: 309

Comment:
wrap in try/catch per error-handling rule

```suggestion
  try {
    const { rows } = await pool.query('SELECT * FROM reminders WHERE id = $1', [reminderId]);
```

How can I resolve this? If you propose a fix, please make it concise.

return;
}

await pool.query('UPDATE reminders SET completed = true WHERE id = $1', [reminderId]);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wrap in try/catch per error-handling rule

Suggested change
await pool.query('UPDATE reminders SET completed = true WHERE id = $1', [reminderId]);
try {
await pool.query('UPDATE reminders SET completed = true WHERE id = $1', [reminderId]);
} catch (err) {
logError('Failed to dismiss reminder', {
reminderId,
userId: interaction.user.id,
error: err instanceof Error ? err.message : String(err),
});
await interaction.reply({
content: '❌ Failed to dismiss reminder. Please try again.',
ephemeral: true,
});
return;
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/modules/reminderHandler.js
Line: 323

Comment:
wrap in try/catch per error-handling rule

```suggestion
  try {
    await pool.query('UPDATE reminders SET completed = true WHERE id = $1', [reminderId]);
  } catch (err) {
    logError('Failed to dismiss reminder', {
      reminderId,
      userId: interaction.user.id,
      error: err instanceof Error ? err.message : String(err),
    });
    
    await interaction.reply({
      content: '❌ Failed to dismiss reminder. Please try again.',
      ephemeral: true,
    });
    return;
  }
```

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: /remind — personal reminders with snooze and recurring options

3 participants