From 301c301c296d5615b3f3171a09d8613bc2d2e762 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Feb 2026 21:04:20 +0000 Subject: [PATCH 1/7] Initial plan From 37e7c0a24daacfa3a21d30917ed7959adef31bde Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Feb 2026 21:06:35 +0000 Subject: [PATCH 2/7] feat: add Copilot instructions for repository Co-authored-by: anna328p <9790772+anna328p@users.noreply.github.com> --- .github/copilot-instructions.md | 225 ++++++++++++++++++++++++++++++++ 1 file changed, 225 insertions(+) create mode 100644 .github/copilot-instructions.md diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..9ce51de --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,225 @@ +# GitHub Copilot Instructions for qbot + +## Project Overview + +qbot is a Discord bot written in Ruby for the unofficial Arch Linux community. It's a modular bot that manages support channels, provides Arch Linux resources, and includes various utility features. + +## Architecture + +- **Main executable**: `qbot` - Loads and initializes the bot +- **Modules**: `modules/*.rb` - Each module contains bot commands and support functions +- **Library code**: `lib/qbot/*.rb` - Shared helper methods and core functionality +- **Database**: SQLite with ActiveRecord ORM +- **Framework**: discordrb for Discord integration +- **Configuration**: YAML files in `config/` directory +- **Localization**: YAML files in `share/locales/` directory + +## Coding Standards + +### General Ruby Conventions + +- **Always** include `# frozen_string_literal: true` at the top of every Ruby file +- Follow the configured RuboCop rules in `.rubocop.yml` +- Maximum line length: 80 characters +- Use semantic block delimiters (braces for functional, do/end for procedural) +- Prefer consistent indentation for arrays and method arguments + +### Module Development + +- Each module extends `Discordrb::Commands::CommandContainer` +- Commands use the `command :name, { options... } do |event, *args|` pattern +- Use `ServerConfig.extend_schema` to add per-server configuration options +- Never hard-code names, IDs, or similar values +- Module-level documentation should use YARD-style comments (`##`) + +### Code Style + +- Use modern Ruby syntax (Ruby 3.2+) +- Prefer pattern matching with `rails-pattern_matching` where appropriate +- Use numbered block parameters (`_1`, `_2`) when appropriate +- Inline access modifiers: `private def method_name` +- Avoid parallel assignment +- Use single-line method definitions with `=` for simple methods: `def method_name = value` + +## Internationalization (i18n) + +- **All** user-facing strings must go through the `t()` helper method +- Add translation keys to `share/locales/en.yml` at minimum +- Translation files use nested YAML structure +- Available locales: `:en`, `:tok`, `:en_kawaii`, `:de` +- Use descriptive keys: `module.command.message-type` +- The `embed` helper creates Discord embeds for bot responses + +## Database + +- Use ActiveRecord models in `lib/qbot/db/models/` +- Define schemas and migrations in `lib/qbot/db/schema/` +- Tables include: `ServerConfig`, `ColorRole`, `Query`, `Snippet`, `UserConfig`, etc. +- Database initialization: run `Database.define_schema` in IRB console +- Use concerns in `lib/qbot/db/concerns/` for shared model behavior +- Extend `ServerConfig` schema with `ServerConfig.extend_schema do ... end` + +## Testing and Quality Assurance + +### Linting + +- Run RuboCop: `bundle exec rubocop --parallel` +- RuboCop must return no offenses before submitting PRs +- Try to avoid disabling cops; fix the underlying issue instead + +### Commit Messages + +- Use [Conventional Commits](https://www.conventionalcommits.org/) format +- Examples: + - `feat: add new command for querying packages` + - `fix: correct color role assignment logic` + - `i18n: added German translation` + - `docs: update module documentation` + +### Markdown Linting + +- Markdown files are linted in CI +- Follow `.markdownlintrc` configuration + +## Development Workflow + +### Setting Up Development Environment + +**With Nix (preferred):** +```bash +nix-shell +# or +nix develop +``` + +**Without Nix:** +```bash +bundle install +``` + +### Running the Bot + +```bash +bundle exec qbot +``` + +### Bot CLI Commands + +- `rs` or `restart` - Restart the bot +- `rc` or `reload-config` - Reload configuration +- `lm` or `load-module` - Load or reload a module +- `irb` - Open REPL in bot context +- `quit` or `stop` - Stop the bot + +### Configuration + +- Copy example config to `config/global.yml` +- Configure Discord bot token and other settings +- Per-server configuration stored in database + +## Adding New Features + +### Creating a New Module + +1. Create `modules/modulename.rb` +2. Define the module extending `Discordrb::Commands::CommandContainer` +3. Add commands using the `command` DSL +4. Add configuration options with `ServerConfig.extend_schema` +5. Add all user-facing strings to translation files +6. Add command descriptions to `share/locales/en.yml` under `descriptions:` + +### Adding Database Tables + +1. Create the model in `lib/qbot/db/models/` +2. Define the schema in `lib/qbot/db/schema/` +3. Write migration matching existing migration format +4. Run `Database.define_schema` to apply + +### Adding Dependencies + +- Add gems to `Gemfile` +- Run `bundle install` +- If using Nix: source `scripts/binst` in nix-shell to update `gemset.nix` + +## Common Patterns + +### Command Definition + +```ruby +command :commandname, { + aliases: [:alias], + help_available: true, + usage: '.command ', + min_args: 1, + max_args: 2, + permission_level: 1 +} do |event, *args| + # Command implementation + embed t('module.command.response') +end +``` + +### Embedding Responses + +```ruby +embed t('translation.key', variable: value) +``` + +### Server Configuration + +```ruby +ServerConfig.extend_schema do + option :config_name, TBoolean.new, default: false + option :other_option, TEnum.new(%w[option1 option2]), default: 'option1' +end +``` + +### Accessing Configuration + +```ruby +config = ServerConfig.for(event.server) +config.config_name # Access configuration value +``` + +## Security Considerations + +- Never commit secrets or tokens to the repository +- Sanitize user input before using in commands +- Use Rails HTML sanitizer for HTML content: `rails-html-sanitizer` +- Validate and escape user-provided data in database queries +- Use parameterized queries through ActiveRecord + +## File Organization + +- **Main bot files**: `lib/qbot/*.rb` +- **Models**: `lib/qbot/db/models/*.rb` +- **Schema**: `lib/qbot/db/schema/*.rb` +- **Modules**: `modules/*.rb` +- **Module subdirectories**: `modules/modulename/*.rb` for module-specific code +- **Translations**: `share/locales/*.yml` +- **Configuration**: `config/*.yml` +- **Scripts**: `scripts/*` + +## Nix Integration + +This project is a Nix flake with: +- `nixosModule` output for NixOS integration +- Overlay for package availability +- Development shell with all dependencies +- Option `services.qbot` for system-wide configuration + +## Discordrb API + +- Use `event.author` for the user who invoked the command +- Use `event.server` for the current server +- Use `event.channel` for the current channel +- Member roles: `member.role?(role)`, `member.modify_roles(add, remove, reason)` +- Respond with embeds: `embed { |e| e.description = text }` + +## Style Preferences + +- Prefer clarity over cleverness +- Document complex logic with comments +- Keep modules focused and single-purpose +- Minimize external dependencies where possible +- Follow existing patterns in the codebase From e6ddda91e36677bb7cf60887927a35e59554972b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Feb 2026 21:07:45 +0000 Subject: [PATCH 3/7] docs: improve Copilot instructions with examples and clarifications Co-authored-by: anna328p <9790772+anna328p@users.noreply.github.com> --- .github/copilot-instructions.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 9ce51de..34e0253 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -37,9 +37,12 @@ qbot is a Discord bot written in Ruby for the unofficial Arch Linux community. I - Use modern Ruby syntax (Ruby 3.2+) - Prefer pattern matching with `rails-pattern_matching` where appropriate - Use numbered block parameters (`_1`, `_2`) when appropriate + - Example: `@options.to_h { |e| [e.nickname || e.typeface, e] }` - Inline access modifiers: `private def method_name` - Avoid parallel assignment -- Use single-line method definitions with `=` for simple methods: `def method_name = value` +- Use single-line method definitions with `=` for simple one-liners + - Example: `def self.hex_code?(string) = string.match?(/^#?[[:xdigit:]]{6}$/)` +- Use forwarding arguments `(...)` to pass all arguments to super or another method ## Internationalization (i18n) @@ -185,9 +188,11 @@ config.config_name # Access configuration value - Never commit secrets or tokens to the repository - Sanitize user input before using in commands -- Use Rails HTML sanitizer for HTML content: `rails-html-sanitizer` +- Use `Rails::Html::FullSanitizer.new.sanitize(content)` for HTML content (gem: `rails-html-sanitizer`) + - This is used even though the bot uses discordrb, as some modules process HTML (e.g., wiki content) - Validate and escape user-provided data in database queries - Use parameterized queries through ActiveRecord +- Be cautious with user-provided URLs and external content ## File Organization From 109c77ed7139b6045aa3d94c33f9722191c7731c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Feb 2026 21:08:24 +0000 Subject: [PATCH 4/7] docs: fix code examples to accurately demonstrate Ruby features Co-authored-by: anna328p <9790772+anna328p@users.noreply.github.com> --- .github/copilot-instructions.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 34e0253..4579bba 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -37,12 +37,14 @@ qbot is a Discord bot written in Ruby for the unofficial Arch Linux community. I - Use modern Ruby syntax (Ruby 3.2+) - Prefer pattern matching with `rails-pattern_matching` where appropriate - Use numbered block parameters (`_1`, `_2`) when appropriate - - Example: `@options.to_h { |e| [e.nickname || e.typeface, e] }` + - Example: `pkgs.first(5).map { package_field(_1) }` + - Example: `roles = records.pluck(:role_id).map { event.server.role(_1) }` - Inline access modifiers: `private def method_name` - Avoid parallel assignment - Use single-line method definitions with `=` for simple one-liners - Example: `def self.hex_code?(string) = string.match?(/^#?[[:xdigit:]]{6}$/)` - Use forwarding arguments `(...)` to pass all arguments to super or another method + - Example: `def find_by_abbrev(...); super; end` ## Internationalization (i18n) From d35bbbf6a9b340e517e60cb744f9af90b7f21a46 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Feb 2026 21:09:01 +0000 Subject: [PATCH 5/7] docs: clarify locale symbols and script sourcing command Co-authored-by: anna328p <9790772+anna328p@users.noreply.github.com> --- .github/copilot-instructions.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 4579bba..04d7e56 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -51,7 +51,7 @@ qbot is a Discord bot written in Ruby for the unofficial Arch Linux community. I - **All** user-facing strings must go through the `t()` helper method - Add translation keys to `share/locales/en.yml` at minimum - Translation files use nested YAML structure -- Available locales: `:en`, `:tok`, `:en_kawaii`, `:de` +- Available locales (Ruby symbols): `:en`, `:tok`, `:en_kawaii`, `:de` - Use descriptive keys: `module.command.message-type` - The `embed` helper creates Discord embeds for bot responses @@ -144,7 +144,7 @@ bundle exec qbot - Add gems to `Gemfile` - Run `bundle install` -- If using Nix: source `scripts/binst` in nix-shell to update `gemset.nix` +- If using Nix: run `. scripts/binst` (source the script) in nix-shell to update `gemset.nix` ## Common Patterns From 26d643f3b2088f2192812218bf6008145c6c4a13 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Feb 2026 21:09:33 +0000 Subject: [PATCH 6/7] docs: improve shell command clarity for script sourcing Co-authored-by: anna328p <9790772+anna328p@users.noreply.github.com> --- .github/copilot-instructions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 04d7e56..9b952e3 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -144,7 +144,7 @@ bundle exec qbot - Add gems to `Gemfile` - Run `bundle install` -- If using Nix: run `. scripts/binst` (source the script) in nix-shell to update `gemset.nix` +- If using Nix: run `. scripts/binst` or `source scripts/binst` in nix-shell to update `gemset.nix` ## Common Patterns From 8bd7a24a5c72cc58fdc035509e67b8ebcf22ca47 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Feb 2026 21:21:23 +0000 Subject: [PATCH 7/7] docs: add modernization notes for dry-system, rom-rb, and Discord features Co-authored-by: anna328p <9790772+anna328p@users.noreply.github.com> --- .github/copilot-instructions.md | 51 +++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 9b952e3..9769a3e 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -4,12 +4,35 @@ qbot is a Discord bot written in Ruby for the unofficial Arch Linux community. It's a modular bot that manages support channels, provides Arch Linux resources, and includes various utility features. -## Architecture +## ⚠️ Modernization in Progress + +**This project is undergoing significant modernization and refactoring.** When contributing new code or refactoring existing code, prioritize modern patterns and best practices over legacy conventions described below. + +### Target Architecture + +- **Dependency injection**: Migrate to `dry-system` for container-based dependency management +- **Database layer**: Transition from ActiveRecord to `rom-rb` for more explicit, flexible data access +- **Discord features**: Adopt modern Discord API features: + - Slash commands (application commands) over prefix commands + - Components v2 (buttons, select menus, modals) in favor of traditional embeds + - Interaction-based architecture for better UX + +### Modernization Goals + +- **Reduce global state**: Rewrite modules to minimize and centralize global state; prefer dependency injection +- **Improve error handling**: Implement consistent, comprehensive error handling patterns +- **Define interfaces**: Document and formalize component interfaces and contracts +- **Modern architecture**: Follow contemporary best practices for clean, maintainable architecture +- **Maintain elegance**: Preserve the distinct, personal coding style with functional programming influences + +**Important**: When existing code conflicts with these modernization goals, prefer the modern approach. Legacy patterns should only be preserved when they represent genuinely good design choices. + +## Current Architecture (Legacy) - **Main executable**: `qbot` - Loads and initializes the bot - **Modules**: `modules/*.rb` - Each module contains bot commands and support functions - **Library code**: `lib/qbot/*.rb` - Shared helper methods and core functionality -- **Database**: SQLite with ActiveRecord ORM +- **Database**: SQLite with ActiveRecord ORM (migrating to rom-rb) - **Framework**: discordrb for Discord integration - **Configuration**: YAML files in `config/` directory - **Localization**: YAML files in `share/locales/` directory @@ -24,7 +47,9 @@ qbot is a Discord bot written in Ruby for the unofficial Arch Linux community. I - Use semantic block delimiters (braces for functional, do/end for procedural) - Prefer consistent indentation for arrays and method arguments -### Module Development +### Module Development (Legacy) + +**Note**: This describes the current legacy pattern. New modules should explore modern Discord interactions (slash commands, components) and dependency injection patterns. - Each module extends `Discordrb::Commands::CommandContainer` - Commands use the `command :name, { options... } do |event, *args|` pattern @@ -32,6 +57,8 @@ qbot is a Discord bot written in Ruby for the unofficial Arch Linux community. I - Never hard-code names, IDs, or similar values - Module-level documentation should use YARD-style comments (`##`) +**For new code**: Consider implementing slash commands and interaction handlers instead of prefix commands where appropriate. + ### Code Style - Use modern Ruby syntax (Ruby 3.2+) @@ -46,6 +73,14 @@ qbot is a Discord bot written in Ruby for the unofficial Arch Linux community. I - Use forwarding arguments `(...)` to pass all arguments to super or another method - Example: `def find_by_abbrev(...); super; end` +### Design Philosophy + +- **Embrace functional programming**: Prefer immutable data, pure functions, and composition +- **Minimize state**: Reduce and centralize mutable state; use dependency injection +- **Clear interfaces**: Document contracts between components; prefer explicit over implicit +- **Elegant expressiveness**: Write code with a distinct, personal style that is both readable and maintainable +- **Pragmatic refactoring**: When refactoring, prioritize clean architecture and modern patterns over preserving legacy code + ## Internationalization (i18n) - **All** user-facing strings must go through the `t()` helper method @@ -57,6 +92,10 @@ qbot is a Discord bot written in Ruby for the unofficial Arch Linux community. I ## Database +**Note**: The project is migrating from ActiveRecord to rom-rb. New database code should explore rom-rb patterns. + +### Current (Legacy) ActiveRecord Patterns + - Use ActiveRecord models in `lib/qbot/db/models/` - Define schemas and migrations in `lib/qbot/db/schema/` - Tables include: `ServerConfig`, `ColorRole`, `Query`, `Snippet`, `UserConfig`, etc. @@ -64,6 +103,12 @@ qbot is a Discord bot written in Ruby for the unofficial Arch Linux community. I - Use concerns in `lib/qbot/db/concerns/` for shared model behavior - Extend `ServerConfig` schema with `ServerConfig.extend_schema do ... end` +### Future (Target) rom-rb Patterns + +- Prefer explicit repositories and relations over ActiveRecord models +- Separate persistence concerns from domain logic +- Use rom-rb's relation and repository patterns for database access + ## Testing and Quality Assurance ### Linting