From 0fcd7c2c5fda991c71b811e0bab7d01e06fd1284 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 9 Jul 2026 21:32:31 +0000 Subject: [PATCH 1/5] Initial plan From 11d7c3233e1164ccfca1da44b20e390f18bdb86c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 9 Jul 2026 21:41:40 +0000 Subject: [PATCH 2/5] Initial plan for healthstone cooldown fix Co-authored-by: argium <15852038+argium@users.noreply.github.com> --- .serena/project.yml | 76 +++++++++++++++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 23 deletions(-) diff --git a/.serena/project.yml b/.serena/project.yml index b12baabb..ff71efd3 100644 --- a/.serena/project.yml +++ b/.serena/project.yml @@ -1,26 +1,31 @@ -# the name by which the project can be referenced within Serena +# the name by which the project can be referenced within Serena/when chatting with the LLM. project_name: "EnhancedCooldownManager" - -# list of languages for which language servers are started; choose from: -# al ansible bash clojure cpp -# cpp_ccls crystal csharp csharp_omnisharp dart -# elixir elm erlang fortran fsharp +# list of languages for which language servers are started (LSP backend only); choose from: +# ada al angular ansible bash +# bsl clojure cpp cpp_ccls crystal +# csharp csharp_omnisharp cue dart elixir +# elm erlang fortran fsharp gdscript # go groovy haskell haxe hlsl -# java json julia kotlin lean4 -# lua luau markdown matlab msl -# nix ocaml pascal perl php -# php_phpactor powershell python python_jedi python_ty -# r rego ruby ruby_solargraph rust -# scala solidity swift systemverilog terraform -# toml typescript typescript_vts vue yaml -# zig -# (This list may be outdated. For the current list, see values of Language enum here: -# https://github.com/oraios/serena/blob/main/src/solidlsp/ls_config.py -# For some languages, there are alternative language servers, e.g. csharp_omnisharp, ruby_solargraph.) +# html java json julia kotlin +# latex lean4 lua luau markdown +# matlab msl nix ocaml pascal +# perl php php_phpactor php_phpantom powershell +# python python_jedi python_pyrefly python_ty r +# rego ruby ruby_solargraph rust scala +# scss solidity svelte swift systemverilog +# terraform toml typescript typescript_vts vue +# yaml zig +# (This list may be outdated; generated with scripts/print_language_list.py; +# For the current list, see values of Language enum here: +# https://github.com/oraios/serena/blob/main/src/solidlsp/ls_config.py) +# For some languages, there are alternative language servers, e.g. csharp_omnisharp, ruby_solargraph.) # Note: # - For C, use cpp # - For JavaScript, use typescript +# - For Angular projects, use angular (subsumes typescript+html; requires `npm install` in the project root) +# - For Svelte projects, use svelte (subsumes typescript/javascript for .svelte projects; requires npm) +# - For SCSS / Sass / plain CSS, use scss (some-sass-language-server handles all three) # - For Free Pascal/Lazarus, use pascal # Special requirements: # Some languages require additional setup/installations. @@ -117,8 +122,8 @@ ignored_memory_patterns: [] # advanced configuration option allowing to configure language server-specific options. # Maps the language key to the options. -# Have a look at the docstring of the constructors of the LS implementations within solidlsp (e.g., for C# or PHP) to see which options are available. -# No documentation on options means no options are available. +# The settings are considered only if the project is trusted (see global configuration to define trusted projects). +# See https://oraios.github.io/serena/02-usage/050_configuration.html#language-server-specific-settings ls_specific_settings: {} # list of mode names to be activated additionally for this project, e.g. ["query-projects"] @@ -126,13 +131,38 @@ ls_specific_settings: {} # See https://oraios.github.io/serena/02-usage/050_configuration.html#modes added_modes: -# list of additional workspace folder paths for cross-package reference support (e.g. in monorepos). +# list of additional workspace folder paths for cross-package reference support. # Paths can be absolute or relative to the project root. # Each folder is registered as an LSP workspace folder, enabling language servers to discover -# symbols and references across package boundaries. -# Currently supported for: TypeScript. +# symbols and references across package boundaries, but these folders are not indexed by Serena, +# i.e. the respective symbols will not be found using Serena's symbol search tools. # Example: # additional_workspace_folders: # - ../sibling-package # - ../shared-lib -additional_workspace_folders: [] +ls_additional_workspace_folders: [] + +# list of workspace folder paths (LSP backend only). +# These folders will be used to build up Serena's symbol index. +# Paths must be within the project root and should thus be relative to the project root. +# Furthermore, the paths should not be filtered by ignore settings. +# Default setting: The entire project root folder (".") is considered. +# In (large) monorepos, this can be used to index only subfolders of the project root, e.g. +# ls_workspace_folders: +# - "./subproject1" +# - "./subproject2" +ls_workspace_folders: +- . + +# optional shell command to run before the language backend (LSP or JetBrains) is initialised. +# the command runs in the project root directory and is only executed if the project is trusted +# (see trusted_project_path_patterns in the global configuration). +# serena waits for the command to exit: a non-zero exit code is logged as an error but does not +# abort activation. a per-project timeout (activation_command_timeout, default 180s) is the safety +# backstop for non-terminating commands; on expiry the process is killed and activation continues. +# example: activation_command: "npx nx run-many -t build" +activation_command: + +# maximum time in seconds to wait for activation_command to complete before killing it (default 180s). +# must be a positive number. +activation_command_timeout: 180.0 From c6573dfe8246e7d492ea14651dec53aa1141ed13 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 9 Jul 2026 21:45:08 +0000 Subject: [PATCH 3/5] Fix healthstone cooldown not shown during combat (#111) - resolveFirstItem: show icon as missing (greyed) when item has an active cooldown, regardless of showIfMissing setting. Fixes the root cause: consumed items (count = 0) now remain visible with their cooldown timer, matching UX for potions that have multiple charges. - OnBagUpdateCooldown: also call RequestLayout so the layout is re-evaluated when any item cooldown changes, ensuring icons are properly hidden once the cooldown clears and the item is still absent. - Tests: three new cases covering the new behaviour and the preserved hide-when-no-cooldown path. Co-authored-by: argium <15852038+argium@users.noreply.github.com> --- Modules/ExtraIcons.lua | 10 ++++-- Tests/Modules/ExtraIcons_spec.lua | 57 +++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/Modules/ExtraIcons.lua b/Modules/ExtraIcons.lua index 5c96a7d4..da0401d9 100644 --- a/Modules/ExtraIcons.lua +++ b/Modules/ExtraIcons.lua @@ -74,9 +74,14 @@ local function resolveFirstItem(ids, showIfMissing) if C_Item.GetItemCount(itemId) > 0 then local texture = C_Item.GetItemIconByID(itemId) if texture then return { itemId = itemId, texture = texture } end - elseif showIfMissing and not missingData then + elseif not missingData then local texture = C_Item.GetItemIconByID(itemId) - if texture then missingData = { itemId = itemId, texture = texture, missing = true } end + if texture then + local _, duration = C_Item.GetItemCooldown(itemId) + if showIfMissing or (duration and duration > 0) then + missingData = { itemId = itemId, texture = texture, missing = true } + end + end end end end @@ -482,6 +487,7 @@ end function ExtraIcons:OnBagUpdateCooldown() self:ThrottledRefresh("OnBagUpdateCooldown") + ns.Runtime.RequestLayout("ExtraIcons:OnBagUpdateCooldown") end function ExtraIcons:OnBagUpdateDelayed() diff --git a/Tests/Modules/ExtraIcons_spec.lua b/Tests/Modules/ExtraIcons_spec.lua index 097d3d8c..bd1ebab7 100644 --- a/Tests/Modules/ExtraIcons_spec.lua +++ b/Tests/Modules/ExtraIcons_spec.lua @@ -641,6 +641,17 @@ describe("ExtraIcons real source", function() assert.same({ "OnBagUpdateCooldown" }, reasons) end) + it("requests layout on bag cooldown change so consumed items hide once cooldown clears", function() + local layoutReasons = {} + ns.Runtime.RequestLayout = function(reason) + layoutReasons[#layoutReasons + 1] = reason + end + + ExtraIcons.InnerFrame = ExtraIcons:CreateFrame() + ExtraIcons:OnBagUpdateCooldown() + assert.same({ "ExtraIcons:OnBagUpdateCooldown" }, layoutReasons) + end) + it("edit mode callbacks toggle state and defer layout", function() local reasons = {} ExtraIcons.InnerFrame = ExtraIcons:CreateFrame() @@ -1513,6 +1524,52 @@ describe("ExtraIcons real source", function() assert.same({ 100, 60 }, ExtraIcons._viewers.utility.iconPool[1].Cooldown.__cooldown) end) + it("shows consumed item stack icon greyed with cooldown when item was just used", function() + local utilityIconChild = TestHelpers.makeFrame({ shown = true, width = 18, height = 18 }) + utilityIconChild.GetSpellID = function() return 1 end + UtilityCooldownViewer.childXPadding = 0 + UtilityCooldownViewer.iconScale = 1 + UtilityCooldownViewer._children = { utilityIconChild } + UtilityCooldownViewer:SetPoint("CENTER", UIParent, "CENTER", 0, 0) + + itemCounts[HEALTHSTONE_ID] = 0 + itemIconsByID[HEALTHSTONE_ID] = "healthstone" + itemCooldownByID[HEALTHSTONE_ID] = { 100, 60, true } + + ExtraIcons.InnerFrame = ExtraIcons:CreateFrame() + ExtraIcons.GetModuleConfig = function() + return makeViewersConfig({ { kind = "itemStack", itemStackId = "healthstones" } }) + end + + assert.is_true(ExtraIcons:UpdateLayout("test")) + local icon = ExtraIcons._viewers.utility.iconPool[1] + assert.are.equal(HEALTHSTONE_ID, icon.itemId) + assert.is_true(icon.Icon:IsDesaturated()) + assert.same({ 100, 60 }, icon.Cooldown.__cooldown) + assert.is_true(ExtraIcons._viewers.utility.container:IsShown()) + end) + + it("hides consumed item stack icon once cooldown expires when showIfMissing is not set", function() + local utilityIconChild = TestHelpers.makeFrame({ shown = true, width = 18, height = 18 }) + utilityIconChild.GetSpellID = function() return 1 end + UtilityCooldownViewer.childXPadding = 0 + UtilityCooldownViewer.iconScale = 1 + UtilityCooldownViewer._children = { utilityIconChild } + UtilityCooldownViewer:SetPoint("CENTER", UIParent, "CENTER", 0, 0) + + itemCounts[HEALTHSTONE_ID] = 0 + itemIconsByID[HEALTHSTONE_ID] = "healthstone" + itemCooldownByID[HEALTHSTONE_ID] = { 0, 0, false } + + ExtraIcons.InnerFrame = ExtraIcons:CreateFrame() + ExtraIcons.GetModuleConfig = function() + return makeViewersConfig({ { kind = "itemStack", itemStackId = "healthstones" } }) + end + + assert.is_false(ExtraIcons:UpdateLayout("test")) + assert.is_false(ExtraIcons._viewers.utility.container:IsShown()) + end) + it("shows item stack counts when enabled", function() local utilityIconChild = TestHelpers.makeFrame({ shown = true, width = 18, height = 18 }) utilityIconChild.GetSpellID = function() return 1 end From 1c604fdd6b68d8b4caed85e5dd424937d344df38 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 9 Jul 2026 22:10:12 +0000 Subject: [PATCH 4/5] Fix charged item handling: consumed items hide, RequestLayout handles charge use - resolveFirstItem: revert to showIfMissing gate only. Consumed items (count=0) are hidden regardless of active cooldown. Only showIfMissing entries remain visible as greyed icons when absent. - OnBagUpdateCooldown: keep RequestLayout call. This is the real fix for use-charge items (Healthstones with multiple charges): BAG_UPDATE_DELAYED does not fire when a charge is consumed but the item stays in the bag, so RequestLayout ensures the layout is re-evaluated and the cooldown shown. - Tests: replace "greyed with cooldown" test (wrong behaviour) with "hidden even with active cooldown" test (correct behaviour); rename RequestLayout test to accurately reflect its purpose. Co-authored-by: argium <15852038+argium@users.noreply.github.com> --- Modules/ExtraIcons.lua | 9 ++------- Tests/Modules/ExtraIcons_spec.lua | 12 ++++-------- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/Modules/ExtraIcons.lua b/Modules/ExtraIcons.lua index da0401d9..98a3e443 100644 --- a/Modules/ExtraIcons.lua +++ b/Modules/ExtraIcons.lua @@ -74,14 +74,9 @@ local function resolveFirstItem(ids, showIfMissing) if C_Item.GetItemCount(itemId) > 0 then local texture = C_Item.GetItemIconByID(itemId) if texture then return { itemId = itemId, texture = texture } end - elseif not missingData then + elseif showIfMissing and not missingData then local texture = C_Item.GetItemIconByID(itemId) - if texture then - local _, duration = C_Item.GetItemCooldown(itemId) - if showIfMissing or (duration and duration > 0) then - missingData = { itemId = itemId, texture = texture, missing = true } - end - end + if texture then missingData = { itemId = itemId, texture = texture, missing = true } end end end end diff --git a/Tests/Modules/ExtraIcons_spec.lua b/Tests/Modules/ExtraIcons_spec.lua index bd1ebab7..d3454991 100644 --- a/Tests/Modules/ExtraIcons_spec.lua +++ b/Tests/Modules/ExtraIcons_spec.lua @@ -641,7 +641,7 @@ describe("ExtraIcons real source", function() assert.same({ "OnBagUpdateCooldown" }, reasons) end) - it("requests layout on bag cooldown change so consumed items hide once cooldown clears", function() + it("requests layout on bag cooldown change so charged item display is re-evaluated", function() local layoutReasons = {} ns.Runtime.RequestLayout = function(reason) layoutReasons[#layoutReasons + 1] = reason @@ -1524,7 +1524,7 @@ describe("ExtraIcons real source", function() assert.same({ 100, 60 }, ExtraIcons._viewers.utility.iconPool[1].Cooldown.__cooldown) end) - it("shows consumed item stack icon greyed with cooldown when item was just used", function() + it("hides consumed item stack icon even when item has active cooldown if showIfMissing is not set", function() local utilityIconChild = TestHelpers.makeFrame({ shown = true, width = 18, height = 18 }) utilityIconChild.GetSpellID = function() return 1 end UtilityCooldownViewer.childXPadding = 0 @@ -1541,12 +1541,8 @@ describe("ExtraIcons real source", function() return makeViewersConfig({ { kind = "itemStack", itemStackId = "healthstones" } }) end - assert.is_true(ExtraIcons:UpdateLayout("test")) - local icon = ExtraIcons._viewers.utility.iconPool[1] - assert.are.equal(HEALTHSTONE_ID, icon.itemId) - assert.is_true(icon.Icon:IsDesaturated()) - assert.same({ 100, 60 }, icon.Cooldown.__cooldown) - assert.is_true(ExtraIcons._viewers.utility.container:IsShown()) + assert.is_false(ExtraIcons:UpdateLayout("test")) + assert.is_false(ExtraIcons._viewers.utility.container:IsShown()) end) it("hides consumed item stack icon once cooldown expires when showIfMissing is not set", function() From 1b2d531bde94cdb05b4a8f6002d2c5a1dafe995a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 9 Jul 2026 22:11:27 +0000 Subject: [PATCH 5/5] Consolidate duplicate consumed-item hidden tests into parameterized loop Co-authored-by: argium <15852038+argium@users.noreply.github.com> --- Tests/Modules/ExtraIcons_spec.lua | 61 +++++++++++-------------------- 1 file changed, 21 insertions(+), 40 deletions(-) diff --git a/Tests/Modules/ExtraIcons_spec.lua b/Tests/Modules/ExtraIcons_spec.lua index d3454991..911a79bc 100644 --- a/Tests/Modules/ExtraIcons_spec.lua +++ b/Tests/Modules/ExtraIcons_spec.lua @@ -1524,47 +1524,28 @@ describe("ExtraIcons real source", function() assert.same({ 100, 60 }, ExtraIcons._viewers.utility.iconPool[1].Cooldown.__cooldown) end) - it("hides consumed item stack icon even when item has active cooldown if showIfMissing is not set", function() - local utilityIconChild = TestHelpers.makeFrame({ shown = true, width = 18, height = 18 }) - utilityIconChild.GetSpellID = function() return 1 end - UtilityCooldownViewer.childXPadding = 0 - UtilityCooldownViewer.iconScale = 1 - UtilityCooldownViewer._children = { utilityIconChild } - UtilityCooldownViewer:SetPoint("CENTER", UIParent, "CENTER", 0, 0) - - itemCounts[HEALTHSTONE_ID] = 0 - itemIconsByID[HEALTHSTONE_ID] = "healthstone" - itemCooldownByID[HEALTHSTONE_ID] = { 100, 60, true } - - ExtraIcons.InnerFrame = ExtraIcons:CreateFrame() - ExtraIcons.GetModuleConfig = function() - return makeViewersConfig({ { kind = "itemStack", itemStackId = "healthstones" } }) - end - - assert.is_false(ExtraIcons:UpdateLayout("test")) - assert.is_false(ExtraIcons._viewers.utility.container:IsShown()) - end) - - it("hides consumed item stack icon once cooldown expires when showIfMissing is not set", function() - local utilityIconChild = TestHelpers.makeFrame({ shown = true, width = 18, height = 18 }) - utilityIconChild.GetSpellID = function() return 1 end - UtilityCooldownViewer.childXPadding = 0 - UtilityCooldownViewer.iconScale = 1 - UtilityCooldownViewer._children = { utilityIconChild } - UtilityCooldownViewer:SetPoint("CENTER", UIParent, "CENTER", 0, 0) - - itemCounts[HEALTHSTONE_ID] = 0 - itemIconsByID[HEALTHSTONE_ID] = "healthstone" - itemCooldownByID[HEALTHSTONE_ID] = { 0, 0, false } - - ExtraIcons.InnerFrame = ExtraIcons:CreateFrame() - ExtraIcons.GetModuleConfig = function() - return makeViewersConfig({ { kind = "itemStack", itemStackId = "healthstones" } }) - end + for _, cd in ipairs({ { 100, 60, true }, { 0, 0, false } }) do + it("hides consumed item stack icon when showIfMissing is not set (cooldown=" .. tostring(cd[3]) .. ")", function() + local utilityIconChild = TestHelpers.makeFrame({ shown = true, width = 18, height = 18 }) + utilityIconChild.GetSpellID = function() return 1 end + UtilityCooldownViewer.childXPadding = 0 + UtilityCooldownViewer.iconScale = 1 + UtilityCooldownViewer._children = { utilityIconChild } + UtilityCooldownViewer:SetPoint("CENTER", UIParent, "CENTER", 0, 0) + + itemCounts[HEALTHSTONE_ID] = 0 + itemIconsByID[HEALTHSTONE_ID] = "healthstone" + itemCooldownByID[HEALTHSTONE_ID] = cd + + ExtraIcons.InnerFrame = ExtraIcons:CreateFrame() + ExtraIcons.GetModuleConfig = function() + return makeViewersConfig({ { kind = "itemStack", itemStackId = "healthstones" } }) + end - assert.is_false(ExtraIcons:UpdateLayout("test")) - assert.is_false(ExtraIcons._viewers.utility.container:IsShown()) - end) + assert.is_false(ExtraIcons:UpdateLayout("test")) + assert.is_false(ExtraIcons._viewers.utility.container:IsShown()) + end) + end it("shows item stack counts when enabled", function() local utilityIconChild = TestHelpers.makeFrame({ shown = true, width = 18, height = 18 })