snes-disassembler
Version:
A Super Nintendo (SNES) ROM disassembler for 65816 assembly
551 lines • 26.9 kB
JavaScript
"use strict";
/**
* Interactive Preferences Manager
*
* Provides an interactive interface for managing user preferences
* for advanced options, ensuring a personalized experience.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.preferencesManager = exports.PreferencesManager = void 0;
const prompts_1 = require("@clack/prompts");
const chalk_1 = __importDefault(require("chalk"));
const session_manager_1 = require("./session-manager");
class PreferencesManager {
/**
* Run the interactive preferences configuration interface
*/
async runPreferencesInterface() {
await session_manager_1.sessionManager.load();
(0, prompts_1.intro)(chalk_1.default.bgBlue.black(' ⚙️ User Preferences Configuration ⚙️ '));
try {
let shouldContinue = true;
while (shouldContinue) {
const action = await (0, prompts_1.select)({
message: 'What would you like to configure?',
options: [
{ value: 'view', label: '👀 View Current Preferences', hint: 'Display all current settings' },
{ value: 'basic', label: '⚡ Basic Settings', hint: 'Output format, directories, etc.' },
{ value: 'advanced', label: '🔧 Advanced Analysis Options', hint: 'Analysis, disassembly features' },
{ value: 'assets', label: '🎨 Asset Extraction', hint: 'Graphics, audio, text preferences' },
{ value: 'brr', label: '🎵 BRR Audio Settings', hint: 'Audio decoding preferences' },
{ value: 'analysis', label: '📊 Analysis Settings', hint: 'Analysis types and output' },
{ value: 'format', label: '📝 Output Format', hint: 'Comments, symbols, formatting' },
{ value: 'ui', label: '🖥️ UI/UX Settings', hint: 'Interactive mode, colors, progress' },
{ value: 'ai', label: '🤖 AI Features', hint: 'AI-powered analysis settings' },
{ value: 'import-export', label: '💾 Import/Export', hint: 'Backup and restore preferences' },
{ value: 'reset', label: '🔄 Reset to Defaults', hint: 'Clear all preferences' },
{ value: 'exit', label: '❌ Exit', hint: 'Save and exit preferences' }
]
});
if ((0, prompts_1.isCancel)(action) || action === 'exit') {
shouldContinue = false;
break;
}
switch (action) {
case 'view':
this.viewPreferences();
break;
case 'basic':
await this.configureBasicSettings();
break;
case 'advanced':
await this.configureAdvancedOptions();
break;
case 'assets':
await this.configureAssetPreferences();
break;
case 'brr':
await this.configureBRRPreferences();
break;
case 'analysis':
await this.configureAnalysisPreferences();
break;
case 'format':
await this.configureFormatPreferences();
break;
case 'ui':
await this.configureUIPreferences();
break;
case 'ai':
await this.configureAIPreferences();
break;
case 'import-export':
await this.handleImportExport();
break;
case 'reset':
await this.resetPreferences();
break;
}
}
(0, prompts_1.outro)(chalk_1.default.green('✅ Preferences saved! Your settings will be applied to future sessions.'));
}
catch (error) {
if ((0, prompts_1.isCancel)(error)) {
(0, prompts_1.cancel)('Preferences configuration cancelled.');
}
else {
(0, prompts_1.outro)(chalk_1.default.red(`❌ Error: ${error instanceof Error ? error.message : error}`));
}
}
}
/**
* Display current preferences
*/
viewPreferences() {
const summary = session_manager_1.sessionManager.getPreferencesSummary();
(0, prompts_1.note)(summary, 'Current Preferences');
}
/**
* Configure basic settings
*/
async configureBasicSettings() {
const currentPrefs = session_manager_1.sessionManager.getPreferences();
const defaultFormat = await (0, prompts_1.select)({
message: 'Default output format:',
options: [
{ value: 'ca65', label: 'CA65 Assembly', hint: 'Compatible with cc65 assembler' },
{ value: 'wla-dx', label: 'WLA-DX Assembly', hint: 'Compatible with WLA-DX assembler' },
{ value: 'bass', label: 'BASS Assembly', hint: 'Compatible with BASS assembler' },
{ value: 'html', label: 'HTML Report', hint: 'Interactive HTML documentation' },
{ value: 'json', label: 'JSON Data', hint: 'Machine-readable JSON format' },
{ value: 'markdown', label: 'Markdown Documentation', hint: 'Human-readable documentation' }
],
initialValue: currentPrefs.defaultFormat ?? 'ca65'
});
if ((0, prompts_1.isCancel)(defaultFormat))
return;
const defaultOutputDir = await (0, prompts_1.text)({
message: 'Default output directory:',
placeholder: './output',
defaultValue: currentPrefs.defaultOutputDir ?? './output'
});
if ((0, prompts_1.isCancel)(defaultOutputDir))
return;
const maxRecentFiles = await (0, prompts_1.text)({
message: 'Maximum recent files to track:',
placeholder: '10',
defaultValue: (currentPrefs.maxRecentFiles ?? 10).toString(),
validate: (value) => {
const num = parseInt(value);
if (isNaN(num) || num < 1 || num > 50) {
return 'Please enter a number between 1 and 50';
}
return undefined;
}
});
if ((0, prompts_1.isCancel)(maxRecentFiles))
return;
const showHelp = await (0, prompts_1.confirm)({
message: 'Show contextual help by default?',
initialValue: currentPrefs.showHelp !== false
});
if ((0, prompts_1.isCancel)(showHelp))
return;
const confirmActions = await (0, prompts_1.confirm)({
message: 'Confirm destructive actions?',
initialValue: currentPrefs.confirmActions !== false
});
if ((0, prompts_1.isCancel)(confirmActions))
return;
// Update preferences
session_manager_1.sessionManager.updatePreferences({
defaultFormat: defaultFormat,
defaultOutputDir: defaultOutputDir,
maxRecentFiles: parseInt(maxRecentFiles),
showHelp: showHelp,
confirmActions: confirmActions
});
(0, prompts_1.note)('✅ Basic settings updated successfully!', 'Success');
}
/**
* Configure advanced analysis options
*/
async configureAdvancedOptions() {
const currentOptions = session_manager_1.sessionManager.getAdvancedOptions();
const selectedOptions = await (0, prompts_1.multiselect)({
message: 'Select advanced options to enable by default:',
options: [
{ value: 'analysis', label: 'Full Analysis', hint: 'Detect functions and data structures' },
{ value: 'enhancedDisasm', label: 'Enhanced Disassembly', hint: 'Use MCP server insights' },
{ value: 'bankAware', label: 'Bank-Aware Addressing', hint: '24-bit addressing mode' },
{ value: 'detectFunctions', label: 'Function Detection', hint: 'Automatically detect functions' },
{ value: 'generateDocs', label: 'Generate Documentation', hint: 'Create comprehensive docs' },
{ value: 'extractAssets', label: 'Extract Assets', hint: 'Also extract graphics/audio' },
{ value: 'quality', label: 'Quality Reports', hint: 'Generate code quality metrics' }
],
required: false,
initialValues: currentOptions ? [
...(currentOptions.analysis ? ['analysis'] : []),
...(currentOptions.enhancedDisasm ? ['enhancedDisasm'] : []),
...(currentOptions.bankAware ? ['bankAware'] : []),
...(currentOptions.detectFunctions ? ['detectFunctions'] : []),
...(currentOptions.generateDocs ? ['generateDocs'] : []),
...(currentOptions.extractAssets ? ['extractAssets'] : []),
...(currentOptions.quality ? ['quality'] : [])
] : []
});
if ((0, prompts_1.isCancel)(selectedOptions))
return;
const disableAI = await (0, prompts_1.confirm)({
message: 'Disable AI features by default?',
initialValue: currentOptions?.disableAI ?? false
});
if ((0, prompts_1.isCancel)(disableAI))
return;
const options = selectedOptions;
await session_manager_1.sessionManager.updateAdvancedOptions({
analysis: options.includes('analysis'),
enhancedDisasm: options.includes('enhancedDisasm'),
bankAware: options.includes('bankAware'),
detectFunctions: options.includes('detectFunctions'),
generateDocs: options.includes('generateDocs'),
extractAssets: options.includes('extractAssets'),
quality: options.includes('quality'),
disableAI: disableAI
});
(0, prompts_1.note)('✅ Advanced options updated successfully!', 'Success');
}
/**
* Configure asset extraction preferences
*/
async configureAssetPreferences() {
const currentPrefs = session_manager_1.sessionManager.getAssetPreferences();
const defaultAssetTypes = await (0, prompts_1.multiselect)({
message: 'Default asset types to extract:',
options: [
{ value: 'graphics', label: '🎨 Graphics', hint: 'Sprites, backgrounds, tiles' },
{ value: 'audio', label: '🎵 Audio', hint: 'Music and sound effects' },
{ value: 'text', label: '📝 Text', hint: 'Dialogue and strings' }
],
required: false,
initialValues: currentPrefs?.defaultAssetTypes ?? []
});
if ((0, prompts_1.isCancel)(defaultAssetTypes))
return;
const defaultAssetFormats = await (0, prompts_1.multiselect)({
message: 'Default graphics formats to extract:',
options: [
{ value: '2bpp', label: '2BPP', hint: '2 bits per pixel' },
{ value: '4bpp', label: '4BPP', hint: '4 bits per pixel (most common)' },
{ value: '8bpp', label: '8BPP', hint: '8 bits per pixel' }
],
required: false,
initialValues: currentPrefs?.defaultAssetFormats ?? ['4bpp']
});
if ((0, prompts_1.isCancel)(defaultAssetFormats))
return;
const defaultAssetOutputDir = await (0, prompts_1.text)({
message: 'Default asset output directory:',
placeholder: './assets',
defaultValue: currentPrefs?.defaultAssetOutputDir ?? './assets'
});
if ((0, prompts_1.isCancel)(defaultAssetOutputDir))
return;
await session_manager_1.sessionManager.updateAssetPreferences({
defaultAssetTypes: defaultAssetTypes,
defaultAssetFormats: defaultAssetFormats,
defaultAssetOutputDir: defaultAssetOutputDir
});
(0, prompts_1.note)('✅ Asset preferences updated successfully!', 'Success');
}
/**
* Configure BRR audio preferences
*/
async configureBRRPreferences() {
const currentPrefs = session_manager_1.sessionManager.getBRRPreferences();
const defaultSampleRate = await (0, prompts_1.text)({
message: 'Default sample rate for BRR decoding (Hz):',
placeholder: '32000',
defaultValue: (currentPrefs?.defaultSampleRate ?? 32000).toString(),
validate: (value) => {
const num = parseInt(value);
if (isNaN(num) || num < 1000 || num > 96000) {
return 'Please enter a sample rate between 1000 and 96000 Hz';
}
return undefined;
}
});
if ((0, prompts_1.isCancel)(defaultSampleRate))
return;
const enableLooping = await (0, prompts_1.confirm)({
message: 'Enable BRR loop processing by default?',
initialValue: currentPrefs?.enableLooping !== false
});
if ((0, prompts_1.isCancel)(enableLooping))
return;
const maxSamples = await (0, prompts_1.text)({
message: 'Maximum samples to decode:',
placeholder: '1000000',
defaultValue: (currentPrefs?.maxSamples ?? 1000000).toString(),
validate: (value) => {
const num = parseInt(value);
if (isNaN(num) || num < 1000) {
return 'Please enter a number of at least 1000 samples';
}
return undefined;
}
});
if ((0, prompts_1.isCancel)(maxSamples))
return;
const defaultOutputFormat = await (0, prompts_1.select)({
message: 'Default output format for BRR decoding:',
options: [
{ value: 'wav', label: 'WAV', hint: 'Standard WAV format' },
{ value: 'flac', label: 'FLAC', hint: 'Lossless compression' }
],
initialValue: currentPrefs?.defaultOutputFormat ?? 'wav'
});
if ((0, prompts_1.isCancel)(defaultOutputFormat))
return;
await session_manager_1.sessionManager.updateBRRPreferences({
defaultSampleRate: parseInt(defaultSampleRate),
enableLooping: enableLooping,
maxSamples: parseInt(maxSamples),
defaultOutputFormat: defaultOutputFormat
});
(0, prompts_1.note)('✅ BRR preferences updated successfully!', 'Success');
}
/**
* Configure analysis preferences
*/
async configureAnalysisPreferences() {
const currentPrefs = session_manager_1.sessionManager.getAnalysisPreferences();
const defaultAnalysisTypes = await (0, prompts_1.multiselect)({
message: 'Default analysis types to run:',
options: [
{ value: 'functions', label: '📊 Function Analysis', hint: 'Detect and analyze functions' },
{ value: 'data-structures', label: '📋 Data Structure Analysis', hint: 'Identify data patterns' },
{ value: 'cross-references', label: '🔗 Cross References', hint: 'Track code relationships' },
{ value: 'quality-report', label: '📈 Quality Report', hint: 'Generate code quality metrics' },
{ value: 'ai-patterns', label: '🤖 AI Pattern Recognition', hint: 'Use AI for pattern detection' }
],
required: false,
initialValues: currentPrefs?.defaultAnalysisTypes ?? []
});
if ((0, prompts_1.isCancel)(defaultAnalysisTypes))
return;
const defaultAnalysisOutputDir = await (0, prompts_1.text)({
message: 'Default analysis output directory:',
placeholder: './analysis',
defaultValue: currentPrefs?.defaultAnalysisOutputDir ?? './analysis'
});
if ((0, prompts_1.isCancel)(defaultAnalysisOutputDir))
return;
const generateHtmlReports = await (0, prompts_1.confirm)({
message: 'Generate HTML reports by default?',
initialValue: currentPrefs?.generateHtmlReports !== false
});
if ((0, prompts_1.isCancel)(generateHtmlReports))
return;
const includeQualityMetrics = await (0, prompts_1.confirm)({
message: 'Include quality metrics in analysis?',
initialValue: currentPrefs?.includeQualityMetrics !== false
});
if ((0, prompts_1.isCancel)(includeQualityMetrics))
return;
await session_manager_1.sessionManager.updateAnalysisPreferences({
defaultAnalysisTypes: defaultAnalysisTypes,
defaultAnalysisOutputDir: defaultAnalysisOutputDir,
generateHtmlReports: generateHtmlReports,
includeQualityMetrics: includeQualityMetrics
});
(0, prompts_1.note)('✅ Analysis preferences updated successfully!', 'Success');
}
/**
* Configure output format preferences
*/
async configureFormatPreferences() {
const currentPrefs = session_manager_1.sessionManager.getFormatPreferences();
const formatOptions = await (0, prompts_1.multiselect)({
message: 'Default output format options:',
options: [
{ value: 'includeComments', label: 'Include Comments', hint: 'Add explanatory comments' },
{ value: 'prettyPrint', label: 'Pretty Print', hint: 'Format output for readability' },
{ value: 'generateSymbols', label: 'Generate Symbols', hint: 'Create symbol files' },
{ value: 'useCustomLabels', label: 'Use Custom Labels', hint: 'Apply custom label files' }
],
required: false,
initialValues: [
...(currentPrefs?.includeComments !== false ? ['includeComments'] : []),
...(currentPrefs?.prettyPrint !== false ? ['prettyPrint'] : []),
...(currentPrefs?.generateSymbols !== false ? ['generateSymbols'] : []),
...(currentPrefs?.useCustomLabels !== false ? ['useCustomLabels'] : [])
]
});
if ((0, prompts_1.isCancel)(formatOptions))
return;
const options = formatOptions;
await session_manager_1.sessionManager.updateFormatPreferences({
includeComments: options.includes('includeComments'),
prettyPrint: options.includes('prettyPrint'),
generateSymbols: options.includes('generateSymbols'),
useCustomLabels: options.includes('useCustomLabels')
});
(0, prompts_1.note)('✅ Format preferences updated successfully!', 'Success');
}
/**
* Configure UI preferences
*/
async configureUIPreferences() {
const currentPrefs = session_manager_1.sessionManager.getUIPreferences();
const uiOptions = await (0, prompts_1.multiselect)({
message: 'UI/UX preferences:',
options: [
{ value: 'preferInteractiveMode', label: 'Prefer Interactive Mode', hint: 'Launch interactive mode by default' },
{ value: 'showProgressBars', label: 'Show Progress Bars', hint: 'Display operation progress' },
{ value: 'colorOutput', label: 'Colored Output', hint: 'Use colors in terminal output' },
{ value: 'compactOutput', label: 'Compact Output', hint: 'Use condensed output format' },
{ value: 'autoSaveResults', label: 'Auto-save Results', hint: 'Automatically save analysis results' }
],
required: false,
initialValues: [
...(currentPrefs?.preferInteractiveMode ? ['preferInteractiveMode'] : []),
...(currentPrefs?.showProgressBars !== false ? ['showProgressBars'] : []),
...(currentPrefs?.colorOutput !== false ? ['colorOutput'] : []),
...(currentPrefs?.compactOutput ? ['compactOutput'] : []),
...(currentPrefs?.autoSaveResults ? ['autoSaveResults'] : [])
]
});
if ((0, prompts_1.isCancel)(uiOptions))
return;
const options = uiOptions;
await session_manager_1.sessionManager.updateUIPreferences({
preferInteractiveMode: options.includes('preferInteractiveMode'),
showProgressBars: options.includes('showProgressBars'),
colorOutput: options.includes('colorOutput'),
compactOutput: options.includes('compactOutput'),
autoSaveResults: options.includes('autoSaveResults')
});
(0, prompts_1.note)('✅ UI preferences updated successfully!', 'Success');
}
/**
* Configure AI preferences
*/
async configureAIPreferences() {
const currentPrefs = session_manager_1.sessionManager.getAIPreferences();
const enableAIFeatures = await (0, prompts_1.confirm)({
message: 'Enable AI features globally?',
initialValue: currentPrefs?.enableAIFeatures !== false
});
if ((0, prompts_1.isCancel)(enableAIFeatures))
return;
if (!enableAIFeatures) {
await session_manager_1.sessionManager.updateAIPreferences({
enableAIFeatures: false
});
(0, prompts_1.note)('✅ AI features disabled globally.', 'Success');
return;
}
const aiConfidenceThreshold = await (0, prompts_1.text)({
message: 'AI confidence threshold (0.0-1.0):',
placeholder: '0.7',
defaultValue: (currentPrefs?.aiConfidenceThreshold ?? 0.7).toString(),
validate: (value) => {
const num = parseFloat(value);
if (isNaN(num) || num < 0 || num > 1) {
return 'Please enter a number between 0.0 and 1.0';
}
return undefined;
}
});
if ((0, prompts_1.isCancel)(aiConfidenceThreshold))
return;
const aiOptions = await (0, prompts_1.multiselect)({
message: 'AI feature options:',
options: [
{ value: 'useContextualNaming', label: 'Contextual Naming', hint: 'Use AI for smart naming' },
{ value: 'generateAIDocumentation', label: 'AI Documentation', hint: 'Generate AI-powered docs' }
],
required: false,
initialValues: [
...(currentPrefs?.useContextualNaming !== false ? ['useContextualNaming'] : []),
...(currentPrefs?.generateAIDocumentation !== false ? ['generateAIDocumentation'] : [])
]
});
if ((0, prompts_1.isCancel)(aiOptions))
return;
const options = aiOptions;
await session_manager_1.sessionManager.updateAIPreferences({
enableAIFeatures: true,
aiConfidenceThreshold: parseFloat(aiConfidenceThreshold),
useContextualNaming: options.includes('useContextualNaming'),
generateAIDocumentation: options.includes('generateAIDocumentation')
});
(0, prompts_1.note)('✅ AI preferences updated successfully!', 'Success');
}
/**
* Handle import/export operations
*/
async handleImportExport() {
const action = await (0, prompts_1.select)({
message: 'Import/Export preferences:',
options: [
{ value: 'export', label: '📤 Export Preferences', hint: 'Save preferences to file' },
{ value: 'import', label: '📥 Import Preferences', hint: 'Load preferences from file' }
]
});
if ((0, prompts_1.isCancel)(action))
return;
if (action === 'export') {
const exportPath = await (0, prompts_1.text)({
message: 'Export file path:',
placeholder: './snes-disasm-preferences.json',
defaultValue: './snes-disasm-preferences.json'
});
if ((0, prompts_1.isCancel)(exportPath))
return;
try {
await session_manager_1.sessionManager.exportPreferences(exportPath);
(0, prompts_1.note)(`✅ Preferences exported to: ${exportPath}`, 'Success');
}
catch (error) {
(0, prompts_1.note)(`❌ Export failed: ${error instanceof Error ? error.message : error}`, 'Error');
}
}
else {
const importPath = await (0, prompts_1.text)({
message: 'Import file path:',
placeholder: './snes-disasm-preferences.json',
validate: (value) => {
if (!value)
return 'File path is required';
// Basic validation - could be enhanced with file existence check
return undefined;
}
});
if ((0, prompts_1.isCancel)(importPath))
return;
const confirmImport = await (0, prompts_1.confirm)({
message: 'This will overwrite your current preferences. Continue?'
});
if ((0, prompts_1.isCancel)(confirmImport) || !confirmImport)
return;
try {
await session_manager_1.sessionManager.importPreferences(importPath);
(0, prompts_1.note)(`✅ Preferences imported from: ${importPath}`, 'Success');
}
catch (error) {
(0, prompts_1.note)(`❌ Import failed: ${error instanceof Error ? error.message : error}`, 'Error');
}
}
}
/**
* Reset preferences to defaults
*/
async resetPreferences() {
const confirmReset = await (0, prompts_1.confirm)({
message: 'Are you sure you want to reset all preferences to defaults? This cannot be undone.'
});
if ((0, prompts_1.isCancel)(confirmReset) || !confirmReset)
return;
await session_manager_1.sessionManager.resetPreferences();
(0, prompts_1.note)('✅ All preferences have been reset to defaults.', 'Success');
}
}
exports.PreferencesManager = PreferencesManager;
// Export singleton instance
exports.preferencesManager = new PreferencesManager();
//# sourceMappingURL=preferences-manager.js.map