- Add temporal awareness and stat decay rules to prompt (0-5% per message)
- Add 'Always Include Attributes' toggle in tracker editor
- Fix skills section editing (was not saving customFields)
- Improve Present Characters parser to handle malformed formats (mid-line chars, extra blank lines)
- All changes work in both together/separate generation modes
- Skip UI initialization entirely when extension is disabled on page load
- Remove all UI elements (panel, buttons) from DOM when disabling extension
- Recreate full UI when re-enabling extension
- Hide mobile toggle button on desktop viewports (>1000px)
- Show/hide mobile toggle based on viewport size transitions
- Ensures clean state management for extension enable/disable
Quests were bleeding through from other chats because loadChatData()
wasn't resetting them when switching to a chat without RPG data.
When loading a chat with no rpg_companion metadata, the function now
resets quests to empty state (main: 'None', optional: []) along with
other tracker data. This ensures each chat maintains its own quest
state independently.
Fixed issues when AI generates multiple character variants (e.g.,
storyteller mode with 'Dottore (Prime)', 'Dottore (Beta)', etc.):
1. Escape quotes in character names to prevent HTML attribute breakage
- Added escapeHtmlAttr() helper function
- Prevents names like 'Marianna "Mari"' from breaking HTML
2. Restore avatar lookup for character variants
- namesMatch() now strips parentheses and quotes from both sides
- Allows 'Dottore (Prime)' to find 'Dottore' character card avatar
- Each variant still gets its own card with separate attributes
3. Multiple characters now display correctly in panel
- Each variant creates its own character object
- Attributes (Details, Relationship, Stats, Thoughts) don't mix
- All characters appear in the panel, not just the last one
- Move Refresh RPG Info button into rpg-settings-buttons-row
- Add rpg-btn-half class to both buttons for equal width distribution
- Conserves vertical space in the hamburger menu
- Buttons now display side-by-side with flex layout
- Add .rpg-attr-name styling to match .rpg-stat-name
- Use SmartTheme colors instead of default white background
- Add focus state with highlight border
- Include .rpg-attr-toggle and .rpg-attr-remove in selectors
Fixes white background on RPG attribute text inputs (STR, DEX, etc.)
in the Tracker Editor modal.
- Fix stripBrackets() removing Skills section header
- Add structural header whitelist (Skills, Status, Inventory, etc.)
- Implement smart look-ahead to detect content below labels
- Previous logic incorrectly removed 'Skills:' when followed by category labels
- Add proper theming to category action buttons (.rpg-category-action)
- Match styling of view toggle buttons
- Use SmartTheme colors for better visibility
- Fix RPG attributes styling in Tracker Editor
- Change background from --rpg-accent to --SmartThemeBlurTintColor
- Update border to match other themed inputs
Resolves issue where skills with categories were all showing as 'Uncategorized'
due to the Skills section being truncated during parsing.
Add detailed logging to trace Skills section through code block extraction.
New logs in parseResponse:
- Log each code block's content length
- Check if code block contains 'Skills:'
- If yes, show 200 chars of text around Skills section
- This runs BEFORE the content is categorized as userStats/infoBox/etc
This will show us:
1. Is Skills section in the extracted code block?
2. At what point does it get truncated?
3. Is it a code block extraction issue or later processing?
Related: Skills categorization debugging
Add verbose debug logging to trace why Skills section extraction is failing.
Logs added:
- Whether statsText is provided
- Text length and if it contains 'Skills:'
- Whether main regex matched
- If 'On Person:' exists (lookahead target)
- 200 chars of text around Skills section
- Whether simple format fallback matched
- Captured text length when successful
This will help diagnose why parser logs show 'Skills extraction failed'
even when Skills section clearly exists in the text.
Related: Skills categorization issue investigation
Add detailed console logging to trace how skills are being parsed and
categorized. This will help diagnose why skills are ending up in
"Uncategorized" instead of their proper categories.
Debug logs added:
- Log all lines extracted from skills section
- Log when category headers are detected
- Log when category arrays are created
- Log when skills are added to categories vs uncategorized
- Log ERROR when skill can't be added due to missing category array
- Log final skills data structure with category counts
Fallback behavior:
- If skill can't be added to its category (category array doesn't exist),
fall back to uncategorized with ERROR log
To see logs:
- Enable Debug Mode in RPG Companion settings
- Check browser console during AI response parsing
- Look for "[RPG Parser]" prefix
Related: Skills categorization issue investigation
Parser was only matching numeric levels "(Lv 5)" but AI was returning
text proficiencies like "(Proficient)", "(Advanced)", causing all skills
to be ignored and not categorized.
Changes to parser.js:
- Add fallback regex to match text proficiency format: "- Skill (Proficient)"
- Map text proficiencies to numeric levels:
- Initiated/Novice → Lv 1
- Basic/Beginner → Lv 2
- Intermediate → Lv 4
- Proficient → Lv 5
- Competent → Lv 6
- Advanced → Lv 7
- Expert → Lv 8
- Mastered/Master → Lv 9
- Grandmaster/Legendary → Lv 10
- Default to Lv 5 for unrecognized proficiency text
- Try numeric format first, fall back to text format
Changes to promptBuilder.js:
- Make prompt instructions more explicit about numeric format
- Add negative examples: "write 'Lv 5' not 'Proficient'"
- Add guidance: "1=novice, 5=intermediate, 10=expert"
- Emphasize with "IMPORTANT:" prefix
Benefits:
- Parser now handles both formats (backward compatible)
- AI has clearer instructions to use numeric levels
- Skills with text proficiencies now parse correctly and show in categories
- Existing numeric format continues to work
Issue Resolution:
- Skills like "Demonic Qi Manipulation (Proficient)" now parse as Lv 5
- Categories like "Demonic Arts:", "Combat:", "Social:" now populate correctly
- Widget displays skills organized by category instead of ignoring them
Related: Skills widget, AI tracker integration
Remove duplicate "Edit Trackers" button from hamburger menu since there's
already a Tracker Settings button in the dashboard header.
Changes:
- Removed "Edit Trackers" button from template.html hamburger menu
- Updated Settings button to full width (removed .rpg-btn-half class)
- Changed dashboard button ID from 'rpg-dashboard-tracker-settings' to
'rpg-open-tracker-editor' to become the canonical button
- Removed redundant event handler in dashboardIntegration.js that was
clicking the old hamburger button
Benefits:
- Reduces UI clutter in hamburger menu
- Single source of truth for Tracker Settings button (dashboard header)
- Existing code in trackerEditor.js, infoBoxWidgets.js continues to work
via jQuery event delegation on ID 'rpg-open-tracker-editor'
Technical Notes:
- jQuery delegation $(document).on('click', '#rpg-open-tracker-editor', ...)
works for any element with that ID, not just a specific one
- No changes needed to trackerEditor.js or widget disabled state handlers
- Dashboard button is now the canonical "Edit Trackers" trigger
Related: Hamburger menu UI, dashboard header controls
Show helpful message when Recent Events tracking is disabled in tracker config.
Changes:
- Check if recentEvents is enabled in trackerConfig before rendering
- If disabled, show dimmed widget with overlay message:
- Info icon + explanation text
- "Enable in Tracker Settings" button
- Button opens Tracker Settings and switches to Info Box tab
UX Improvements:
- Widget opacity reduced to 0.6 to indicate disabled state
- Message centered with clear visual hierarchy
- Button has hover/active states with elevation feedback
- Clicking button directly navigates to the right settings location
Technical Implementation:
- attachDisabledStateHandlers() opens Tracker Settings modal
- Auto-switches to Info Box tab after 100ms delay
- Graceful fallback if button not found (console warning)
CSS Additions:
- .rpg-widget-disabled: Dimmed overlay state
- .rpg-widget-disabled-message: Centered message container
- .rpg-widget-enable-btn: Styled action button with hover effects
Benefits:
- Users immediately understand why Recent Events isn't updating
- One-click access to fix the issue
- Clear visual feedback about widget state
- Pattern can be reused for other widgets (Skills, etc.)
Next Steps:
- Apply this pattern to other widgets that depend on tracker config
- Consider adding similar disabled states for Skills, Stats, etc.
Related: Recent Events widget implementation, tracker config system
Add comprehensive Skills widget to dashboard system with category organization,
XP tracking, level progression, and multiple view modes.
Widget Features:
- Three sub-tabs: All Skills, By Category, Quick View
- Level-up and level-down buttons for manual progression
- XP progress bars with visual feedback
- Search and filter functionality
- Category collapse/expand in By Category view
- Editable skill names and categories
- Delete skills and categories
- Add new skills and categories
- Configurable max level and XP display
UI Improvements:
- Scrollable content area for large skill lists
- Responsive card layout
- Shortened tab labels for compact display ("All", "Quick" vs "All Skills", "Quick View")
- Proper flex layout for skill names (no longer truncated)
- Level badges and action buttons
Technical Implementation:
- Event handler deduplication to prevent exponential level-up bug
- Flag-based handler attachment: container.dataset.handlersAttached
- Nested flex containers for proper space distribution
- Scrollable views wrapper matching Inventory/Quests pattern
Dashboard Integration:
- Added Skills tab to defaultLayout.js (tab 5)
- Icon: fa-solid fa-book (fixed invalid fa-book-sparkles)
- Dimensions: 3x7 grid cells
- Default config: All Skills tab, show XP, show categories
- Auto-arrange support in dashboardManager.js
- Skills category group with priority order 6
- Auto-creates Skills tab when skills widgets detected
- Widget registration in dashboardIntegration.js
Widget Files:
- src/systems/dashboard/widgets/userSkillsWidget.js (new)
- Full widget implementation with all sub-tabs and features
- State management with Map-based storage
- Category-based and flat views
- Search/filter/sort functionality
Styling:
- style.css: Added skills widget styles
- Skill cards, headers, action buttons
- Level-down button with accent color
- XP progress bars
- Category sections
Fixes from iteration:
1. Invalid FontAwesome icon (fa-book-sparkles → fa-book)
2. Tab labels too wide (shortened to single words)
3. Skill names truncated (fixed with proper flex structure)
4. Widget height incorrect (adjusted to h:7)
5. Level-up exponential bug (duplicate handlers, added flag guard)
6. No level-down button (added with minimum level 1)
7. No scrollbar on long lists (added .rpg-skills-views wrapper)
Category: skills
Integration: Fully integrated with dashboard v2.0 system
Tested: Layout, interactions, scrolling, level progression
Refs: AI tracker integration (separate commit)
Add AI tracker awareness for skills system with proper level and category support.
Changes:
- Add extractSkills() parser function to extract structured skills data
- Parses category-based format: "CategoryName:\n- SkillName (Lv X)"
- Falls back to legacy string format for backward compatibility
- Returns structured data: { version: 1, categories: {}, uncategorized: [] }
- Update prompt instructions to request structured skills format
- AI now generates: "Skills:\nCombat:\n- Swordsmanship (Lv 5)"
- Supports multiple categories (Combat, Magic, Social, Crafting, etc.)
- Includes Uncategorized section for skills without clear category
- Add buildSkillsSummary() utility function
- Converts structured skills data back to formatted text
- Ready for future feature: syncing manual skill edits to AI context
Parser integration:
- parseUserStats() now uses extractSkills() to parse Skills section
- Stores structured data in extensionSettings.userStats.skills
- Widget reads structured data for display and level-up/down functionality
AI workflow:
1. AI generates skills in structured format (via prompt instructions)
2. Parser extracts to structured data (via extractSkills)
3. Widget displays with level controls (already implemented)
4. Raw text flows through committedTrackerData to next generation
Note: Manual skill edits (level-up/down in widget) are not yet synced back
to AI context. This requires additional work to regenerate the raw text
when skills are manually modified. buildSkillsSummary is ready for this.
Refs: Skills widget implementation (previous session)
The green settings icon that appeared on widget hover during edit mode
was not connected to any functionality. Removed to simplify UI.
- Delete button (red X) remains functional
- Edit mode drag/drop and resize unaffected
Refactored loadLayout() to call resetLayout() for first-run users instead of
duplicating setup logic inline. This provides a single source of truth for
"set to default layout" behavior.
Previous Approach (Problems):
- loadLayout() had ~40 lines of inline first-run setup
- Different behavior: used autoLayout (repositions widgets)
- Less comprehensive: no state reset, different persistence method
- Code duplication between loadLayout() and resetLayout()
- Error handler also duplicated applyDashboardConfig() logic
- Emergency fallback tab creation needed after load
New Approach (Benefits):
- loadLayout() is now a simple router: saved layout vs. reset
- Consistent behavior: first-run and manual reset use same code path
- More comprehensive: fresh layout generation, state reset, validation
- Better error recovery: always uses resetLayout() for clean state
- Single source of truth for default layout initialization
- ~40 lines removed, cleaner code
Changes:
1. Removed inline applyDashboardConfig(defaultLayout) for first run
2. Removed manual autoLayout() loop (lines 1489-1494)
3. Removed manual saveLayout() call (line 1497)
4. Removed error handler's inline applyDashboardConfig()
5. Removed emergency fallback tab creation (lines 1506-1520)
6. Added resetLayout() call for first run (line 1494)
7. Added resetLayout() call for error recovery (line 1500)
Result:
- First-run users get comprehensive setup via resetLayout()
- Preserves default positions (doesn't reposition with autoLayout)
- Consistent layout behavior across first-run and manual reset
- Better maintainability (single code path for default setup)
- Proven reliability (resetLayout already works in production)
Fixed bug where the lock/unlock button's icon and title didn't update when
toggling lock state outside of edit mode. The logical state changed correctly
(widgets locked/unlocked), but the button appearance remained stale.
Root Cause:
- toggleLock() correctly updates the button element
- When in dropdown/menu mode (narrow screens), menu items are static snapshots
- Edit mode toggle refreshed the menu (via headerOverflowManager.refresh())
- Lock button toggle did NOT refresh the menu
- Result: stale button appearance in dropdown menus
Solution:
- Added headerOverflowManager.refresh() call after toggleLock()
- Follows the exact same pattern as edit mode toggle (lines 323-326)
- Uses setTimeout(50ms) to ensure DOM updates complete first
Changes:
- src/systems/dashboard/dashboardIntegration.js (lines 338-341)
Added 4 lines to refresh menu after lock state change
Result:
Lock button now correctly updates its visual state (icon: lock/lock-open,
title: "Lock Widgets"/"Unlock Widgets") whether in edit mode or not, and
whether visible directly or in dropdown/hamburger menus.
Fixed critical initialization timing bug where new users saw a blank screen
with error "Tab not found: main" when migrating from v1.x to v2.0.
Root Cause:
- dashboardManager.init() created a premature fallback "main" tab before
loading the default layout
- TabManager was initialized with activeTabId='main'
- loadLayout() then replaced tabs with proper IDs ('tab-status', etc.)
- TabManager still referenced the non-existent 'main' tab
- Result: blank screen
Changes:
1. Removed premature fallback tab creation (lines 189-198)
- Default layout is always set via setDefaultLayout() before init()
- No need to create "main" tab before layout loads
2. Added safety check after loadLayout() completes (line 1506-1520)
- If no tabs exist after loading, create emergency fallback
- Uses correct tab ID 'tab-status' instead of 'main'
- Updates TabManager's activeTab to match
Flow now:
- init() creates TabManager with empty tabs
- loadLayout() populates tabs from default or saved layout
- Safety check ensures at least one tab exists
- TabManager references only valid tab IDs
Fixes blank screen bug for users migrating from v1.x to v2.0.
Resolves overlap issue between long character names and level indicator
in 1x2 userInfo widgets. Level now displays at top-right corner flush
with container, while name remains at bottom with full width available.
- Changed level container position from bottom: 0 to top: 0
- Prevents text overlap for names like 'Seol Yi-hwan Lvl 1'
- Maintains clean, compact layout at 1080p and other resolutions
UserInfo Widget:
- Changed from column-based to mobile detection (window.innerWidth <= 1000)
- Desktop narrow (2-col) now correctly uses 1x2 instead of 1x1
- Mobile devices still use 1x1 compact mode with round avatar
- Ensures vertical layout at all desktop widths
PresentCharacters Widget:
- Changed maxAutoSize to match defaultSize (3x2 on desktop)
- Prevents auto-expansion to 3 rows during layout
- Stays at 2 rows to fit 1080p screens without scrolling
Fixes responsive sizing issues on desktop narrow panels.
Modified autoLayoutCurrentTab() and autoLayoutWidgets() to detect when
widgets match the default layout and apply the exact positions from
defaultLayout.js instead of using the gridEngine.autoLayout packing
algorithm.
This ensures that:
- "Reset Layout" button uses default positions
- "Auto Arrange All Widgets" button uses default positions (if widgets match)
- "Sort Current Page" button uses default positions (if widgets match)
All three operations now produce identical layouts for the default widget set.
Changes:
- Added tryApplyDefaultLayoutToTab() helper for single tab layout
- Added tryApplyDefaultLayout() helper for all tabs layout
- Modified autoLayoutCurrentTab() to try default layout first
- Modified autoLayoutWidgets() to try default layout first
- Falls back to gridEngine.autoLayout for custom widgets
Fixes responsive dashboard layout consistency.