@@ -92,12 +92,17 @@ component singleton {
9292 }
9393
9494 /**
95- * Refresh guidelines based on installed modules
95+ * Refresh guidelines - syncs manifest with file system and installed modules
96+ * - Updates module guidelines based on box.json dependencies
97+ * - Syncs custom guidelines from .ai/guidelines/custom/
98+ * - Syncs override guidelines from .ai/guidelines/overrides/
99+ * - Removes manifest entries for deleted files
100+ * - Removes guidelines for uninstalled modules
96101 *
97102 * @directory The project directory
98103 * @manifest The manifest struct to update
99104 */
100- function refresh( required string directory , required struct manifest ){
105+ function refresh( required string directory , required struct manifest ){
101106 var changes = {
102107 " added" : [],
103108 " updated" : [],
@@ -159,10 +164,19 @@ component singleton {
159164 }
160165
161166 // Remove guidelines for uninstalled modules
162- var toRemove = [];
167+ var toRemove = []
163168 for ( var guideline in manifest .guidelines ) {
164- if ( guideline .source ! = " coldbox-cli" && ! structKeyExists ( allDependencies , guideline .source ) ) {
165- toRemove .append ( guideline .name );
169+ var gType = guideline .type ?: " "
170+ var gSource = guideline .source ?: " "
171+
172+ // Don't remove core, custom, or override guidelines
173+ if ( gSource == " coldbox-cli" || gType == " core" || gSource == " user" || gType == " custom" || gType == " override" ) {
174+ continue ;
175+ }
176+
177+ // Remove module guidelines if module no longer installed
178+ if ( ! structKeyExists ( allDependencies , gSource ) ) {
179+ toRemove .append ( guideline .name )
166180 }
167181 }
168182
@@ -171,6 +185,84 @@ component singleton {
171185 changes .removed .append ( name )
172186 } )
173187
188+ // Sync custom guidelines from filesystem
189+ var customDir = " #arguments .directory #/.ai/guidelines/custom"
190+ if ( directoryExists ( customDir ) ) {
191+ var customFiles = directoryList ( customDir , false , " name" , " *.md" )
192+ customFiles .each ( ( fileName ) = > {
193+ var guidelineName = replaceNoCase ( fileName , " .md" , " " )
194+
195+ // Check if in manifest
196+ var existing = manifest .guidelines .filter ( ( g ) = > g .name == guidelineName )
197+ if ( ! existing .len () ) {
198+ // Add to manifest
199+ updateManifestEntry (
200+ manifest ,
201+ guidelineName ,
202+ " custom" ,
203+ " user" ,
204+ variables .utility .getColdboxCliVersion (),
205+ false
206+ )
207+ changes .added .append ( guidelineName )
208+ }
209+ } )
210+ }
211+
212+ // Sync override guidelines from filesystem
213+ var overridesDir = " #arguments .directory #/.ai/guidelines/overrides"
214+ if ( directoryExists ( overridesDir ) ) {
215+ var overrideFiles = directoryList ( overridesDir , false , " name" , " *.md" )
216+ overrideFiles .each ( ( fileName ) = > {
217+ var baseName = replaceNoCase ( fileName , " .md" , " " )
218+ var manifestName = " #baseName #-override"
219+
220+ // Check if in manifest
221+ var existing = manifest .guidelines .filter ( ( g ) = > g .name == manifestName )
222+ if ( ! existing .len () ) {
223+ // Add to manifest
224+ updateManifestEntry (
225+ manifest ,
226+ manifestName ,
227+ " override" ,
228+ " user" ,
229+ variables .utility .getColdboxCliVersion (),
230+ false
231+ )
232+ changes .added .append ( manifestName )
233+ }
234+ } )
235+ }
236+
237+ // Remove manifest entries for files that no longer exist
238+ var orphanedGuidelines = []
239+ for ( var guideline in manifest .guidelines ) {
240+ var gType = guideline .type ?: " "
241+ var filePath = " "
242+
243+ // Determine expected file path
244+ if ( gType == " core" ) {
245+ filePath = " #arguments .directory #/.ai/guidelines/core/#guideline .name #.md"
246+ } else if ( gType == " module" ) {
247+ filePath = " #arguments .directory #/.ai/guidelines/modules/#guideline .name #.md"
248+ } else if ( gType == " custom" ) {
249+ filePath = " #arguments .directory #/.ai/guidelines/custom/#guideline .name #.md"
250+ } else if ( gType == " override" ) {
251+ var baseName = replaceNoCase ( guideline .name , " -override" , " " )
252+ filePath = " #arguments .directory #/.ai/guidelines/overrides/#baseName #.md"
253+ }
254+
255+ // Check if file exists
256+ if ( filePath .len () && ! fileExists ( filePath ) ) {
257+ orphanedGuidelines .append ( guideline .name )
258+ }
259+ }
260+
261+ orphanedGuidelines .each ( ( name ) = > {
262+ manifest .guidelines = manifest .guidelines .filter ( ( g ) = > g .name ! = name )
263+ changes .removed .append ( name )
264+ } )
265+
174266 return changes ;
175267 }
176268
@@ -391,7 +483,7 @@ component singleton {
391483 // Read override template
392484 var templatesPath = variables .utility .getTemplatesPath () & " /ai/guidelines/"
393485 var templatePath = templatesPath & " guideline-override-template.md"
394-
486+
395487 if ( ! fileExists ( templatePath ) ) {
396488 throw (
397489 type = " GuidelineManager.TemplateNotFound" ,
0 commit comments