Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
0044917
fix(player): harden stream bridge error handling
LucasSantana-Dev May 6, 2026
cfda46d
test(player): add streamBridge and soundcloudMatcher test suites
LucasSantana-Dev May 6, 2026
85777be
ci: extend CI triggers to release/** branches for trunk-based develop…
LucasSantana-Dev May 6, 2026
a5bcb77
ci: extend workflow triggers to release/** branches (#816)
LucasSantana-Dev May 8, 2026
f8f13d4
fix(autoplay): block gospel/spanish candidates from non-matching sess…
LucasSantana-Dev May 8, 2026
ef2bc6c
fix(autoplay): prioritize user tracks, Spotify liked seeds, sertanejo…
LucasSantana-Dev May 8, 2026
54e910a
fix(autoplay): use Spotify genres as fallback to block Spanish gospel…
LucasSantana-Dev May 8, 2026
838b0d9
feat(autoplay): wire recentSkipCount into mood detection (#829)
LucasSantana-Dev May 8, 2026
27dd30d
fix(autoplay): remove YouTube fallback from seed search to prevent cr…
LucasSantana-Dev May 9, 2026
d51a9f9
fix(lastfm): resolve canonical metadata for album art and multi-artis…
LucasSantana-Dev May 9, 2026
1778d14
ci(bot): pin coverage threshold floor before phase-2 cleanup (#835)
LucasSantana-Dev May 9, 2026
777ef44
refactor(autoplay): replace reason string with structured Recommendat…
LucasSantana-Dev May 10, 2026
7aff629
fix(autoplay): block Spanish gospel tracks when Last.fm is not linked…
LucasSantana-Dev May 10, 2026
ed39e74
chore(deps): bump node from 22-alpine to 26-alpine (#831)
dependabot[bot] May 10, 2026
3f5e893
chore(deps): bump trufflesecurity/trufflehog from 5f47aad1c2df34f7c62…
dependabot[bot] May 10, 2026
f4a0a1d
chore(deps-dev): bump the dev-dependencies group with 14 updates (#833)
dependabot[bot] May 10, 2026
a3f31f3
feat(bot): add Spotify API 429 retry with Retry-After header (#808)
LucasSantana-Dev May 10, 2026
4efb1ab
chore(ci): revamp PR review tooling — Claude review + Danger + chill …
LucasSantana-Dev May 13, 2026
1b92400
chore(release): v2.10.0
LucasSantana-Dev May 13, 2026
a266888
Merge remote-tracking branch 'origin/main' into chore/release-v2.10.0
LucasSantana-Dev May 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions .coderabbit.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# CodeRabbit configuration — Lucky
# Docs: https://docs.coderabbit.ai/getting-started/configure-coderabbit
#
# Goal: stop nit-spam from blocking the merge gate. Keep substantive
# bug-finding active. Per workflow.md merge rule: tools should approve
# when there's no real concern, not when there's no comment at all.
language: en-US

reviews:
# 'chill' = minor/nit comments are summarized rather than posted as
# actionable threads that flip the PR to CHANGES_REQUESTED.
profile: chill
# Never auto-block merges on style / opinion. The merge rule already
# gates on substantive concerns, not bot mood.
request_changes_workflow: false
# Keep the high-level summary so reviewers see a TL;DR.
high_level_summary: true
# No poems — they're noise in the comment timeline.
poem: false
# Don't post the per-file walkthrough as a separate review status.
review_status: false
# Collapse the walkthrough so it's clickable but not screen-eating.
collapse_walkthrough: true
# Skip auto-review on these paths — they're either generated or
# policy artifacts where bot opinions don't add value.
path_filters:
- '!**/*.lock'
- '!**/package-lock.json'
- '!**/dist/**'
- '!**/build/**'
- '!**/.next/**'
- '!**/generated/**'
- '!**/__generated__/**'
- '!**/CHANGELOG.md'
- '!**/*.snap'

auto_review:
enabled: true
# Don't review on draft PRs — saves rate-limit budget.
drafts: false
# Run on these base branches; release/** and main only.
base_branches:
- main
- 'release/.*'

chat:
# Don't auto-reply to comments — keeps the thread quiet.
auto_reply: false

# Knowledge-base sources CodeRabbit reads for context.
knowledge_base:
learnings:
scope: auto
issues:
scope: auto
2 changes: 1 addition & 1 deletion .github/workflows/bundle-size.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Bundle Size

on:
pull_request:
branches: [main]
branches: [main, 'release/**']
paths:
- 'packages/frontend/**'
- 'package.json'
Expand Down
10 changes: 7 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ name: CI/CD Pipeline

on:
push:
branches: [main]
branches: [main, 'release/**']
pull_request:
branches: [main]
branches: [main, 'release/**']

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
Expand Down Expand Up @@ -89,7 +89,11 @@ jobs:
run: npx secretlint "**/*"

- name: TruffleHog secret scan
uses: trufflesecurity/trufflehog@5f47aad1c2df34f7c6230784ce9a5a659922f479 # v3.94.3
uses: trufflesecurity/trufflehog@ba0a524d6e51744d9d4e306bc57ac5d6ca5173ea # post-v3.95.2 (2026-05-07)
with:
extra_args: --only-verified
continue-on-error: true

- name: Socket.dev supply chain scan
run: echo "Socket.dev scan -- GitHub App (apps/socket-security) covers PR-level blocking"
# SocketDev/socket-security-action@v1 is unavailable; removed to unblock CI
2 changes: 1 addition & 1 deletion .github/workflows/path-portability.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: Path Portability
on:
pull_request:
push:
branches: [main]
branches: [main, 'release/**']

jobs:
portability:
Expand Down
37 changes: 37 additions & 0 deletions .github/workflows/pr-agent.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: PR Agent

on:
pull_request:
types: [opened, reopened, ready_for_review]
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
pull_request_review:
types: [submitted]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false

jobs:
pr-agent:
name: AI Code Review
runs-on: ubuntu-latest
if: ${{ github.event.sender.type != 'Bot' && (github.event_name != 'issue_comment' || github.event.issue.pull_request != null) }}
permissions:
issues: write
pull-requests: write
contents: read
steps:
- name: PR Agent action
uses: Codium-ai/pr-agent@009ba5a116c4d3273368a6dc53a4efdb7904d519 # main
env:
OPENAI.KEY: ${{ secrets.ANTHROPIC_API_KEY }}
OPENAI.API_TYPE: anthropic
OPENAI.MODEL: claude-sonnet-4-6
CONFIG.AI_PROVIDER: anthropic
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
github_action_config.auto_review: 'true'
github_action_config.auto_describe: 'true'
github_action_config.auto_improve: 'true'
42 changes: 42 additions & 0 deletions .github/workflows/review-tools.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: Review Tools

# Calls the org-level reusable workflows in LucasSantana-Dev/.github
# (single source of truth for the Claude review prompt + Danger runtime).
#
# Tag policy: pinned to the mutable `@v1` tag intentionally. We accept the
# trade-off — automatic adoption of non-breaking central updates is the
# reason these workflows are centralized at all. Breaking changes ship under
# a new major (`@v2`); consumers bump explicitly.
# If a downstream repo needs strict immutability, pin to a commit SHA
# instead of `@v1`.
#
# Repo-specific behavior lives in:
# - dangerfile.ts (rules)
# - .coderabbit.yaml (path filters, base branches)

on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
branches:
- main
- 'release/**'
paths-ignore:
- '**.md'
- 'docs/**'
- 'CHANGELOG.md'
- 'package-lock.json'

# Cancel superseded runs when a newer commit is pushed to the same PR.
concurrency:
group: review-tools-${{ github.event.pull_request.number }}
cancel-in-progress: true

jobs:
claude-review:
uses: LucasSantana-Dev/.github/.github/workflows/claude-review.yml@v1
secrets:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}

danger:
uses: LucasSantana-Dev/.github/.github/workflows/danger.yml@v1
secrets: inherit
4 changes: 2 additions & 2 deletions .github/workflows/sonarcloud.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ name: SonarCloud Analysis

on:
push:
branches: [main]
branches: [main, 'release/**']
pull_request:
branches: [main]
branches: [main, 'release/**']

jobs:
sonarcloud:
Expand Down
23 changes: 23 additions & 0 deletions .review-tools-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"$schema": "https://raw.githubusercontent.com/LucasSantana-Dev/.github/main/schemas/review-tools-config.schema.json",
"version": 1,
"central_workflow_tag": "v1",
"components": {
"claude_review": {
"action": "anthropics/claude-code-action",
"version": "v1",
"model": "claude-sonnet-4-6"
},
"danger": {
"package": "danger",
"version": "^12",
"node": "22"
},
"coderabbit": {
"profile": "chill",
"config_path": ".coderabbit.yaml"
}
},
"installed_at": "2026-05-10",
"installed_by": "manual (pilot consumer for ADR 2026-05-10-multi-repo-review-tools-rollout)"
}
25 changes: 25 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,31 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [2.10.0] - 2026-05-13

### Added
- feat(bot): Spotify API 429 retry with `Retry-After` header parsing — covers both delta-seconds and HTTP-date formats, hardened against unparseable values (#808)
- feat(autoplay): wire `recentSkipCount` into mood detection so the recommender adapts faster to user skips (#829)

### Changed
- refactor(autoplay): replace `reason` string with structured `RecommendationBasis { source, signals[] }`; serialization boundary via `serializeBasis()` (#830)

### Fixed
- fix(autoplay): block Spanish-language gospel tracks from autoplay when Last.fm is not linked, using Spotify-genre fallback and detector hardening (#818, #819, #820, #827)
- fix(autoplay): prioritize user tracks + Spotify-liked seeds, add sertanejo genre filter, expand Last.fm limits (#817)
- fix(lastfm): resolve canonical metadata for album art and multi-artist scrobbles (#821)
- fix(player): harden stream bridge error handling and add 57 missing tests covering reconnect + format negotiation
- fix(autoplay): remove YouTube fallback from seed search to prevent cross-language drift (#827)

### Internal
- chore(ci): revamp PR review tooling — Claude review action + Danger rules + chilled CodeRabbit profile, delegated to org-level reusable workflows (#838)
- ci(bot): pin coverage threshold floor before phase-2 test cleanup (#835)
- ci: extend workflow triggers to `release/**` branches for trunk-based-with-release-branches flow (#816)
- test(player): add `streamBridge` and `soundcloudMatcher` test suites
- chore(deps-dev): bump dev-dependencies group with 14 updates (#833)
- chore(deps): bump trufflesecurity/trufflehog action SHA (#832)
- chore(deps): bump base image from `node:22-alpine` to `node:26-alpine` (#831)

## [2.9.0] - 2026-05-05

### Added
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile.frontend
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# syntax=docker/dockerfile:1
FROM node:22-alpine AS builder
FROM node:26-alpine AS builder

WORKDIR /app

Expand Down
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
</p>

<p align="center">
<b>Self-hosted Discord music bot + React dashboard.</b><br>
TypeScript monorepo · Discord.js 14 · Prisma 7 · ~2500 tests · Zero prod incidents.
<b>The Discord music bot that can't be shut down — because you host it.</b><br>
Self-hosted · Open-source · TypeScript monorepo · ~2500 tests · Zero prod incidents.
</p>

<p align="center">
<a href="https://discord.com/oauth2/authorize?client_id=962198089161134131&scope=bot%20applications.commands&permissions=36970496"><b>→ Invite Lucky</b></a> ·
<a href="https://lucky.lucassantana.tech/invite?utm_source=github&utm_medium=readme&utm_campaign=readme-badge"><b>→ Invite Lucky</b></a> ·
<a href="https://lucky.lucassantana.tech"><b>Dashboard</b></a> ·
<a href="./docs/ARCHITECTURE.md">Architecture</a> ·
<a href="./CHANGELOG.md">Changelog</a> ·
Expand All @@ -20,7 +20,7 @@

<p align="center">
<a href="https://github.com/LucasSantana-Dev/Lucky/actions/workflows/ci.yml"><img src="https://github.com/LucasSantana-Dev/Lucky/actions/workflows/ci.yml/badge.svg" alt="CI" /></a>
<a href="https://discord.com/oauth2/authorize?client_id=962198089161134131&scope=bot%20applications.commands&permissions=36970496"><img src="https://img.shields.io/badge/Invite-Lucky%20Bot-5865F2?logo=discord&logoColor=white" alt="Invite Lucky" /></a>
<a href="https://lucky.lucassantana.tech/invite?utm_source=github&utm_medium=readme&utm_campaign=readme-badge"><img src="https://img.shields.io/badge/Invite-Lucky%20Bot-5865F2?logo=discord&logoColor=white" alt="Invite Lucky" /></a>
<a href="https://nodejs.org/"><img src="https://img.shields.io/badge/Node.js-22.x-green.svg" alt="Node.js" /></a>
<a href="https://www.typescriptlang.org/"><img src="https://img.shields.io/badge/TypeScript-5.9-blue.svg" alt="TypeScript" /></a>
<a href="https://discord.js.org/"><img src="https://img.shields.io/badge/Discord.js-14-purple.svg" alt="Discord.js" /></a>
Expand All @@ -33,7 +33,7 @@

Lucky is a production-grade Discord bot built as a TypeScript monorepo. Music player with autoplay + recommendations, full moderation suite, auto-mod presets, and a React 19 dashboard — all self-hostable via Docker. Ships with /artist and /album commands for Spotify listening stats, session save/restore, a leveling system with XP and role rewards, and Twitch stream notifications.

**Live at** [lucky.lucassantana.tech](https://lucky.lucassantana.tech) · [Invite to your server](https://discord.com/oauth2/authorize?client_id=962198089161134131&scope=bot%20applications.commands&permissions=36970496)
**Live at** [lucky.lucassantana.tech](https://lucky.lucassantana.tech) · [Invite to your server](https://lucky.lucassantana.tech/invite?utm_source=github&utm_medium=readme&utm_campaign=readme-badge)

---

Expand All @@ -51,13 +51,14 @@ Lucky is a production-grade Discord bot built as a TypeScript monorepo. Music pl

## Why Lucky?

Most Discord music bots are cloud-only black boxes. Lucky is different:
Groovy, Rythm, Hydra — the biggest Discord music bots all died. YouTube API enforcement can kill any cloud-only bot overnight. Lucky can't be shut down because you host it.

- **Self-hostable** — your data, your server, your rules. No dependency on a third-party service staying alive.
- **Shutdown-proof** — self-hosted means no third-party service can take your bot away. Your server, your uptime.
- **Full-stack** — bot + React 19 dashboard in one monorepo. Control music, moderation, and settings from a web interface.
- **Production-grade** — ~2500 tests, zero production incidents, Sentry monitoring, and SonarCloud quality gates.
- **Multi-source** — YouTube + Spotify + SoundCloud, not locked to one provider.
- **Smart autoplay** — personalized recommendations from listening history, not just random tracks.
- **No paywall** — every feature included, free forever. No premium tier, no upsells.

---

Expand Down
Loading
Loading