Toolasha

Toolasha - Enhanced tools for Milky Way Idle.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(У мене вже є менеджер скриптів, дайте мені встановити його!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Toolasha
// @namespace    http://tampermonkey.net/
// @version      2.18.2
// @description  Toolasha - Enhanced tools for Milky Way Idle.
// @author       Celasha and Claude, thank you to bot7420, DrDucky, Frotty, Truth_Light, AlphB, qu, and sentientmilk, for providing the basis for a lot of this. Thank you to Miku, Orvel, Jigglymoose, Incinarator, Knerd, and others for their time and help. Thank you to Steez for testing and helping me figure out where I'm wrong! Thank you to Tib for his generous contribution of the Character Cards. Thank you to Sapnas for -deeply- testing and singlehandedly help me improve performance. Special thanks to Zaeter for the name.
// @license      CC-BY-NC-SA-4.0
// @run-at       document-start
// @match        https://www.milkywayidle.com/*
// @match        https://test.milkywayidle.com/*
// @match        https://shykai.github.io/MWICombatSimulatorTest/dist/*
// @grant        GM_addStyle
// @grant        GM.xmlHttpRequest
// @grant        GM_xmlhttpRequest
// @grant        GM_notification
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        unsafeWindow
// @require      https://cdnjs.cloudflare.com/ajax/libs/mathjs/12.4.2/math.js
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/chart.min.js
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/chartjs-plugin-datalabels.min.js
// @require      https://cdn.jsdelivr.net/gh/Celasha/Toolasha@bf5b1c2b286d3ed25d3ff0b63bc234c4bd08f394/dist/libraries/toolasha-core.js
// @require      https://cdn.jsdelivr.net/gh/Celasha/Toolasha@bf5b1c2b286d3ed25d3ff0b63bc234c4bd08f394/dist/libraries/toolasha-utils.js
// @require      https://cdn.jsdelivr.net/gh/Celasha/Toolasha@bf5b1c2b286d3ed25d3ff0b63bc234c4bd08f394/dist/libraries/toolasha-market.js
// @require      https://cdn.jsdelivr.net/gh/Celasha/Toolasha@bf5b1c2b286d3ed25d3ff0b63bc234c4bd08f394/dist/libraries/toolasha-actions.js
// @require      https://cdn.jsdelivr.net/gh/Celasha/Toolasha@bf5b1c2b286d3ed25d3ff0b63bc234c4bd08f394/dist/libraries/toolasha-combat.js
// @require      https://cdn.jsdelivr.net/gh/Celasha/Toolasha@bf5b1c2b286d3ed25d3ff0b63bc234c4bd08f394/dist/libraries/toolasha-ui.js
// ==/UserScript==
// Note: Combat Sim auto-import requires Tampermonkey for cross-domain storage. Not available on Steam (use manual clipboard copy/paste instead).

(function () {
    'use strict';

    window.Toolasha = window.Toolasha || {}; window.Toolasha.__buildTarget = "browser";

    /**
     * Toolasha Entrypoint
     * Minimal bootstrap script that loads libraries and initializes features
     *
     * Libraries are loaded via @require in userscript header:
     * - Core (core modules, API)
     * - Utils (all utilities)
     * - Market (market, inventory, economy)
     * - Actions (production, gathering, alchemy)
     * - Combat (combat, stats, abilities)
     * - UI (tasks, skills, settings, misc)
     */

    // Environment mismatch detection
    (function checkBuildEnvironment() {
        const buildTarget = window.Toolasha?.__buildTarget;
        // Check for GM_info specifically - the Steam polyfill provides GM but not GM_info
        const hasScriptManager = typeof GM_info !== 'undefined';

        if (buildTarget === 'browser' && !hasScriptManager) {
            alert(
                'Toolasha: Wrong build installed!\n\n' +
                    'You have the BROWSER build installed, but you are running on Steam.\n' +
                    'The browser build requires Tampermonkey and will not work on Steam.\n\n' +
                    'Please install the Steam build instead.'
            );
            throw new Error('[Toolasha] Browser build cannot run on Steam. Install the Steam build.');
        }
        if (buildTarget === 'steam' && hasScriptManager) {
            console.warn(
                '[Toolasha] Steam build detected in browser. ' +
                    'The Steam build is larger than necessary for browser use — consider switching to the browser build. ' +
                    'Continuing anyway.'
            );
        }
    })();

    // Access libraries from global namespace
    const Core = window.Toolasha.Core;
    const Utils = window.Toolasha.Utils;
    const Market = window.Toolasha.Market;
    const Actions = window.Toolasha.Actions;
    const Combat = window.Toolasha.Combat;
    const UI = window.Toolasha.UI;

    // Destructure core modules
    const { storage, config, webSocketHook, domObserver, dataManager, featureRegistry } = Core;

    const { setupScrollTooltipDismissal } = Utils.dom;

    /**
     * Detect if running on Combat Simulator page
     * @returns {boolean} True if on Combat Simulator
     */
    function isCombatSimulatorPage() {
        const url = window.location.href;
        // Only work on test Combat Simulator for now
        return url.includes('shykai.github.io/MWICombatSimulatorTest/dist/');
    }

    /**
     * Register all features from libraries into the feature registry
     */
    function registerFeatures() {
        // Market Features
        const marketFeatures = [
            { key: 'tooltipPrices', name: 'Tooltip Prices', category: 'Market', module: Market.tooltipPrices, async: true },
            {
                key: 'expectedValueCalculator',
                name: 'Expected Value Calculator',
                category: 'Market',
                module: Market.expectedValueCalculator,
                async: true,
            },
            {
                key: 'tooltipConsumables',
                name: 'Tooltip Consumables',
                category: 'Market',
                module: Market.tooltipConsumables,
                async: true,
            },
            {
                key: 'dungeonTokenTooltips',
                name: 'Dungeon Token Tooltips',
                category: 'Inventory',
                module: Market.dungeonTokenTooltips,
                async: true,
            },
            { key: 'marketFilter', name: 'Market Filter', category: 'Market', module: Market.marketFilter, async: false },
            { key: 'marketSort', name: 'Market Sort', category: 'Market', module: Market.marketSort, async: false },
            {
                key: 'autoFillPrice',
                name: 'Auto Fill Price',
                category: 'Market',
                module: Market.autoFillPrice,
                async: false,
            },
            {
                key: 'autoClickMax',
                name: 'Auto Click Max',
                category: 'Market',
                module: Market.autoClickMax,
                async: false,
            },
            {
                key: 'itemCountDisplay',
                name: 'Item Count Display',
                category: 'Market',
                module: Market.itemCountDisplay,
                async: false,
            },
            {
                key: 'listingPriceDisplay',
                name: 'Listing Price Display',
                category: 'Market',
                module: Market.listingPriceDisplay,
                async: false,
            },
            {
                key: 'estimatedListingAge',
                name: 'Estimated Listing Age',
                category: 'Market',
                module: Market.estimatedListingAge,
                async: false,
            },
            {
                key: 'queueLengthEstimator',
                name: 'Queue Length Estimator',
                category: 'Market',
                module: Market.queueLengthEstimator,
                async: false,
            },
            {
                key: 'marketOrderTotals',
                name: 'Market Order Totals',
                category: 'Market',
                module: Market.marketOrderTotals,
                async: false,
            },
            {
                key: 'marketHistoryViewer',
                name: 'Market History Viewer',
                category: 'Market',
                module: Market.marketHistoryViewer,
                async: false,
            },
            {
                key: 'philoCalculator',
                name: 'Philo Calculator',
                category: 'Market',
                module: Market.philoCalculator,
                async: false,
            },
            { key: 'tradeHistory', name: 'Trade History', category: 'Market', module: Market.tradeHistory, async: false },
            {
                key: 'tradeHistoryDisplay',
                name: 'Trade History Display',
                category: 'Market',
                module: Market.tradeHistoryDisplay,
                async: false,
            },
            { key: 'networth', name: 'Net Worth', category: 'Economy', module: Market.networthFeature, async: false },
            {
                key: 'inventoryBadgeManager',
                name: 'Inventory Badge Manager',
                category: 'Inventory',
                module: Market.inventoryBadgeManager,
                async: false,
            },
            {
                key: 'inventorySort',
                name: 'Inventory Sort',
                category: 'Inventory',
                module: Market.inventorySort,
                async: false,
            },
            {
                key: 'inventoryBadgePrices',
                name: 'Inventory Badge Prices',
                category: 'Inventory',
                module: Market.inventoryBadgePrices,
                async: false,
            },
            {
                key: 'invCategoryTotals',
                name: 'Inventory Category Totals',
                category: 'Inventory',
                module: Market.inventoryCategoryTotals,
                async: false,
            },
            {
                key: 'autoAllButton',
                name: 'Auto All Button',
                category: 'Inventory',
                module: Market.autoAllButton,
                async: false,
            },
            {
                key: 'inventoryTabs',
                name: 'Custom Inventory Tabs',
                category: 'Inventory',
                module: Market.customTabsFeature,
                async: true,
            },
        ];

        // Actions Features
        const actionsFeatures = [
            {
                key: 'actionTimeDisplay',
                name: 'Action Time Display',
                category: 'Actions',
                module: Actions.actionTimeDisplay,
                async: false,
            },
            {
                key: 'quickInputButtons',
                name: 'Quick Input Buttons',
                category: 'Actions',
                module: Actions.quickInputButtons,
                async: false,
            },
            { key: 'outputTotals', name: 'Output Totals', category: 'Actions', module: Actions.outputTotals, async: false },
            {
                key: 'maxProduceable',
                name: 'Max Produceable',
                category: 'Actions',
                module: Actions.maxProduceable,
                async: false,
            },
            {
                key: 'gatheringStats',
                name: 'Gathering Stats',
                category: 'Actions',
                module: Actions.gatheringStats,
                async: false,
            },
            {
                key: 'requiredMaterials',
                name: 'Required Materials',
                category: 'Actions',
                module: Actions.requiredMaterials,
                async: false,
            },
            {
                key: 'missingMaterialsButton',
                name: 'Missing Materials Button',
                category: 'Actions',
                module: Actions.missingMaterialsButton,
                async: false,
            },
            {
                key: 'budgetCalculator',
                name: 'Budget Calculator',
                category: 'Actions',
                module: Actions.budgetCalculator,
                async: false,
            },
            {
                key: 'alchemyProfitDisplay',
                name: 'Alchemy Profit Display',
                category: 'Alchemy',
                module: Actions.alchemyProfitDisplay,
                async: false,
            },
            {
                key: 'teaRecommendation',
                name: 'Tea Recommendation',
                category: 'Actions',
                module: Actions.teaRecommendation,
                async: false,
            },
            {
                key: 'lootLogStats',
                name: 'Loot Log Statistics',
                category: 'Actions',
                module: UI.lootLogStats,
                async: false,
            },
            {
                key: 'inventoryCountDisplay',
                name: 'Inventory Count Display',
                category: 'Actions',
                module: Actions.inventoryCountDisplay,
                async: false,
            },
            {
                key: 'pinnedActionsPage',
                name: 'Pinned Actions Page',
                category: 'Actions',
                module: Actions.pinnedActionsPage,
                async: false,
            },
        ];

        // Combat Features
        const combatFeatures = [
            {
                key: 'abilityBookCalculator',
                name: 'Ability Book Calculator',
                category: 'Combat',
                module: Combat.abilityBookCalculator,
                async: false,
            },
            { key: 'zoneIndices', name: 'Zone Indices', category: 'Combat', module: Combat.zoneIndices, async: false },
            { key: 'combatScore', name: 'Combat Score', category: 'Profile', module: Combat.combatScore, async: false },
            {
                key: 'characterCardButton',
                name: 'Character Card Button',
                category: 'Profile',
                module: Combat.characterCardButton,
                async: false,
            },
            {
                key: 'loadoutEnhancementDisplay',
                name: 'Loadout Enhancement Display',
                category: 'Combat',
                module: Combat.loadoutEnhancementDisplay,
                async: false,
            },
            {
                key: 'dungeonTracker',
                name: 'Dungeon Tracker',
                category: 'Combat',
                module: Combat.dungeonTracker,
                async: false,
            },
            {
                key: 'dungeonTrackerUI',
                name: 'Dungeon Tracker UI',
                category: 'Combat',
                module: Combat.dungeonTrackerUI,
                async: false,
            },
            {
                key: 'dungeonTrackerChatAnnotations',
                name: 'Dungeon Tracker Chat',
                category: 'Combat',
                module: Combat.dungeonTrackerChatAnnotations,
                async: false,
            },
            {
                key: 'combatBattleCounter',
                name: 'Combat Battle Counter',
                category: 'Combat',
                module: Combat.combatBattleCounter,
                async: false,
            },
            {
                key: 'combatSummary',
                name: 'Combat Summary',
                category: 'Combat',
                module: Combat.combatSummary,
                async: false,
            },
            { key: 'combatStats', name: 'Combat Stats', category: 'Combat', module: Combat.combatStats, async: true },
            {
                key: 'labyrinthTracker',
                name: 'Labyrinth Tracker',
                category: 'Combat',
                module: Combat.labyrinthTracker,
                async: false,
            },
            {
                key: 'labyrinthBestLevel',
                name: 'Labyrinth Best Level',
                category: 'Combat',
                module: Combat.labyrinthBestLevel,
                async: false,
            },
            {
                key: 'labyrinthShopPrices',
                name: 'Labyrinth Shop Prices',
                category: 'Combat',
                module: Combat.labyrinthShopPrices,
                async: false,
            },
            {
                key: 'loadoutSort',
                name: 'Loadout Sort',
                category: 'Combat',
                module: Combat.loadoutSort,
                async: false,
            },
            {
                key: 'loadoutSnapshot',
                name: 'Loadout Snapshots',
                category: 'Combat',
                module: Combat.loadoutSnapshot,
                async: false,
            },
            {
                key: 'scrollSimulatorUI',
                name: 'Scroll Simulator UI',
                category: 'Combat',
                module: Combat.scrollSimulatorUI,
                async: false,
            },
            {
                key: 'combatSim',
                name: 'Combat Simulator',
                category: 'Combat',
                module: Combat.combatSim,
                async: false,
            },
        ];

        // UI Features
        const uiFeatures = [
            {
                key: 'equipmentLevelDisplay',
                name: 'Equipment Level Display',
                category: 'UI',
                module: UI.equipmentLevelDisplay,
                async: false,
            },
            {
                key: 'alchemyItemDimming',
                name: 'Alchemy Item Dimming',
                category: 'UI',
                module: UI.alchemyItemDimming,
                async: false,
            },
            {
                key: 'skillExperiencePercentage',
                name: 'Skill Experience Percentage',
                category: 'UI',
                module: UI.skillExperiencePercentage,
                async: false,
            },
            { key: 'externalLinks', name: 'External Links', category: 'UI', module: UI.externalLinks, async: false },
            {
                key: 'hideLabyrinthBadge',
                name: 'Hide Labyrinth Badge',
                category: 'UI',
                module: UI.hideLabyrinthBadge,
                async: false,
            },
            {
                key: 'altClickNavigation',
                name: 'Alt+Click Navigation',
                category: 'Navigation',
                module: UI.altClickNavigation,
                async: false,
            },
            {
                key: 'collectionNavigation',
                name: 'Collection Navigation',
                category: 'Navigation',
                module: UI.collectionNavigation,
                async: false,
            },
            {
                key: 'collectionFilters',
                name: 'Collection Filters',
                category: 'Collection',
                module: UI.collectionFilters,
                async: true,
            },
            { key: 'chatCommands', name: 'Chat Commands', category: 'Chat', module: UI.chatCommands, async: true },
            { key: 'mentionTracker', name: 'Mention Tracker', category: 'Chat', module: UI.mentionTracker, async: true },
            { key: 'popOutChat', name: 'Pop-Out Chat', category: 'Chat', module: UI.popOutChat, async: true },
            { key: 'chatBlockList', name: 'Chat Block List', category: 'Chat', module: UI.chatBlockList, async: false },
            {
                key: 'chatHistoryExtender',
                name: 'Chat History Extender',
                category: 'Chat',
                module: UI.chatHistoryExtender,
                async: false,
            },
            {
                key: 'taskProfitDisplay',
                name: 'Task Profit Display',
                category: 'Tasks',
                module: UI.taskProfitDisplay,
                async: false,
            },
            {
                key: 'taskRerollTracker',
                name: 'Task Reroll Tracker',
                category: 'Tasks',
                module: UI.taskRerollTracker,
                async: false,
            },
            { key: 'taskSorter', name: 'Task Sorter', category: 'Tasks', module: UI.taskSorter, async: false },
            { key: 'taskIcons', name: 'Task Icons', category: 'Tasks', module: UI.taskIcons, async: false },
            {
                key: 'taskInventoryHighlighter',
                name: 'Task Inventory Highlighter',
                category: 'Tasks',
                module: UI.taskInventoryHighlighter,
                async: false,
            },
            {
                key: 'taskStatistics',
                name: 'Task Statistics',
                category: 'Tasks',
                module: UI.taskStatistics,
                async: false,
            },
            {
                key: 'taskClaimCollector',
                name: 'Task Claim Collector',
                category: 'Tasks',
                module: UI.taskClaimCollector,
                async: false,
            },
            { key: 'skillRemainingXP', name: 'Remaining XP', category: 'Skills', module: UI.remainingXP, async: false },
            { key: 'xpTracker', name: 'XP/hr Tracker', category: 'Skills', module: UI.xpTracker, async: false },
            {
                key: 'housePanelObserver',
                name: 'House Panel Observer',
                category: 'House',
                module: UI.housePanelObserver,
                async: false,
            },
            {
                key: 'transmuteRates',
                name: 'Transmute Rates',
                category: 'Dictionary',
                module: UI.transmuteRates,
                async: false,
            },
            {
                key: 'alchemy_transmuteHistory',
                name: 'Transmute History Tracker',
                category: 'Alchemy',
                module: UI.transmuteHistoryTracker,
                async: false,
            },
            {
                key: 'alchemy_transmuteHistoryViewer',
                name: 'Transmute History Viewer',
                category: 'Alchemy',
                module: UI.transmuteHistoryViewer,
                async: false,
            },
            {
                key: 'alchemy_coinifyHistory',
                name: 'Coinify History Tracker',
                category: 'Alchemy',
                module: UI.coinifyHistoryTracker,
                async: false,
            },
            {
                key: 'alchemy_coinifyHistoryViewer',
                name: 'Coinify History Viewer',
                category: 'Alchemy',
                module: UI.coinifyHistoryViewer,
                async: false,
            },
            {
                key: 'enhancementFeature',
                name: 'Enhancement Tracker',
                category: 'Enhancement',
                module: UI.enhancementFeature,
                async: false,
            },
            {
                key: 'enhancementXPH',
                name: 'Enhancement XPH Calculator',
                category: 'Enhancement',
                module: UI.xphCalculator,
                async: false,
            },
            {
                key: 'guildXPTracker',
                name: 'Guild XP Tracker',
                category: 'Guild',
                module: UI.guildXPTracker,
                async: false,
            },
            {
                key: 'guildXPDisplay',
                name: 'Guild XP Display',
                category: 'Guild',
                module: UI.guildXPDisplay,
                async: false,
            },
            {
                key: 'emptyQueueNotification',
                name: 'Empty Queue Notification',
                category: 'Notifications',
                module: UI.emptyQueueNotification,
                async: false,
            },
        ];

        // Combine all features
        const allFeatures = [...marketFeatures, ...actionsFeatures, ...combatFeatures, ...uiFeatures];

        // Convert to feature registry format
        const features = allFeatures.map((feature) => ({
            key: feature.key,
            name: feature.name,
            category: feature.category,
            initialize: () => feature.module.initialize(),
            disable: typeof feature.module.disable === 'function' ? () => feature.module.disable() : undefined,
            async: feature.async,
        }));

        // Replace feature registry's features array
        featureRegistry.replaceFeatures(features);
    }

    if (isCombatSimulatorPage()) {
        // Initialize combat sim integration only
        Combat.combatSimIntegration.initialize();

        // Skip all other initialization
    } else {
        // CRITICAL: Install WebSocket hook FIRST, before game connects
        webSocketHook.install();

        // CRITICAL: Start centralized DOM observer SECOND, before features initialize
        domObserver.start();

        // Set up scroll listener to dismiss stuck tooltips
        setupScrollTooltipDismissal();

        // Initialize network alert (must be early, before market features)
        Market.networkAlert.initialize();

        // Start capturing client data from localStorage (for Combat Sim export)
        webSocketHook.captureClientDataFromLocalStorage();

        // Register all features from libraries
        registerFeatures();

        // Initialize action panel observer (special case - not a regular feature)
        Actions.initActionPanelObserver();

        // Initialize storage and config THIRD (async)
        // Store the promise so character_initialized can wait for storage readiness
        const storageReady = (async () => {
            try {
                // Initialize storage (opens IndexedDB)
                await storage.initialize();

                // Initialize config (loads settings from storage)
                await config.initialize();

                // Add beforeunload handler to flush all pending writes
                window.addEventListener('beforeunload', () => {
                    storage.flushAll();
                });

                // Initialize Data Manager immediately
                // Don't wait for localStorageUtil - it handles missing data gracefully
                dataManager.initialize();
            } catch (error) {
                console.error('[Toolasha] Storage/config initialization failed:', error);
                // Initialize anyway
                dataManager.initialize();
            }
        })();

        // Setup character switch handler once (NOT inside character_initialized listener)
        featureRegistry.setupCharacterSwitchHandler();

        dataManager.on('character_initialized', (_data) => {
            // Skip full initialization during character switches
            // The character_switched handler in feature-registry already handles reinitialization
            if (_data._isCharacterSwitch) {
                return;
            }

            // Initialize all features using the feature registry
            setTimeout(async () => {
                try {
                    // Ensure storage/config are initialized before loading character settings
                    // On Steam, character data can arrive before IndexedDB is open
                    await storageReady;

                    // Reload config settings with character-specific data
                    await config.loadSettings();
                    config.applyColorSettings();

                    // Initialize scroll simulator storage (character-specific)
                    await Combat.scrollSimulator.initialize().catch((error) => {
                        console.error('[Toolasha] Scroll simulator initialization failed:', error);
                    });

                    // Initialize Settings UI after character data is loaded
                    await UI.settingsUI.initialize().catch((error) => {
                        console.error('[Toolasha] Settings UI initialization failed:', error);
                    });

                    await featureRegistry.initializeFeatures();

                    // Health check after initialization
                    setTimeout(async () => {
                        const failedFeatures = featureRegistry.checkFeatureHealth();

                        // Note: Settings tab health check removed - tab only appears when user opens settings panel

                        if (failedFeatures.length > 0) {
                            console.warn(
                                '[Toolasha] Health check found failed features:',
                                failedFeatures.map((f) => f.name)
                            );

                            setTimeout(async () => {
                                await featureRegistry.retryFailedFeatures(failedFeatures);

                                // Final health check
                                const stillFailed = featureRegistry.checkFeatureHealth();
                                if (stillFailed.length > 0) {
                                    console.warn(
                                        '[Toolasha] These features could not initialize:',
                                        stillFailed.map((f) => f.name)
                                    );
                                    console.warn(
                                        '[Toolasha] Try refreshing the page or reopening the relevant game panels'
                                    );
                                }
                            }, 1000);
                        }
                    }, 500); // Wait 500ms after initialization to check health
                } catch (error) {
                    console.error('[Toolasha] Feature initialization failed:', error);
                }
            }, 100);
        });

        // Expose minimal user-facing API
        const targetWindow = typeof unsafeWindow !== 'undefined' ? unsafeWindow : window;

        targetWindow.Toolasha.version = '0.14.3';

        // Feature toggle API (for users to manage settings via console)
        targetWindow.Toolasha.features = {
            list: () => config.getFeaturesByCategory(),
            enable: (key) => config.setFeatureEnabled(key, true),
            disable: (key) => config.setFeatureEnabled(key, false),
            toggle: (key) => config.toggleFeature(key),
            status: (key) => config.isFeatureEnabled(key),
            info: (key) => config.getFeatureInfo(key),
        };

        // Guild XP data management
        targetWindow.Toolasha.guild = {
            resetMemberXP: () => UI.guildXPTracker.resetMemberData(),
        };
    }

})();