From a53968c58780b1e980114ddac24c46b1845708f1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 11 May 2026 20:02:30 +0000 Subject: [PATCH 1/4] Initial plan From 1dbc68f8d8191c79344de6185da432451c47ff22 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 11 May 2026 20:05:20 +0000 Subject: [PATCH 2/4] fix: prevent re-installation of explicitly removed skills during refresh Add an `excludes` array to the manifest that tracks skill names the user has explicitly removed via `coldbox ai skills remove`. During `refresh()`, skills in the excludes list are filtered out of `missingDesiredSkills` so they are never auto-reinstalled. When a skill is explicitly re-installed via `coldbox ai skills install`, its name is removed from `excludes` so normal auto-management resumes. - SkillManager.refresh(): initialise excludes section; filter excluded skills from missingDesiredSkills (step 0) - SkillManager.removeSkillFromProject(): append removed skill name to manifest.excludes before saving - SkillManager.installRemoteSkill(): lift exclusion when skill is explicitly re-installed - SkillManager.ensureExcludesSection(): new private helper for backwards-compatible initialisation of manifest.excludes Agent-Logs-Url: https://github.com/ColdBox/coldbox-cli/sessions/92d13e96-d882-4c14-9d67-62579d852353 Co-authored-by: lmajano <137111+lmajano@users.noreply.github.com> --- models/SkillManager.cfc | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/models/SkillManager.cfc b/models/SkillManager.cfc index c64ad8a..cb582fc 100644 --- a/models/SkillManager.cfc +++ b/models/SkillManager.cfc @@ -186,6 +186,9 @@ component singleton { // Ensure customSkills key exists (backwards compatibility with old manifests) ensureCustomSkillsSection( arguments.manifest ) + // Ensure excludes key exists (backwards compatibility with old manifests) + ensureExcludesSection( arguments.manifest ) + // ------------------------------------------------------------------ // 0. Install missing desired skills (core + module) not yet in manifest // ------------------------------------------------------------------ @@ -195,6 +198,10 @@ component singleton { ); var missingDesiredSkills = desiredTargets.filter( ( t ) => { + // Skip skills the user has explicitly excluded + if ( arguments.manifest.excludes.findNoCase( t.name ) ) { + return false + } return !manifest.skills .filter( ( s ) => { return ( s.owner == t.owner && s.repo == t.repo && s.slug == t.slug ); @@ -828,6 +835,13 @@ component singleton { if ( structKeyExists( manifest, "customSkills" ) ) { manifest.customSkills = manifest.customSkills.filter( ( s ) => s.name != name ) } + + // Track the explicit exclusion so refresh() does not auto-reinstall it + ensureExcludesSection( manifest ) + if ( !manifest.excludes.findNoCase( arguments.name ) ) { + manifest.excludes.append( arguments.name ) + } + variables.aiService.saveManifest( arguments.directory, manifest ) return true @@ -1345,6 +1359,10 @@ component singleton { arguments.manifest.skills.append( entry ) } + // If this skill was previously excluded, lift the exclusion now that it is being explicitly installed + ensureExcludesSection( arguments.manifest ) + arguments.manifest.excludes = arguments.manifest.excludes.filter( ( ex ) => !ex.equalsIgnoreCase( resolvedName ) ) + return resolvedName } @@ -1397,6 +1415,20 @@ component singleton { } } + /** + * Ensure manifest has an excludes array (backwards compatibility). + * The excludes array holds skill names that the user explicitly removed and + * should never be auto-reinstalled by refresh(). + * Mutates manifest in place. + * + * @manifest The manifest struct to ensure has an excludes key + */ + private function ensureExcludesSection( required struct manifest ){ + if ( !structKeyExists( arguments.manifest, "excludes" ) ) { + arguments.manifest[ "excludes" ] = [] + } + } + /** * Delete a skill directory under .ai/skills/ if it exists. * From 33ab6abe8e7ab97749c5e9ae626c9eb1f1ffe66a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 11 May 2026 20:06:19 +0000 Subject: [PATCH 3/4] fix: address code review - semicolon consistency and rename closure param Agent-Logs-Url: https://github.com/ColdBox/coldbox-cli/sessions/92d13e96-d882-4c14-9d67-62579d852353 Co-authored-by: lmajano <137111+lmajano@users.noreply.github.com> --- models/SkillManager.cfc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/models/SkillManager.cfc b/models/SkillManager.cfc index cb582fc..dabd32e 100644 --- a/models/SkillManager.cfc +++ b/models/SkillManager.cfc @@ -200,7 +200,7 @@ component singleton { var missingDesiredSkills = desiredTargets.filter( ( t ) => { // Skip skills the user has explicitly excluded if ( arguments.manifest.excludes.findNoCase( t.name ) ) { - return false + return false; } return !manifest.skills .filter( ( s ) => { @@ -1361,7 +1361,7 @@ component singleton { // If this skill was previously excluded, lift the exclusion now that it is being explicitly installed ensureExcludesSection( arguments.manifest ) - arguments.manifest.excludes = arguments.manifest.excludes.filter( ( ex ) => !ex.equalsIgnoreCase( resolvedName ) ) + arguments.manifest.excludes = arguments.manifest.excludes.filter( ( excludedName ) => !excludedName.equalsIgnoreCase( resolvedName ) ) return resolvedName } From 029efb42cbebb1e73913de3ebebfcce6c1359598 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 11 May 2026 20:11:43 +0000 Subject: [PATCH 4/4] docs: add changelog entry for skills remove exclusion fix Agent-Logs-Url: https://github.com/ColdBox/coldbox-cli/sessions/9646a1c2-ec9e-48db-9ef0-4d0d4d75f87a Co-authored-by: lmajano <137111+lmajano@users.noreply.github.com> --- changelog.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/changelog.md b/changelog.md index 3ba6779..0f914e7 100644 --- a/changelog.md +++ b/changelog.md @@ -16,6 +16,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `AIService.diagnose()` now uses the `static.AI_DIR` constant (`.agents`) instead of the hardcoded `/.ai` path - `coldbox ai uninstall` now correctly checks, removes, and references the `.agents` directory - `coldbox ai skills add slug --list` was not working. +- **`coldbox ai skills remove` reinstalling removed skills during refresh** + - When a skill was removed via `coldbox ai skills remove`, the subsequent agent config regeneration step (`refresh()`) would detect the skill as "missing" (because its module dependency was still present in `box.json`) and immediately reinstall it + - Removed skills are now tracked in a new `manifest.excludes[]` array so that `refresh()` will never auto-reinstall them + - Explicitly re-installing a previously excluded skill via `coldbox ai skills install` lifts the exclusion and restores normal auto-management ### Added