Release history
Changelog
Every new feature, fix and speed-up on s&box Explorer, newest first.
- Last 30 days
- 90
- Features shipped
- 233
- Fixes
- 218
- Days with changes
- 66
812 changes Clear filters
June 2026
1
-
Refactor
10:35 PM
Cleanup CSS: remove vendor prefixes & modernize
Details
Remove legacy vendor hacks and small CSS cruft across many stylesheets. -webkit-backdrop-filter vendor prefixes and outdated font-smoothing fallbacks were removed, color-mix fallback block replaced with a comment (browsers now support color-mix), and several empty/unused rules and keyframes were pruned. Also modernized some layout declarations to logical properties (inset-block/start, inset-inline/start, margin-inline), replaced negative margin centering with translate, added overflow-x/padding adjustments for pre blocks, and added a line-clamp shorthand. Changes touch numerous frontend/css files to reduce redundancy and rely on modern browser capabilities.
f33ad6e
1
-
Refactor
9:09 PM
Switch s&box API calls to v2 endpoints
Details
Update code to use the s&box public API v2 endpoints (inserted "/2/" and switched list -> find/2 with skip/take). Updated callers include PackageController, StatsController, legacy compatibility routes, package-comparison, RecommendationEngine, and various api helper functions (leaderboard, stats, get, versions). Also added/updated many response schema fixtures under schema/output_schemas and refreshed schema index and docs (llms.txt) to reflect the new endpoints and example payloads.
ab5545d
May 2026
4
-
Maintenance
1:59 PM
Delete .agents directory
afd18bd -
Maintenance
1:38 PM
Production readiness audit and cleanup (#17)
Details
- fix: resolve CSS build error and remove dead/debug files
- Fix stray closing brace in profiles.css that broke PostCSS build
- Remove debug_cache.php and upgrade_gradients.py from project root
- Remove frontend/test-features.php and its route from router.php
- Remove 7 SQLite-based migration/schema scripts from backend/api/
- Add built CSS bundle (frontend/css/dist/bundle.min.css)
- chore: mark FEAT-001 as completed
- refactor: clean up production code quality issues
- Rename STINKY_STEAM_IDS to BLOCKED_STEAM_IDS across all PHP files
- Rename is_stinky user property to is_blocked
- Remove debug output and ?debug=1 handling from frontend/orgnews.php
- Remove console.error calls from frontend/js/main.js search handler
- Remove TEMP comment from phpstan.neon ignore list
- Delete deprecated frontend/api-doc-legacy.php
- Delete frontend/css/pages/api-legacy.css and its @import
- refactor: consolidate duplicate and legacy backend code
- Remove unused backend/controllers/ directory (AdminController, BaseController, PackageController, UserController) - superseded by backend/api/Controllers/
- Add documentation headers to analytics-advanced.php, analytics-advanced2.php, and analytics-advanced3.php clarifying their roles as function libraries required by analytics-api.php
- Add docblock to legacy-rate-limiter.php explaining its purpose for standalone API endpoints not routed through the modern api.php entry point
- fix: remove redundant console statements from frontend JS for production
- chore: final cleanup pass - remove dev .bat files, fix gitignore, harden htaccess
- Remove bundle-css.bat, dev-server.bat, lint.bat (duplicate npm scripts)
- Remove .phpunit.result.cache (test runner cache)
- Add .phpunit.result.cache to .gitignore
- Update index.php maintenance message to be generic
- Add security rules to .htaccess blocking sensitive dirs and dotfiles
- fix: address review findings - rename env var, remove dead code, fix htaccess ordering
- Rename STINKY_STEAM_IDS to BLOCKED_STEAM_IDS in .env.example
- Remove dead $debugInfo array and all assignments from frontend/orgnews.php
- Move directory-blocking RewriteRules before the front-controller catch-all in .htaccess
- chore: complete environment setup - verify deps and build pipeline
- feat: create centralized API utility module and replace all raw fetch() calls
- Create frontend/js/api.js as IIFE exposing window.API with get, post, put, delete, and request methods
- Includes CSRF token injection from meta tag, retry logic with exponential backoff, request deduplication, in-memory GET cache with TTL, AbortController timeout support, and global error toasts
- Add <meta name="csrf-token"> tag in backend/includes/header.php
- Add api.js script tag after toast-manager.js in header.php
- Replace raw fetch() calls across 37 frontend JS files with API module
- Add 'API' to ESLint globals in eslint.config.js
- Preserve existing error handling behavior in all modified files
- chore: mark FEAT-002 as completed
- feat: standardize API responses using apiSuccess/apiError/apiPaginated helpers
Migrate 48 standalone PHP API files to use the centralized api-response-formatter.php helpers instead of raw json_encode().
All responses now follow the standard format: {success: bool, data: ..., error: string|null, meta: {timestamp, api_version}}
- Add require_once for api-response-formatter.php in each file
- Replace raw json_encode success responses with apiSuccess()
- Replace raw json_encode error responses with apiError()
- Ensure proper HTTP status codes (401/403/404/400/500/503)
- Preserve all existing business logic unchanged
- Skip health.php and kofi-webhook.php (special formats)
- 41+ files now use the standardized response helpers
- chore: mark FEAT-003 as completed
- feat: add HTTP caching headers, security hardening, and input sanitization
- Create CacheHeaderMiddleware with publicCache, privateCache, noStore methods
- Add HSTS header and expanded Permissions-Policy to SecurityMiddleware
- Apply Cache-Control: public headers to read-only API endpoints
- Apply Cache-Control: no-store to authenticated/admin API endpoints
- Add CacheHeaderMiddleware to PackageController list/search methods
- Create AuthRateLimitMiddleware (10 req/min) for auth endpoints
- Update CSRFProtection to accept X-CSRF-Token header
- Create InputSanitizer utility class with sanitize methods
- feat: enhanced service worker with API caching, stale-while-revalidate, pre-caching, and background sync
- feat: optimize database queries in CacheManager with LIMIT clauses, indexes, and Redis-only fast path
- feat: add esbuild JS minification, jsAsset helper, defer attributes, and preload hints
- Install esbuild and add tools/build-js.js for individual file minification
- Add js:build and unified build scripts to package.json
- Add jsAsset() helper in helpers.php for environment-aware script paths
- Update header.php with jsAsset() calls and preload hints for critical assets
- Update footer.php script tags to use jsAsset() helper
- Add defer attribute to all external script tags across PHP templates
- Add frontend/js/dist/*.js to .gitignore (build artifacts)
- feat: add structured logging with request ID tracking and client error reporting
- Create Logger class with JSON-formatted output, daily log rotation, and severity filtering
- Add client-errors.php endpoint for frontend error reporting with rate limiting
- Generate UUID v4 request ID per page load in api.js, sent via X-Request-ID header
- Echo X-Request-ID in SecurityMiddleware response headers for correlation
- Add unhandledrejection and error event listeners with debounced reporting (max 5/page)
- Log API requests in api.php with duration tracking
- feat: add asset optimization with fingerprinting, preload hints, and image lazy loading
- Create AssetManager.php with content-hash based cache busting and manifest support
- Create tools/generate-asset-manifest.js for build-time hash manifest generation
- Update js:build script to generate manifest.json after minification
- Replace time()-based cache busting in newspost.php and notifications.php with AssetManager
- Update header.php preload hints to use AssetManager::preloadTag()
- Add loading=lazy to images in compare.php, newspost.php, latest-news.php, skins-item.php
- Add manifest.json and generate-asset-manifest.js to .gitignore rules
- feat: add unit tests for frontend API module and backend classes
- tests/api.test.js: 10 Vitest tests for window.API (headers, CSRF, retry, deduplication, caching, abort, error toast, request body)
- tests/Unit/LoggerTest.php: 4 Pest tests for Logger class
- tests/Unit/InputSanitizerTest.php: 6 Pest tests for InputSanitizer
- tests/Unit/AssetManagerTest.php: 4 Pest tests for AssetManager
- tests/Unit/CacheHeaderMiddlewareTest.php: 5 Pest tests for middleware
- Install jsdom devDependency for Vitest browser environment
- Update vitest.config.js to use jsdom environment
- fix: address code review security and reliability issues
- Replace mt_rand with random_bytes for UUID v4 generation in Logger
- Add data: and vbscript: scheme rejection to InputSanitizer::sanitizeUrl
- Fix service worker pre-cache path mismatch by adding dist paths and stripping query params when matching static assets in cache
- Add missing exit statements after apiError calls in profile-layout.php, settings.php, announcement-api.php, and featured-badges.php
- Remove exception details leak in settings.php delete-account error path
- Complete migration from errorHandler.fetchWithRetry to API.get/post in cache-management.js and advanced-search.js
- fix: remove preload tags with mismatched versioned URLs
The preload tags in header.php used AssetManager::asset() which generates content-hash versioned URLs, but the actual resource loads used different versioning strategies:
- CSS bundle: loaded via filemtime() in head.php (different version string)
- main.js: loaded with bare path (no version) in body-scripts.php
- api.js: loaded via jsAsset() which may resolve to a different path (frontend/js/dist/) or compute a different hash than the manifest
This caused browser console warnings: 'was preloaded but not used' because the browser couldn't match the preloaded URL to the actual request URL.
- fix: resolve admin panel JS errors from defer loading and response wrapping
- Remove 'defer' from admin.js script tag in admin-layout.php so utility functions (formatNumber, debounce, escapeHtml, formatBytes, formatTimeAgo) and the fetch monkey-patch for CSRF tokens are available before inline scripts execute. Fixes 403 Forbidden on POST requests, ReferenceError for debounce in log-viewer, and ReferenceError for formatNumber in analytics.
- Fix sendResponse() in admin-tools-api.php to output JSON directly instead of double-wrapping through apiSuccess(). The function was passing already- structured data (with 'success', 'metrics', etc.) into apiSuccess() which wrapped it again as {success: true, data: {success: true, metrics: {...}}}. Admin pages expect the flat structure at the top level.
- Unwrap .data property in analytics-advanced.php fetch calls for realtime, predictions, behavior, and comparison endpoints that use apiSuccess() wrapper, using 'json.data || json' for backwards compatibility.
- Unwrap .data property in analytics.php fetchSection() for the same reason.
- fix: improve analytics behavior layout and add null checks in sync-reputation
- Wrap Churn Analysis and Lifetime Value cards in a 2-column grid container in renderBehavior(), keeping User Segmentation full-width
- Fix undefined churn.at_risk_rate reference by calculating inline
- Add null/error checks for fetchPlayerData, fetchUserPackages, getUserClaimedOrgs in sync-reputation to prevent 500 errors
- Add explicit int casts for player data fields
- Improve error message in catch block with steam ID context
- fix: redesign User Behavior tab to multi-column dashboard layout
Replace single-column stacking layout with proper multi-column dashboard:
- Top row: 4 segment cards in fixed repeat(4, 1fr) grid
- Middle row: Churn Analysis and Lifetime Value side-by-side (1fr 1fr)
- Bottom row: Full-width Overall Health summary with 4 key metrics
- Use flexbox (flex: 1) inside cards for robust internal layouts
- Remove redundant segment bar visualization
- Use formatNumber() for numeric display
- Normalize line endings to LF per .editorconfig
- chore: add batch files for linting, building, and dev server
- fix: add cd to project root in bat files for correct path resolution
- fix: language switching now writes to user_settings table and returns redirect URL
Problem 1: The /set-language route wrote to the users table but i18n read the preference from user_settings. Now writes to both tables with an UPSERT on user_settings as the primary store.
Problem 2: The API returned no redirect URL, causing the page to reload without a language prefix. Now computes and returns the correct language-prefixed redirect path.
Also adds validation against available languages to reject unsupported language codes.
- fix: use fetch() instead of API wrapper in i18n-client to avoid load order dependency
---------
eb28097 -
Maintenance
8:20 AM
Delete .agents/tasks directory
37c160c -
Feature
8:20 AM
Add Streamable HTTP (SSE) transport support (#16)
Details
- feat(mcp): add Streamable HTTP (SSE) transport support
- Add McpStreamResponse class for SSE event streaming
- Upgrade McpResponse with dual-mode output (JSON or SSE)
- Detect Accept: text/event-stream and stream for eligible tools
- Add per-file progress notifications to sbox_analyse
- Add fetch/search progress notifications to sbox_docs
- Advertise 'logging' capability in initialize response
- Bump server version to 2.2.0
- Fully backward-compatible: non-SSE clients unchanged
- docs(mcp): add Streamable HTTP (SSE) section to browser landing page
Explains how SSE streaming works, that it's automatic for modern clients, shows an example response for custom client developers, and notes backward compatibility.
- fix(mcp): SSE detection via X-MCP-Stream header opt-in
IDEs like Kiro/Cursor don't send Accept: text/event-stream. Instead of guessing, use explicit opt-in:
- Accept: text/event-stream (spec-compliant clients)
- X-MCP-Stream: true header (IDEs that support custom headers)
Without either signal, plain JSON is returned (safe default). Updated landing page docs to show how to enable streaming.
- feat(mcp): add prompts, completion, batch requests, and logging
New MCP protocol features:
1. prompts/list + prompts/get — 6 pre-built prompt templates:
- review_sbox_code: Performance/networking code review
- explain_component: Deep-dive on any s&box type
- network_this: Multiplayer networking plan for a feature
- scaffold_component: Generate full component from description
- debug_issue: Troubleshoot errors with KB/docs context
- whats_new: Latest KB entries and trending topics
2. completion/complete — Auto-completion hints for:
- All tool arguments (actions, categories, tags, slugs)
- All prompt arguments (component names, focus areas)
- Live slug completion from KB search
3. Batch requests — POST an array of JSON-RPC requests:
- Safe methods processed in one round-trip
- tools/call excluded from batch (requires streaming/auth)
4. logging/setLevel — Accepts client log level preference
5. Bumps server to v2.3.0, advertises prompts + completions capabilities in initialize response.
6. prompts/list and completion/complete are public methods (no auth required, like tools/list).
- fix(mcp): disable Apache/PHP-FPM buffering for SSE support
The server has no nginx (Apache 2.4.67 + PHP-FPM directly). SSE wasn't working because: 1. mod_deflate/mod_brotli buffer entire response for compression 2. PHP-FPM output_buffering holds output until script ends
Fixes:
- Root .htaccess: Exclude /mcp/ from gzip/brotli compression
- mcp/.htaccess: Disable output filters for the endpoint
- mcp/.user.ini: Disable PHP output_buffering and enable implicit_flush (read by PHP-FPM per-directory)
- fix(mcp): accept int|string request IDs in SSE stream
JSON-RPC id can be integer or string. The begin() method was typed as ?string but clients send integer IDs (e.g. id: 1). Changed to mixed to accept both.
- feat(mcp): enable SSE streaming for all tools
All 6 tools now respond via SSE when the client opts in. Fast tools (sbox_stats, sbox_contribute) just send the final result as a single SSE event. No behavior change for tools that already had progress notifications (analyse, docs, kb).
- docs: add continuation prompt for next MCP feature session
- feat(mcp): add scaffold, diagnose, changelog tools + semantic search, voting, code validation, context support
New tools:
- sbox_scaffold: Generate boilerplate C# for 8 template types (component, networked_component, game_resource, panel, game_mode, player_controller, npc, service)
- sbox_diagnose: Static analysis for s&box C# code — networking, lifecycle, performance, security, and common gotchas
- sbox_changelog: View recent KB activity (new entries, updates, contributions, summary)
New services:
- SemanticSearch: pgvector cosine similarity → pg_trgm fallback → fulltext search. Degrades gracefully on shared hosting without pgvector.
- VotingService: Upvote/downvote system with quality score integration. Auto-creates mcp_knowledge_votes table. One vote per user per entry.
- CodeValidator: Inline C# code validation in sbox_contribute — checks structure, naming, s&box API usage, and common mistakes.
- ContextService: Processes _context parameter across all tools for context-aware search enhancement, result ranking, and suggestions.
Updated tools:
- sbox_kb: Added semantic_search and vote actions, integrated ContextService for smarter search results
- sbox_contribute: Added CodeValidator checks before submission (blocks on errors, surfaces warnings)
Infrastructure:
- Bumped server version to 2.4.0
- Added completions for all new tools in McpCompletion
- All new services auto-create DB schemas on first use
- Full SSE streaming support in new tools
- fix(mcp): resolve audit failures — path resolution, class name, timeout, N+1 detection
- Fix require_once path in SemanticSearch.php, VotingService.php, and AdminService.php: use '/../../../backend/' (3 levels up from mcp/lib/services/) instead of '/../../backend/' (2 levels)
- Fix AdminService.php referencing non-existent 'QualityScorer' class — corrected to 'McpQualityScorer' (2 call sites)
- Rewrite changelog_summary to consolidate queries (4→3), wrap in try/catch for graceful timeout handling, fix array_sum on potential non-array from FETCH_KEY_PAIR
- Enhance diagnose_performance with N+1 loop detection: tracks foreach/for/while brace depth via loopStack and flags Scene.Trace, Components.Get, Clone/Instantiate, and RPC/Broadcast inside loops
- fix(mcp): resolve second audit round — N+1 detection, audit_logs, constructor checks, security
Diagnose tool:
- Fix loop depth tracking: start at 0 (not brace count on foreach line) so loops with opening brace on next line are correctly tracked
- Add iteration-pattern detection (GetAllObjects, GetAllComponents, etc.) to catch N+1 even when combined with foreach on the same line
- Broaden constructor detection regex to match any non-void/non-static method-like pattern without 'override', catching more constructor forms
- Add Components.Get detection in constructors (not just Transform/GO)
- Add HTTP exfiltration checks: HttpClient/WebRequest near user data, string interpolation of SteamId/PlayerId into URLs
Admin tool:
- Fix audit_logs handler: extract logs from AdminService wrapper result (was iterating the wrapper dict, causing 'array offset on true')
- Map correct DB column names (created_at not timestamp, target_id not entry_id, details.reason not top-level reason)
Contribute tool:
- Normalize literal '\n' escape sequences to real newlines before code block detection (fixes rejection when clients send escaped strings)
- refactor(mcp): rename sbox_changelog → sbox_updates, add browser UI examples for new tools
- Rename sbox_changelog to sbox_updates to avoid confusion with the official s&box game changelog. Description now explicitly states this tracks knowledge added to this MCP server, not Facepunch releases.
- No legacy alias needed (tool not yet public).
- Add entries for sbox_scaffold, sbox_diagnose, sbox_updates so they appear with clickable example JSON on the /mcp/ browser page.
- Add all 3 new tools to mapping (scaffold+diagnose → docs, updates → kb).
- Update Completion.php: rename completeChangelog → completeUpdates, match on 'sbox_updates' instead of 'sbox_changelog'.
- feat(mcp): add unified search tool, analyse+diagnose alignment, and Discord webhook notifications
New tool:
- sbox_search: Unified search across KB + official docs + API schema in one call. Merged ranked results with source icons, context boosting, and per-source filtering. Registered in index.php with browser example.
Improvements:
- AnalyseService now runs diagnose_performance, diagnose_lifecycle, diagnose_security, and diagnose_sbox_gotchas on each C# file during project analysis. Results are severity-mapped and merged into the health score. Fixes the 'sbox_analyse missed N+1' audit finding.
Discord webhook notifications for MCP events:
- New McpWebhookService (backend/includes/McpWebhookService.php) sends rich Discord embeds for: contribution submitted, approved, rejected, entry updated, entry deleted.
- Admin panel (admin/webhook-settings.php) extended with MCP section: separate webhook URL, enable toggle, 5 event checkboxes, test button.
- Settings stored in existing webhook_settings table with mcp_* prefix.
- Webhook calls wired into contribute.php, kb.php (update), and AdminService (approve/reject/delete). All wrapped in try/catch — webhook failures never block the primary action.
- Notifications logged to webhook_sent_notifications for history.
- refactor(admin): overhaul webhook-settings UI with tabs, action-grid, and data-table
- Add 3-tab navigation: Package Webhooks, MCP Webhooks, Notification History
- Convert actions section to action-grid with individual cards
- Convert notification log from custom divs to data-table
- Remove all inline style attributes and the style block
- Add switchTab() JavaScript function
- All 7 POST form actions preserved unchanged
- Backend PHP logic completely untouched
- chore: mark FEAT-001 webhook-settings-overhaul as completed
- fix(admin): use data-tab attributes and URL hash for tab persistence
- Replace brittle onclick-based tab selector with data-tab attributes
- Add URL hash persistence so tab state survives page reload
- Read hash on DOMContentLoaded to restore active tab
- Update MCP action redirects to use #mcp hash
- Update clear_notifications redirect to use #history hash
- feat: create MCP Tools documentation page at /mcp-tools
- Add /frontend/mcp-tools.php with full documentation for all 11 MCP tools
- Document sbox_search, sbox_kb, sbox_docs, sbox_contribute, sbox_diagnose, sbox_analyse, sbox_scaffold, sbox_admin, sbox_updates, sbox_stats, sbox_explain
- Include hero section, quick-start guide, tools overview with expandable cards, usage examples, common workflows, best practices, troubleshooting, and perf tips
- Add route in routing_logic.php for /mcp-tools
- Add /mcp-tools to maintenanceExempt list in index.php
- Use existing .mcp-* CSS design system classes throughout
- Add copy-to-clipboard and expand/collapse JS interactions
- chore: mark FEAT-001 mcp-tools documentation page as completed
- feat: add sbox_package and sbox_explain MCP tools
- sbox_package: search, get, popular, dependencies, health actions
- Uses fetchPackagesBySearch from api_functions.php
- Streaming for search and popular actions
- CacheManager for popular/health results (60s TTL)
- Rich error messages with what/how/related format
- sbox_explain: tools, recommend, workflow, error actions
- Lists all registered tools from ToolRegistry::list()
- Keyword-based intent matching for recommendations
- 5 predefined workflow guides
- Detailed error code explanations from McpToolRegistry::ERROR_CODES
- Registered both in mcp/index.php
- chore: mark FEAT-002 sbox_package and sbox_explain tools as completed
- feat: add sbox_migrate and sbox_refactor MCP tools
- chore: mark FEAT-003 sbox_migrate and sbox_refactor tools as completed
- feat: improve existing MCP tools with new actions, dynamic scoring, and rich errors
- sbox_diagnose: add fix/batch actions, populate fix fields in diagnostics
- sbox_search: replace hardcoded relevance with dynamic scoring, add did_you_mean
- sbox_stats: add kb_health/community/tool_usage actions, increase cache to 60s
- sbox_scaffold: add from_description/test/multi templates
- All tools: rich error messages with what/how/related format
- chore: mark FEAT-004 existing tools improvement as completed
- feat: add streaming progress support to kb, docs, admin, and contribute tools
- chore: mark FEAT-005 streaming progress support as completed
- fix: address review issues in MCP tools (fabricated data labels, fallback warnings, thresholds)
- stats.php: Label estimated values with ~ prefix and (estimated) suffix, add disclaimer when KnowledgeDB methods are unavailable
- package.php: Warn when falling back to non-exact match in package_get(), include actual ident of returned package for verification
- search.php: Tighten did_you_mean threshold from max(3, len*0.6) to max(2, len*0.4) for better suggestion quality
- migrate.php: Add note about lines with multiple deprecated patterns needing multiple passes
- feat: add tool cards for sbox_package, sbox_explain, sbox_migrate, sbox_refactor to MCP tools page
- Add sbox_package to Search & Discovery group with actions, params, examples
- Replace sbox_explain Coming Soon placeholder with full tool card in Search & Discovery
- Add new Code Transformation group with sbox_migrate and sbox_refactor
- Remove sbox_explain from Administration group
- Update hero stats from 11 to 15 tools, 50+ to 60+ actions
- Update group counts: Search & Discovery 5, Administration 1, Code Transformation 2
- refactor: replace Available tools section with compact CTA linking to /mcp-tools
- Removed all PHP tool-card rendering logic (, , arrays and foreach loops)
- Added compact stats grid (15 tools, 60+ actions, 5 categories, SSE streaming)
- Added 'View Full Tools Documentation' button linking to /mcp-tools
- Added 'Tools Reference' button in hero buttons area linking to /mcp-tools
- feat: hide Administration tool group on mcp-tools page for non-admin users
- feat: add /mcp-tools route to router.php
- refactor: rewrite router.php with clean table-driven routing patterns
- chore: remove excessive comments and separator lines from router and MCP tool files
- fix: remove debug error_log from production routing_logic.php
- feat: add MCP Resources support with registry and 7 registered resources
- chore: mark FEAT-001 as completed
- feat: add 4 new MCP prompts and enhance kb vote/feedback actions
- Add project_review, multiplayer_setup, performance_audit, migrate_code prompts
- Add optional reason field to sbox_kb vote action with logging
- Add new feedback action to sbox_kb with helpful/not_helpful signals
- chore: mark FEAT-002 as completed
- feat: add sbox://project/context resource and project_setup action to sbox_explain
- chore: mark FEAT-003 as completed
- feat: add IDE Integration Guides section with tabbed setup for Cursor, Continue, Claude Desktop, Windsurf, and Generic
- chore: mark FEAT-004 as completed
- fix: handle null type in resource handler and differentiate feedback from vote
- Return empty contents array when ApiSchemaService::getType() returns null instead of returning "null" as text content
- Make kb_handleFeedback() semantically distinct from kb_handleVote():
- Always log with [AI feedback] context marker (not just when reason given)
- Include entry title in the feedback log when available
- Return response message clearly identifying as AI quality feedback
- fix: resolve 6 MCP tool audit issues
- admin: add explicit 'approve' and 'reject' action cases that route to the moderation approval/rejection logic
- contribute: return the actual mcp_knowledge entry ID (not the mcp_contributions ID) when auto-approving trusted submissions
- stats: replace placeholder tool_usage output with actual tool listing showing all available tools and their actions
- diagnose fix: when issue line is 0, prepend the fix instead of silently returning unchanged code
- diagnose batch: add public field detection to diagnose_sbox_gotchas so batch and single-file modes both catch this pattern
- admin audit_logs: fix KnowledgeDB::getAuditLogs to properly bind the LIMIT parameter and decode JSON details column
---------
abd8b26
1
-
Feature
9:13 AM
Add May 2026 chart history JSON files
Details
Add daily chart history data files for game (2026-05-04 to 2026-05-26) and map (2026-05-05 to 2026-05-27). Each JSON contains daily rankings with title, org, user counts and favorites for use in analytics/leaderboards.
e4ffa76
2
-
Feature
4:40 AM
Major platform refactor, Steam profile expansion, and MCP tooling enhancements
Details
Large-scale refactor and feature expansion across frontend, backend, API, schema, documentation, and MCP systems focused on improving maintainability, developer tooling, performance, and overall platform stability.
Frontend & UI:
- Reworked and cleaned CSS across multiple components
- Improved shared frontend architecture and reusable layouts
- Refined package sections and overall interface presentation
- Applied broad UI polish and styling consistency improvements
- Updated packages.css and related styling assets
- Improved settings pages and related components
- Refined user profile redesign elements
- Updated usage stats and global stats pages
- Refactored profile CSS/markup and removed duplicate styling rules
- Improved profile layout spacing, grids, and section structure
- Cleaned favorite games UI and condensed playtime display logic
- Fixed minor layout and margin inconsistencies
- Added Steam inventory UI with new card-based layout system
- Added inventory section rendering and fallback handling
Backend, API & Schema:
- Refactored API functions and related integrations
- Cleaned and updated schema systems
- Improved overall code organization and maintainability
- Added ApiSchemaService for schema fetching, caching, indexing, and search support
- Added schema chunking and improved type formatting and handling
- Improved API validation and detection of obsolete structures
Analysis & Developer Tooling:
- Added and enhanced AnalyseService for static project analysis
- Improved C#, UI, styles, and asset scanning capabilities
- Introduced structured optimization reports with severity scoring and suggestions
- Added autofix suggestions and richer issue payload output
- Integrated ApiSchemaService into analysis pipeline
- Added chunked/session-based analysis with merge and cleanup support
- Introduced audit.md report generation workflow
- Registered and refined sbox_analyse MCP tool integration
Documentation System:
- Expanded DocsService capabilities and tooling
- Added chunked documentation page fetching
- Improved documentation searching, categorisation, and snippet generation
- Improved caching layers and sanitisation handling
- Updated external request user-agent handling
Database & Knowledge Systems:
- Improved KnowledgeDB duplicate detection logic
- Added pg_trgm similarity support with safe fallback handling
- Reduced noisy error output when extensions are unavailable
MCP & Platform Services:
- Improved MCP client detection and capability negotiation
- Updated mcp/index.php with improved tool registration and UI examples
- Bumped MCP server version to v2.1.0
- Added demo analysis tool entry point
- Improved memory and upload limit handling
- Tightened .htaccess constraints for MCP stability
Steam Integration & Profile Systems:
- Added Steam inventory fetching via SteamIntegrationManager
- Implemented caching and merging improvements for Steam friend and presence data
- Added multi-cURL based Steam store image fetching (capsule/header assets)
- Enhanced Steam game data enrichment with public app ID filtering
- Improved Steam API caching, error handling, and data consistency
- Expanded profile UI to support Steam inventory display
- Added richer game media rendering on profiles (images, capsules, metadata)
Account System:
- Fixed account deletion related issues
- Added support for fully deleting all user account data
- Improved related account management flows
Organization System:
- Added and refined organization-related functionality
- Improved organization management systems and moderation flows
- Applied frontend and backend improvements for organization features
Misc:
- General project cleanup and polish
- Internal checkpoints and development progress saves
- Performance improvements, caching enhancements, and stability fixes across systems
934caf9 -
Performance
4:36 AM
Improve UX, accessibility, and code quality for 4 pages (#15)
Details
- Improve UX, accessibility, and code quality for news, charts, and global-stats pages
- /news: Add reading progress bar, skeleton loading, grid/list view toggle, scroll-to-top button, keyboard navigation (J/K), article count display, better ARIA attributes, rel=noopener on external links, proper time elements
- /orgnews: Add server-side search, client-side sorting (newest/A-Z), relative time display, 'New' badge on recent articles, better ARIA labels, preserve search params in pagination links
- /ugc/charts/game: Add live player count summary with pulsing indicator, refresh button, section item counts, staggered card animations, IntersectionObserver for sections, keyboard navigation, focus-visible styles, reduced motion support, improved empty state with alternative link
- /global-stats: Extract ~250 lines of inline styles to dedicated CSS file (frontend/css/pages/global-stats.css), add ARIA roles/labels/live regions, aria-pressed on tag buttons, aria-checked on range buttons, hover transitions on metric cards, focus-visible on game cards, reduced motion support
- Improve accessibility and fix structural issues in frontend PHP pages
- changelog.php: Remove duplicate theme-manager.js script, remove extra </div></div> tags, move </main> before scripts/footer, add role/aria-label to main, add aria-current to active pagination and filter buttons, wrap pagination controls in nav with aria-label
- about.php: Add role/aria-label to main, add aria-hidden to decorative icons, add noreferrer to external links
- credits.php: Add role/aria-label to main, add aria-hidden to decorative icons, remove stray </div>, add noreferrer to external links
- donate.php: Add role/aria-label to main, add aria-hidden to decorative icons
- new-user-guide.php: Add role/aria-label to main, add aria-hidden to hero icon
- release-notes.php: Add role/aria-label to main, add aria-hidden to decorative icons, add rel=noopener noreferrer to sbox.game link, remove stray </div>
- Improve accessibility and UX across all remaining frontend pages
Pages improved:
- compare.php: Extract inline CSS to external file, add ARIA roles/labels, focus-visible styles, prefers-reduced-motion support
- search.php: FIX CRITICAL BUG - broken <style> tag that included footer inside it. Scripts moved to bottom, added role=search, aria-labels
- leaderboard.php: Add aria-pressed on filter buttons, role=list/listitem in JS rendering, aria-live=polite on container
- favorites.php: Change div to semantic main element, add role=list/listitem, aria-live=polite, aria-hidden on decorative icons
- followed.php: Same accessibility pattern as favorites
- notifications.php: Add role=main, aria-live on container, aria-labels on mark-all-read and remove-all buttons
- settings.php: Add role=main, aria-label on main and form elements
- settings-language.php: Add role=main, aria-current=page on active nav, role=radiogroup on language grid
- notifications-following.php: Add role=main, aria-hidden on decorative icons, role=list/listitem on grid items
- CSS overhaul: extract inline styles and modernize page stylesheets
- notifications-following.php: Extract ~250 lines of inline CSS to frontend/css/pages/notifications-following.css (following grid, cards, badges, empty state, unfollow buttons, responsive)
- settings-language.php: Extract ~150 lines of inline CSS to frontend/css/pages/settings-language.css (settings layout, sidebar, language cards, responsive)
- compare.css: Add card entrance animation (fadeInScale with stagger), stat value hover effect, button active click feedback
- global-stats.css: Add card entrance states for IntersectionObserver, focus-visible on hero, update reduced-motion block
- charts.css: Verified existing focus-visible, reduced-motion, and responsive styles are all present
- Replace ugly #04131c header color with #0c1222 (matches navy palette)
The old #04131c had a greenish undertone that clashed with the blue-navy palette (--bg-primary: #080f1f, --bg-secondary: #181f2f). Replaced with #0c1222 which sits naturally between the two and keeps the header visually distinct without looking out of place.
- Align CSS variables with sbox.game official theme
Synced root variables to match the sbox.game design system:
- --site-header-height: 56px -> 60px (matches official)
- --site-header-color: kept #0c1222 (improved over official #04131c)
- --text-secondary: #b8c0d9 -> #adb3cb (official --text-color)
- --text-muted: #8892a8 -> #b2bed4 (official)
- --link: now uses color-mix formula from sbox.game
- --link-hover: now var(--accent-bright) instead of #fff
- font-size: 14px -> 13px (matches official)
- body background: now uses var(--site-background-color) semantically
- Added --admin/#c4214f, --admin-alt, --text-on-strong
- Added --form-surface, --form-divider, --form-label-color
- Added --column-gap: 0.75rem
- Added sbox.game menu color variables (--menu-option-color, etc)
- CSS audit: remove dead vendor prefixes, migrate z-index to variables, tokenize colors
Dead code removal:
- Remove 10 deprecated -webkit-overflow-scrolling: touch declarations
- Remove 1 -ms-overflow-style: none (IE is dead)
Z-index migration (156 hardcoded -> variables):
- Expand z-index scale: add --z-below, --z-raised, --z-header, --z-popover, --z-loading, --z-command-palette
- Replace ALL 156 hardcoded z-index values with var(--z-*) tokens
- Only z-index: 0 (stacking context resets) left as literals
Color tokenization:
- Add --purple (#8b5cf6) and --purple-light (#a78bfa) to design system
- Replace 33 #4ade80 -> var(--success-light)
- Replace 19 #22c55e/#10b981 -> var(--success)
- Replace 29 #ef4444 -> var(--error)
- Replace 14 #f87171 -> var(--error-light)
- Replace 18 #f59e0b/#fbbf24 -> var(--warning)
- Replace 11 #3498db -> var(--info)
- Replace 11 #8b5cf6 -> var(--purple)
- Replace #a78bfa -> var(--purple-light)
- Fix toast.css to use design system variables for success/error/warning
- Update base.css
- Fix TypeError: navigator.clipboard.writeText on undefined in package-detail-sections.php
Added fallback using document.execCommand('copy') for browsers/contexts where navigator.clipboard is unavailable (e.g., non-HTTPS or older browsers).
- Security, performance, and code quality improvements
Security:
- Fix navigator.clipboard TypeError in mcp-knowledge.js (2), settings.js (1) with document.execCommand fallback for non-HTTPS/older browsers
- Restrict CORS on settings API from wildcard to same-origin only
- Add CSRF token validation to admin-tools-api.php POST requests with auto-injection via admin.js fetch wrapper and token rotation
- Add Content-Security-Policy and Permissions-Policy headers to SecurityMiddleware.php (whitelists required CDNs, blocks frame/object)
- Stop leaking exception messages in search-api.php error responses
Performance:
- Rewrite notification-bell.js: 30s polling (was 10s), 2min when hidden, exponential backoff on errors, beforeunload cleanup
- Add try/catch guards for localStorage in command-palette.js (prevents crashes in private browsing mode)
Code quality:
- Extract admin/index.php inline styles to admin-dashboard.css (BEM classes)
- Consolidate duplicate .text-gradient/.gradient-text in design-system.css
- Remove excessive error_log() calls from settings.php
- Strip all code comments from PHP, JS, and CSS files
Removed all inline (//) and block (/* */) comments across the entire codebase (578 files scanned, 261 modified):
- 175 PHP files: stripped via PHP tokenizer (safe with strings/heredocs)
- 63 JS files: stripped via terser with beautified output
- 70 CSS files: stripped via regex (/* */ only, no string ambiguity)
- 16 PHP files: additional pass for comments inside <script>/<style> blocks
Only functional code remains. String literals containing // or /* (URLs, regex patterns, programmatic comment builders) are preserved correctly.
- Collapse excessive blank lines left by comment removal
Reduces 2+ consecutive blank lines to a single blank line across all 426 source files. Removes trailing whitespace and leading blank lines after <?php tags.
- Lint all PHP files with php-cs-fixer (PSR-12 + PHP 8.2+)
Ran php-cs-fixer v3.95.2 across all 390 PHP files (321 modified). Applied rules include:
- PSR-12 formatting (indentation, braces, spacing)
- PHP 8.2 migration (modern syntax, typed properties)
- PHP 8.0 risky rules (arrow functions, named args, match)
- Strict comparisons and strict params
- Ordered imports (alpha, class/function/const groups)
- Trailing commas in multiline arrays/args/params
- Yoda-style disabled (natural reading order)
- Void return types added where applicable
- Ternary to null coalescing where possible
Also expanded .php-cs-fixer.dist.php finder to cover admin/, auth/, mcp/, tests/, and tools/ directories (previously only backend/, frontend/, includes/, config/).
- feat: implement Facepunch API features - hidden gems, browse filters, tag cloud, game modes, achievement rarity, review playtime, enhanced cards
- Add /hidden-gems page with sort:hiddengem discovery grid
- Add browse-api.php endpoint with full sort/filter support
- Add browse-sort-orders.js with all API sort orders
- Add browse-filters.php faceted sidebar (genre, style, stars, size, review tags)
- Add tag-cloud.php weighted tag cloud partial
- Add game-mode-badges.php with SinglePlayer/MultiPlayer/Coop/Versus badges
- Add achievement rarity tiers (Common/Uncommon/Rare/Epic/Legendary)
- Add review-playtime.php horizontal bar chart visualization
- Add package-card-enhanced.php with ThumbWide, FileSize, dates, WIP/player badges
- Add getGameModeBadges(), formatFileSize(), formatRelativeDate() helpers
- Fix 400 errors and integrate new features into UI
Fixes:
- Fix 400 Bad Request on /api.php/packages/search calls from homepage-categories.js loadSubFilters() — was missing required 'q' param. Now uses type-specific endpoint /packages/{type} instead.
Navigation:
- Add Hidden Gems link (diamond icon) to main site navigation
UI Integration:
- Hidden Gems page: add browse filters sidebar with sticky layout, enhanced cards showing ThumbWide, live player badge, FileSize, dates
- Search page: add tag cloud (fetches live tag counts from API) shown when no search query is active
- Package detail sidebar: add game mode badges (SinglePlayer, Multiplayer, Co-op, Versus) before tags section
- CSS: import browse-filters.css and hidden-gems.css in styles.css
- Fix category+tag filtering and hidden gems filters
Homepage categories:
- Fix PackageController to use skip/take params (Facepunch API format) instead of page/count (which Facepunch ignores entirely)
- Increase FETCH_TIMEOUT from 2s to 8s to avoid aborting requests that need a fresh API call (cache miss → 3-5s roundtrip to Facepunch)
- Tag sub-filters now work: clicking Maps → Rats fetches 'rats type:map' which returns relevant results via free-text search
Hidden Gems filters:
- Wire browse-filters.php to hidden-gems.php: genres, style, stars, size, and reviewtag params are now read from URL and passed to API query
- Map filter values to Facepunch API facet format: disksize:1-9, pos:bitmask, stars:1-5, genre:name, style:2d/3d
- Fix TotalCount key (was 'Total', API returns 'TotalCount')
- Cache key now includes filter state (was only page number)
Browse filters partial:
- Fix size filter values: use API disksize numbers (1-9) not text keys
- Fix reviewtag values: use API pos: bitmask values (4, 512, 256, etc.) mapped to human labels (Gameplay, Replayability, Addictive, etc.)
- Convert homepage category nav to stats-only links
The category nav on the homepage never worked for filtering — the JS tried to update a #packagesGrid element that only exists in the browse layout (else branch), not in the homepage layout (if branch). Every call to fetchAndRender hit 'if (!grid) return' immediately.
Changes:
- Convert category nav buttons to links pointing to /t/{type}/ browse pages (where server-side rendering actually works)
- Remove initCategories() JS import from homepage (no longer needed)
- Remove broken sub-filters panel (tags like 'rats' never rendered)
- Add text-decoration:none for link-based nav items
- Categories with 0 count are now hidden instead of disabled
- Fix /t/game/ showing homepage instead of filtered results, fix hidden gems filters
/t/{type}/ route:
- Set $filterType = $tagType in routing_logic.php so package-list.php renders the browse layout instead of the homepage layout. Previously $filterType was unset, so $isHomepage evaluated to true and showed the full homepage instead of filtered packages.
Hidden gems filters:
- Always show the filter sidebar (was inside if-packages-exist check, meaning filters disappeared when a filter produced 0 results)
- Handle comma-separated genres (only use first value since API only supports one genre: filter at a time)
- Fix empty state message to suggest adjusting filters
- Improve /t/{type}/ browse page: show active type, fix nav links
- Header now shows 'Browse Games', 'Browse Maps', etc. instead of generic 'Browse Packages' when viewing a specific type
- Type filter nav correctly highlights the active type (uses $filterType from routing instead of $_GET['type'] which is empty on /t/ routes)
- Filter links now use /t/{type}/ URLs (proper route) instead of /?type= query params (which triggered homepage rendering)
- Fix /t/{type}/ dumping all packages without pagination
The tag listing route was calling fetchPackagesByTypeAndTag() which fetches up to 2000 packages (10 pages × 200) in bulk with no pagination.
Now uses the same paginated approach as the main browse: calls fetchPackagesByType() with proper page/perPage params (25 per page), calculates pagination data, and renders page controls.
When a tag sub-filter is active (?tags=rats), uses fetchPackagesBySearch() with the tag as free-text combined with the type filter.
- Clarify Hidden Gems is powered by Facepunch API, not hand-picked
Add subtitle text making it clear the page uses Facepunch's built-in 'Hidden Gems' algorithm (sort:hiddengem) rather than being manually curated by the site owner.
- Fix hidden gems filters not responding to clicks
The browse-filters.php partial included an inline script that wrapped all event listeners in DOMContentLoaded. But since the partial is included mid-page (inside main), DOMContentLoaded has already fired by the time the browser parses the script so the callback never executed and no click handlers were ever attached.
Fix: Use readyState check pattern - if DOM is already loaded, run initFilters() immediately; otherwise attach to DOMContentLoaded. This ensures filters work regardless of when the partial is included in the document.
- feat: add org social links, type-specific filters, video preview, profile stats, browse filter sidebar, referenced packages count
- Task 1: Org social links (Twitter, Website, Discord) on package detail sidebar
- Task 2: Type-specific browse filters for game/map/library types
- Task 3: Video preview section on package detail page
- Task 4: TotalReviews and PositiveReviews stats on player profile
- Task 5: Browse filter sidebar integration for /t/game/ and /t/map/ pages
- Task 6: Referenced by X packages indicator in usage stats
- Use proper Material Symbols for social links and fix Twitter URL
- Twitter: alternate_email icon (@ symbol) + auto-convert @handle to https://x.com/handle URL
- Website: language icon (globe - unchanged)
- Discord: headset_mic icon (recognizable voice chat icon)
Previously used 'flutter' (not a real Material Symbol) for Twitter and 'forum' for Discord which were generic/incorrect.
- Use Font Awesome brand icons for social links (Twitter/X, Discord)
Google Material Symbols don't have Twitter/X or Discord icons. Switch to Font Awesome 6 Brands which is already loaded via CDN on profile pages — now also loaded on package detail pages.
- Twitter/X: fa-brands fa-x-twitter (official X logo)
- Discord: fa-brands fa-discord (official Discord logo)
- Website: keeps Material Symbols 'language' (globe icon)
Font Awesome CDN link now conditionally loaded on package detail pages (was previously only on user/org profile pages).
---------
e2ce930
2
-
Feature
9:51 PM
Implement unused API data fields across the application (#14)
Details
- feat: implement unused API data fields across the application
- Add ReviewStats rating distribution histogram on package detail page (new section showing star breakdown like Steam/Google Play)
- Add Org social links (Twitter, Discord, WebUrl) on org page with org description display
- Add 'Latest Update' callout using Version.Changes from package/get (shows changelog snippet without extra API call)
- Use ThumbWide as preferred hero banner image on package detail
- Add ThumbWide srcset to package grid cards for responsive loading
- Re-enable Version info block in package-details.php (was disabled)
- Add FileSize and API Version from /status endpoint to footer
- Add Author.Online indicator (green dot) on news posts
- Add Author.Score badge on news author displays
- Add CSS for all new components (rating bars, social links, callout, online dot, score badge)
- fix: cast EngineVersion to string for htmlspecialchars (PHP 8.4 TypeError)
- refactor: move latest update into version history section, remove duplicates
- Remove standalone latest-update.php callout (was awkward mid-page)
- Integrate 'Latest Update' as a highlighted banner inside Version History
- Remove duplicate Version.Changes from package-details.php
- Replace callout CSS with version-current-banner CSS (themed properly)
- Reduces duplicate info: version data now only shows in Version History and the technical Package Details section
- fix: restyle org description and social links with proper themed component
- Replace inline styles with new .org-about-bar component
- Description + social links now sit in a unified bordered card
- Properly themed with border, backdrop-blur, hover states
- Responsive: stacks and compresses on mobile
- Color-coded hover states for Twitter (blue), Discord (indigo), Website (green)
- feat: improve package detail view UX
- Remove duplicate Organization section (already in sidebar)
- Remove duplicate Summary section (already in header)
- Add VotesDown and Referenced counts to header stats
- Add relative time badge ('Updated 3d ago') to header meta row
- Add quick info pills below header (size, file count, engine version, freshness)
- Add 'Copy ID' button with clipboard feedback animation
- Add expandable description with gradient fade + Show more/less toggle
- CSS: quick info pills, updated badge, copy button, negative stat, expandable description
- fix: move quick info pills into pkg-header instead of floating below
- fix: set pkg-pill border-radius to 4px
---------
1b61ced -
Docs
8:49 PM
Rewrite README to reflect current codebase state
Details
- Update PHP version requirement from 8.1+ to 8.4+
- Document consolidated MCP architecture (5 tools with actions)
- List all 24 available themes (was 7)
- Add testing section (Pest, Vitest, PHPStan)
- Add linting section (ESLint, Stylelint, PHP-CS-Fixer)
- Add build system section (PostCSS pipeline)
- Correct cache TTLs to match config/constants.php
- Expand maintenance tools listing (50+ scripts)
- Document backend API architecture (Controllers, Middleware, etc.)
- Add additional features (command palette, steam presence, etc.)
- Update project structure to include all top-level files
- Add config directory documentation
- Include npm install in setup and deployment steps
9a00d8d
16
-
Style
5:39 PM
Visual & UX overhaul: flat design, navigation redesign, consistency pass (#12)
Details
- feat: overhaul design system foundation - flatten UI, normalize radii, remove glow effects
- Normalize border radii: --radius-md/lg/xl/2xl all set to 4px
- Remove --glow-primary and --glow-secondary CSS variables from :root
- Remove text gradient (background-clip: text) from MCP hero title
- Simplify body background to flat var(--bg-primary) without radial gradients
- Flatten .btn-primary: solid background instead of linear-gradient, no glow shadows
- Flatten .card: solid background, no backdrop-filter or gradient
- Remove .glass, .glass-strong, .glass-card, .shine-effect from design-system
- Remove backdrop-filter from .surface class
- Remove inset box-shadow highlights from .brand-icon
- Update --shadow-primary to use subtle 20% opacity
- Replace glow references in homepage feature CSS with shadow-md
- chore: mark FEAT-001 as completed
- feat: redesign navigation - replace hamburger with Material Symbols, simplify brand, clean styling
- Replace hamburger span lines with Material Symbols menu/menu_open icon
- Remove brand-icon-glow and brand-icon-wrapper from header
- Remove initBrandAnimation() from navigation.js
- Simplify .site-nav (remove ::before gradient line)
- Redesign .nav-container with proper gap and shorter padding
- Simplify .brand-icon to flat 32px square, no glow/gradient/shadow
- Clean .nav-link: no pseudo-elements, simple color/bg transitions
- Redesign .nav-toggle as 36px icon button
- Clean .user-menu-trigger with border and 4px radius
- Remove ::before arrow from .user-dropdown, flat bg-secondary
- Simplify .user-dropdown-item styling
- Mobile menu uses translateX instead of opacity for reveal
- Clean .btn-steam-login: remove shimmer, use border/color transitions
- Remove brand-letter animation CSS from components.css
- Consistent focus-visible: outline 2px solid var(--primary), offset 2px
- chore: mark FEAT-002 as completed
- feat: clean up component styles - remove gradients, excessive transforms, decorative animations
- buttons.css: remove filter:brightness, inset box-shadows, reduce hover translateY from -2px to -1px, use flat backgrounds
- base.css: flatten .card hover (no translateY), simplify .btn-enhanced, update input focus ring to 2px, use border-radius: var(--radius-sm)
- design-system.css: remove .hover-lift translateY, .hover-scale excessive scale, .interactive translateY, .page-hero radial gradients, fix .callout border-radius to 4px
- hero.css: remove ::before/::after radial gradient blurs, hero-title drop-shadow, simplify search-input to solid background
- homepage-hero.css: remove hp-hero__title drop-shadow
- navigation.css: remove pagination ::before gradient overlay, hover translateY, ::after shine animation, will-change, stagger delays, pagination-wrapper decorative line
- layout.css footer: remove footer-shimmer, footer-float, glow-pulse keyframes, shimmer-track, glow-top, brand-icon animation/gradient, social link gradient/excessive transforms, stat-card gradient/transforms, support-link gradient
- chore: mark FEAT-003 as completed
- feat: improve responsive design, typography, accessibility, and replace hard-coded footer colors
- chore: mark FEAT-004 as completed
- fix: replace -webkit-text-fill-color with standard color property in non-theme CSS
- fix: address review findings - reduce hover lifts, remove dead CSS, fix radius inconsistency
- feat: restore footer blue glow ambient effect
- feat: enhance design tokens, depth system, and micro-interactions
- Add --shadow-xs, --shadow-card-hover, --surface-elevated-1/2 tokens
- Add --transition-micro for snappy micro-interaction timing
- Refine .card with surface elevation shadows and border tint on hover
- Improve button hover shadow layering and scale(0.98) active state
- Soften input focus ring to 3px with inset shadow
- Add translateY(-1px) and subtle shadow to .tag hover
- Refine .interactive with explicit transition properties and hover lift
- Improve .hover-lift with translateY(-2px) and ease-out-quart curve
- Add box-shadow depth to .surface and .surface-elevated
- Add .press-feedback utility class for physical button feel
- Enhance .pill hover with translateY and subtle shadow
- chore: mark FEAT-001 as completed
- feat: refine nav, footer, modals, toasts, type-filters, and cards for premium polish
- chore: mark FEAT-002 as completed
- fix: address review findings - remove dead tokens, refine footer glow, fix toast transition
- chore: update task state with review and verification metadata
- fix: correct text color hierarchy - make --text-muted properly dimmer than --text-secondary
- feat: global CSS foundations - spacing tokens, card unification, section rhythm, interactive consistency, selection color
- Add --space-between (0.75rem) and --section-gap tokens to :root
- Add .card-surface foundation class in design-system.css
- Update homepage-layout to use --section-gap for vertical rhythm
- Replace transition: all with enumerated properties in charts.css, api-doc.css, community.css, favorites.css
- Standardize hover lifts to max -2px (except -3px for hp-card large cards)
- Change carousel-nav border-radius from radius-full to radius-sm
- Remove Inter from --font-sans (only Poppins is actually loaded)
- Add ::selection and ::-moz-selection styles with primary-tinted background
- Replace hardcoded 0.75rem/1.25rem spacing with tokens in navigation, favorites, community, media CSS
- Unify card border opacity (6%), shadow, and inset highlight pattern
- chore: mark FEAT-001 as completed
- feat: mobile nav staggered animation and empty state unification
- Add staggered entrance animation for mobile nav links with subtle translateX and increasing delays per child
- Add @keyframes nav-link-enter for the stagger effect
- Respect prefers-reduced-motion by disabling animation
- Remove conflicting .empty-state overrides from favorites.css and community.css (canonical definition in design-system.css)
- Update .no-badges in community.css to match unified empty state pattern
- Update .no-packages-state in layout.css with token-based padding, dashed border, and rounded corners
- Update .activity-empty-icon to use 2.5rem size and color token
- chore: mark FEAT-002 as completed
- fix: remove deprecated -moz-selection, add empty-state h2/icon fallback selectors
---------
a2beae7 -
Maintenance
6:09 AM
Remove decorative section divider comments
75ea436 -
Maintenance
6:07 AM
Remove inline comments
5618984 -
Fix
6:03 AM
Move Helpful button code out of hero counter IIFE
Details
The Helpful button JS was inside the same IIFE as the hero stat counters, which has an early return when .kb-stat-pill elements are not found. On the entry detail page (where the Helpful button lives) there are no stat pills, so the entire IIFE exited early and the click handler was never registered.
Fix: split into two separate IIFEs so each feature initializes independently.
593b647 -
Fix
6:00 AM
Handle stale localStorage preventing Helpful button clicks
Details
The previous non-functional Helpful button saved to localStorage on click without actually recording the vote server-side. Users who previously clicked it had a stale localStorage entry that permanently blocked the button on page load.
Fix: only trust localStorage if server-side count > 0; otherwise clear the stale entry so the user can vote again.
48e9283 -
Feature
5:53 AM
Implement 16 MCP integration improvements (#9)
Details
- feat(mcp): implement 16 MCP integration improvements
Critical Fixes:
- Wrap insertApproved(), approveContribution(), approvePendingContribution() in beginTransaction()/commit()/rollBack() for slug uniqueness safety
- Fix AdminService::rebuildRelationships() to call buildRelationships() instead of non-existent rebuildAll()
- Fix cleanupDeadSources() to check $result['is_reachable'] (array return)
- Add force:true requirement for deleteAllEntries when >100 entries
Schema & Migration:
- Add static $schemaChecked flag so createSchema() runs once per request
- Add view_count, quality_score, last_viewed columns to mcp_knowledge
- Create mcp_knowledge_history and mcp_audit_log tables
- Add pg_trgm extension and GiST index on title for fuzzy matching
Code Quality:
- Replace O(n) PHP similar_text() loop with PostgreSQL similarity() in findStrictDuplicate()
- Remove duplicate alias resolution from ToolRegistry::call() (McpToolRegistry already handles it)
- Fix string interpolation: single quotes to double quotes for $action var
- Wire up version history: call createHistoryRecord() before edits in AdminService::editEntry()
Performance:
- DB-level pagination in mcp-knowledge.php using searchAdvanced() with LIMIT/OFFSET instead of loading 200 results and slicing with array_slice()
Developer Experience:
- Add X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset headers after rate limit checks; add Retry-After: 60 on 429 responses
Frontend Cleanup:
- Add DocsService::clearCache() method for cache invalidation
- Remove duplicate .kb-page ::selection CSS rule
- Update $toolIcons to current consolidated tool names (sbox_kb, sbox_docs, sbox_admin, sbox_contribute, sbox_stats)
- feat(mcp): security, performance & DX improvements (batch 2)
Security:
- SSRF protection in KBService::ingestFromUrl() with private IP blocklist and domain allowlist (sbox.game, github.com, etc.)
- DocsService slug sanitization to prevent path traversal (../ stripping, character validation)
- Fail-closed rate limiting and duplicate checks in contribute.php — DB errors now reject submissions instead of silently bypassing
Performance:
- Replace O(n2) findAllDuplicates() with pg_trgm SQL self-join (capped at 100 results)
- Replace findRelated() full-table load with category-scoped searchAdvanced + PHP tag intersection
- Add 45-second cache TTL to stats tool to reduce DB hits
- Fix clearCache() to only delete known MCP doc cache keys instead of nuking all API response caches
Developer Experience:
- Wire up QualityScorer::suggestTags() — auto-tags contributions when no tags provided
- Add audit logging to kb_handleUpdate (with history snapshot)
- Add audit log retention: pruneOldEntries(90 days) called during cleanup
- Add clear_doc_cache admin action to sbox_admin tool
- Add prune_audit_logs to cleanup task enum
- feat(kb): visual improvements — reading time, quality badges, sort, featured entries, tag cloud, stagger animation, helpful button
Listing View:
- Add sort dropdown (newest/oldest/quality/popular) with pill-style buttons
- Add featured entries section (top 3 by quality score) on the first page
- Add tag cloud in sidebar showing 15 most popular tags with size scaling
- Add contribute CTA link in sidebar (green accent)
- Add quality score badge on cards (shown when >= 60)
- Add view count indicator on cards (eye icon + number)
- Add 'Updated' badge on cards modified within the last 7 days
- Add staggered fade-in animation for cards (0.04s delay per card)
- Include sort parameter in URL persistence
Entry View:
- Add reading time indicator (~X min read) in the header meta
- Add quality score indicator in header
- Add breadcrumb navigation (Knowledgebase > Category)
- Add 'Was this helpful?' vote button (localStorage-based)
Hero Section:
- Add IntersectionObserver-powered count-up animation on stat pills
Empty State:
- Add prominent 'Contribute an entry' CTA button alongside clear filters
- Update mcp-knowledge.php
---------
3821b93 -
Feature
5:50 AM
Wire up Helpful button to persist votes to database
Details
- Add helpful_count column to mcp_knowledge table (idempotent migration)
- Add KnowledgeDB::incrementHelpfulCount() method with RETURNING clause
- Create POST /backend/api/kb-vote.php endpoint with session-based rate limiting
- Update frontend JS to POST vote and sync count from server response
- Display live helpful count badge in the button UI
- Add CSS styling for the count badge in both default and voted states
7636f25 -
Feature
5:41 AM
Visual improvements — reading time, quality badges, sort, featured entries, tag cloud, stagger animation, helpful button
Details
Listing View:
- Add sort dropdown (newest/oldest/quality/popular) with pill-style buttons
- Add featured entries section (top 3 by quality score) on the first page
- Add tag cloud in sidebar showing 15 most popular tags with size scaling
- Add contribute CTA link in sidebar (green accent)
- Add quality score badge on cards (shown when >= 60)
- Add view count indicator on cards (eye icon + number)
- Add 'Updated' badge on cards modified within the last 7 days
- Add staggered fade-in animation for cards (0.04s delay per card)
- Include sort parameter in URL persistence
Entry View:
- Add reading time indicator (~X min read) in the header meta
- Add quality score indicator in header
- Add breadcrumb navigation (Knowledgebase > Category)
- Add 'Was this helpful?' vote button (localStorage-based)
Hero Section:
- Add IntersectionObserver-powered count-up animation on stat pills
Empty State:
- Add prominent 'Contribute an entry' CTA button alongside clear filters
1bd8db4 -
Feature
5:15 AM
Security, performance & DX improvements (batch 2)
Details
Security:
- SSRF protection in KBService::ingestFromUrl() with private IP blocklist and domain allowlist (sbox.game, github.com, etc.)
- DocsService slug sanitization to prevent path traversal (../ stripping, character validation)
- Fail-closed rate limiting and duplicate checks in contribute.php — DB errors now reject submissions instead of silently bypassing
Performance:
- Replace O(n2) findAllDuplicates() with pg_trgm SQL self-join (capped at 100 results)
- Replace findRelated() full-table load with category-scoped searchAdvanced + PHP tag intersection
- Add 45-second cache TTL to stats tool to reduce DB hits
- Fix clearCache() to only delete known MCP doc cache keys instead of nuking all API response caches
Developer Experience:
- Wire up QualityScorer::suggestTags() — auto-tags contributions when no tags provided
- Add audit logging to kb_handleUpdate (with history snapshot)
- Add audit log retention: pruneOldEntries(90 days) called during cleanup
- Add clear_doc_cache admin action to sbox_admin tool
- Add prune_audit_logs to cleanup task enum
a3d0c0d -
Feature
4:59 AM
Implement 16 MCP integration improvements
Details
Critical Fixes:
- Wrap insertApproved(), approveContribution(), approvePendingContribution() in beginTransaction()/commit()/rollBack() for slug uniqueness safety
- Fix AdminService::rebuildRelationships() to call buildRelationships() instead of non-existent rebuildAll()
- Fix cleanupDeadSources() to check $result['is_reachable'] (array return)
- Add force:true requirement for deleteAllEntries when >100 entries
Schema & Migration:
- Add static $schemaChecked flag so createSchema() runs once per request
- Add view_count, quality_score, last_viewed columns to mcp_knowledge
- Create mcp_knowledge_history and mcp_audit_log tables
- Add pg_trgm extension and GiST index on title for fuzzy matching
Code Quality:
- Replace O(n) PHP similar_text() loop with PostgreSQL similarity() in findStrictDuplicate()
- Remove duplicate alias resolution from ToolRegistry::call() (McpToolRegistry already handles it)
- Fix string interpolation: single quotes to double quotes for $action var
- Wire up version history: call createHistoryRecord() before edits in AdminService::editEntry()
Performance:
- DB-level pagination in mcp-knowledge.php using searchAdvanced() with LIMIT/OFFSET instead of loading 200 results and slicing with array_slice()
Developer Experience:
- Add X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset headers after rate limit checks; add Retry-After: 60 on 429 responses
Frontend Cleanup:
- Add DocsService::clearCache() method for cache invalidation
- Remove duplicate .kb-page ::selection CSS rule
- Update $toolIcons to current consolidated tool names (sbox_kb, sbox_docs, sbox_admin, sbox_contribute, sbox_stats)
f190a63 -
Style
3:59 AM
Align base theme with official sbox.game design system (#7)
Details
- chore: rebuild CSS bundle and update lockfile after npm install
- chore: add missing vendor/tippy.css required for CSS build
- feat: align base CSS theme with sbox.game design system
- Add --tint/--scrim RGB triplet variables for composable overlays
- Add --surface-bg, --surface-bg-hover, --surface-line, --surface-bg-fade
- Update --text-muted to #b2bed4, --warning to #f59e0b
- Add --accent-bright, --highlight-gold, --text-strong, --text-faint
- Add --input-* form variables and update form styles to use them
- Add --code-* syntax highlighting variables with .hljs token classes
- Add --menu-background, --menu-border, --btn-highlight-* variables
- Add --container-max-width, --site-background-color(-dark)
- Update shadows to use stronger --scrim-based values
- Replace scrollbar styles with sbox.game pattern (transparent track)
- Add table styles with tint/scrim composable pattern
- Add pre/code block and highlight.js syntax highlighting styles
- Add fallbacks in color-mix-fallbacks.css for older browsers
- fix: address 5 CSS review issues in base theme
- Replace rgb(from var(...)) relative color syntax with compatible rgb(var(--color-primary-rgb) / N%) in input-focus-ring, tr:hover, and thead tr for cross-browser support
- Update --color-warning-rgb to 245, 158, 11 and --color-warning-solid to #f59e0b to match the --warning value
- Restore Firefox scrollbar support with scrollbar-width: thin and scrollbar-color on html element
- Scope table element selectors under .content to prevent style leakage into admin panels and third-party widgets
- Fix tippy.css light theme to use --bg-secondary and --border instead of undefined --bg-elevated and --border-color variables
- Add --input-focus-ring fallback in color-mix-fallbacks.css
- feat: enhance buttons, links, cards, animations, menus, callouts, and badges with sbox.game design patterns
- fix: address 5 CSS review issues from theme refinements
- Remove duplicate .btn.disabled rule, add button.disabled to existing selector
- Fix slideUp default from 20px back to 100% to avoid breaking existing consumers
- Add explicit content: none to .callout::before base rule
- Replace hardcoded border-radius: 10px on .card with var(--radius-2xl) token
- Update --radius-2xl from 8px to 10px to match card design intent
- Narrow .menu-option transition from 'all' to 'color, background-color'
- chore: verify existing CSS build passes (FEAT-001)
- feat: complete rewrite of responsive.css with comprehensive mobile-first overhaul
- Section 1: body.menu-open state preserved
- Section 2: tablet adjustments (1024px) for nav and container padding
- Section 3: primary mobile breakpoint (768px) covering navigation overlay with backdrop blur, touch targets (48px min), content layout, typography scaling, hero, footer collapse, modals as bottom sheets, forms, package detail stacking, scrollable tab bars, and performance optimizations
- Section 4: small phone (480px) with brand text hidden, single-column grids, tighter padding, and modal max-height adjustments
- Section 5: touch device overrides disabling hover transforms, adding active scale feedback, and ensuring 44px minimum touch targets
- Section 6: prefers-reduced-motion with universal animation/transition disable
- Section 7: safe area support via @supports for footer, nav actions, and modals
- Section 8: performance included within 768px block (reduced backdrop-filter, simplified shadows, removed will-change)
- chore: mark FEAT-002 as completed
- fix: address CSS review issues - replace greedy tab selectors, remove duplicate reduced-motion, restore focus-visible
- feat: redesign user menu to match sbox.game session button pattern
Desktop:
- Trigger is now a clean circular avatar with subtle border ring
- Avatar size increased to 36px, username/arrow hidden
- Hover shows border brightening + glow effect
- Dropdown uses design system variables (--menu-background, --menu-border)
- Dropdown has 10px border-radius, 220px min-width, top notch arrow
- Items use --menu-option-text/bg variables with proper transitions
Mobile (768px):
- Trigger stays compact (avatar only, no text/arrow)
- Dropdown is a bottom sheet (slides up from bottom)
- Rounded top corners (16px), max-height 70dvh
- Drag handle pill indicator at top
- Backdrop overlay with scrim when open
- Safe area padding at bottom
- Stronger backdrop-filter blur (24px)
- refactor: restructure navbar to fix mobile layout - remove .nav-actions
- Restructure header.php: user-menu/login now in .nav-right wrapper alongside .nav-toggle, always visible in header bar
- Move .nav-links outside .nav-container as direct child of .site-nav so it can become a full-screen overlay without being constrained
- Remove .nav-actions from HTML, CSS (layout.css, responsive.css, nav-auth.css), and JS (navigation.js)
- Mobile nav overlay now uses solid var(--bg-primary) background
- Add z-index layering: .nav-container at 1002 above .nav-links at 1001
- Clean up navigation.js: remove all navActions references from initMobileMenu, initFocusTrap, and handleOutsideClick
- chore: mark FEAT-001 as completed
- fix: remove stale mobile nav-links rules and redundant margin-left from layout.css
- Remove conflicting .nav-links mobile rules (transform, max-height, top, border-top, transition) from the 768px media query in layout.css that clashed with the new responsive.css overlay approach
- Remove .nav-links.active translateX(0) rule superseded by opacity transition
- Remove redundant margin-left: auto from .nav-right since .nav-container already uses justify-content: space-between
- chore: mark FEAT-002 as completed
- chore: rebuild CSS bundle with all nav refactor and theme changes
- fix: use position:fixed for user dropdown so it always opens below header, never off-canvas
- fix: revert dropdown to position:absolute - backdrop-filter on site-nav traps fixed positioning
- refactor: rewrite nav from scratch to fix backdrop-filter containing block bug
- Remove backdrop-filter, transform, and filter from .site-nav
- Use solid background: var(--site-header-color) instead
- Move .nav-links inside .nav-container (between brand and nav-right)
- Change .site-nav from position:relative to position:sticky
- Merge scroll behavior (.scrolled, .nav-hidden) into main nav section
- Remove duplicate .nav-toggle and .site-nav blocks from bottom of layout.css
- Remove bottom-sheet mobile dropdown pattern (use normal absolute dropdown)
- Remove backdrop-filter from responsive.css performance section
- User dropdown now escapes containing block correctly (position:absolute in position:relative .user-menu)
- chore: mark FEAT-001 as completed
- fix: address nav CSS review issues - duplicate rule, fixed positioning, reduced motion
- Remove duplicate .nav-right base rule from nav-auth.css (layout.css is the single source of truth)
- Remove position:fixed from body.menu-open in responsive.css to prevent sticky nav breakage on iOS Safari; overflow:hidden alone prevents scroll
- Add prefers-reduced-motion:reduce block for .nav-links and .user-dropdown to disable opacity/transform transitions for motion-sensitive users
- chore: record review fix findings in task state
- fix: brand icon uses 4px border-radius squircle
- fix: user avatar uses 4px squircle border-radius, not circle
- chore: gitignore bundle.min.css - generated file should not be tracked
---------
6383437 -
Performance
1:33 AM
Remove Pace.js, async fonts, optimize image loading
Details
- Remove Pace.js (~30KB) — progress bar library loaded on every page with minimal user benefit. Removed from head.php, theme-manager.js vendor list, and disabled in bundleManager config.
- Make Material Symbols font non-render-blocking — was loaded as a synchronous stylesheet. Now uses preload/onload pattern (same as Poppins). Eliminates render-blocking external CSS request from the critical path.
- Remove unused cdn.jsdelivr.net dns-prefetch/preconnect (nothing loads from it)
- Add fetchpriority=high to package-detail hero image (LCP element)
- Add loading=lazy to skins-item large icon image
91bcbac -
Performance
1:25 AM
Frontend performance and accessibility improvements
Details
Performance:
- Fix render-blocking chart.min.js and chartjs-plugin-zoom.min.js (add defer)
- Remove duplicate Google Fonts @import from styles.css (already loaded via <link preload> in head.php — eliminates blocking CSS network request)
- Fix theme-manager.js double-loading 9 vendor scripts already present in head.php (popper, tippy, sweetalert2, toastify, pace, clipboard, chart.js, chartjs-plugin-zoom, smooth-scroll). Now detects existing <script> tags and skips duplicates.
- Restructure body-scripts.php from 30+ unconditional scripts to contextual loading: Core (8), Browse (6), Package detail (6), Profile (9), Auth (2), Interactive (3). Simple pages now load ~14 scripts instead of 30+.
Accessibility:
- Add skip-to-content link (visible on Tab focus, hidden otherwise)
- Replace div.container with main#main-content (proper ARIA landmark)
- Skip link styled with primary color, positioned absolutely, transitions into view on :focus
4430658 -
Refactor
1:17 AM
Admin panel visual overhaul — unified CSS & accessibility (#4)
Details
Shared CSS (admin-components.css):
- Add missing button variants: .btn-secondary, .btn-warning, .btn-text, .btn-admin
- Add :focus-visible states for all interactive elements (buttons, nav, tabs, forms)
- Add shared components: .admin-grid, .admin-card, .admin-table, .admin-tabs, .progress-bar-container/.progress-bar, .health-indicator, .checkbox-grid, .checkbox-label, .form-grid, .form-row, .info-box, .warning-box, .action-grid, .result-item, .admin-badge variants
- Add utility classes: .gap-lg, .text-primary, .text-secondary, .truncate, .w-full, .hidden
Layout (admin-layout.css):
- Add mobile sidebar backdrop overlay (.sidebar-backdrop) for better mobile UX
JavaScript (admin.js):
- Add sidebar backdrop toggle with proper open/close functions
- Add aria-current=page on active nav items
- Add role=alert + aria-live=polite on toast notifications
- Add role=dialog + aria-modal=true on modals with auto-focus
- Add role=tablist/tab/tabpanel with aria-selected on tab groups
- Add formatDate utility function
- Replace plain close-on-outside-click with backdrop-aware logic
Page refactors:
- webhook-settings.php: Replace ~120 lines inline CSS with shared components (.metrics-grid, .metric-card, .card, .health-indicator, .checkbox-grid, .form-grid)
- bulk-actions.php: Replace ~170 lines inline CSS with shared components (.action-grid, .card, .info-box, .warning-box, .progress-bar, .result-item) Fix: material-symbols-outlined → rounded (consistency) Fix: custom .notification → shared adminToast() (no more duplicate toast system)
- mcp-knowledge.php: Extract 250 lines inline CSS → admin-knowledge.css (page-specific design kept intact, just externalized for cacheability)
c62f915 -
Performance
12:53 AM
Admin panel overhaul — speed, security, and bug fixes
Details
Performance:
- Cache dashboard metrics with 30s TTL (eliminates ~8 DB queries per load)
- Progressive analytics loading: core metrics first, then secondary panels
- Combine multiple COUNT queries into single SQL statements throughout
- active-users.php: lazy-load tabs, replace meta-refresh with JS interval
- moderation-logs.php: tail-based file reading (last 100KB vs entire file)
- player-history.php: combine 7 queries into 1 + add 60s cache
- Defer admin.js, async-load non-critical CSS across all admin pages
- broadcast-notification.php: batch INSERT (chunks of 100) vs N+1 loop
SQL Optimizations:
- getUserStats: 4 queries → 1 using COUNT(DISTINCT CASE WHEN)
- getUserEngagement: replace NOT IN subquery with LEFT JOIN
- getRetentionMetrics: compute in SQL instead of fetching all rows to PHP
- getUserSessionStats: 4 queries → 1 combined query
Bug Fixes:
- Fix TypeError in org-claims-full loadData() (wrong CSS selector)
- Fix CalHeatMap not defined (removed invalid defer from CDN scripts)
- Fix reputation avgScore using only top 50 (now queries all users)
- Fix donations double saveDonation() creating duplicate test entries
Security:
- Remove display_errors=1 from diagnose.php in production
5d2ab45 -
Fix
12:10 AM
SQL injection, add rate limiting, remove cache duplication, DRY up code
Details
- Fix SQL injection in CacheManager::flushStats() by using parameterized queries
- Add rate limiting to 12 legacy API endpoints via new legacy-rate-limiter.php
- Remove ~200 lines of duplicate cache logic from DatabaseManager (delegate to CacheManager)
- Clean up .gitignore: remove duplicates, fix conflicting *.md pattern, organize sections
- DRY up PackageController: extract findByFilter() helper for 5 near-identical methods
33c5ea0
2
-
Change
8:59 AM
MCP admin stuff
df45757 -
Maintenance
12:18 AM
Auto-fix code (+)
45f675f
Generated from the project's commit history whenever the site is deployed. Times are server time.