Skip to content

Commit a547ce5

Browse files
committed
more updates
1 parent dd08dec commit a547ce5

3 files changed

Lines changed: 228 additions & 38 deletions

File tree

models/AgentRegistry.cfc

Lines changed: 192 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,18 @@ component singleton {
5757
value : "opencode"
5858
}
5959
]
60+
61+
// Compiled once (singleton) — matches any public function declaration
62+
FUNCTION_PATTERN = createObject( "java", "java.util.regex.Pattern" ).compile(
63+
"(?i)(?:^|\s)(?:public\s+)?(?:\w+\s+)?function\s+(\w+)\s*\("
64+
)
6065
}
6166

6267
// Expose them as instance properties for easier access in commands
6368
this.SUPPORTED_AGENTS = static.SUPPORTED_AGENTS
6469
this.AGENT_OPTIONS = static.AGENT_OPTIONS
6570
this.AGENT_FILES = static.AGENT_FILES
71+
this.FUNCTION_PATTERN = static.FUNCTION_PATTERN
6672

6773
/**
6874
* Configure agents for a project
@@ -418,16 +424,20 @@ component singleton {
418424
)
419425

420426
// Generate handlers snapshot
421-
var handlersSnapshotContent = generateHandlersSnapshot(
422-
arguments.directory,
423-
arguments.templateType
424-
)
425-
content = replaceNoCase(
426-
content,
427-
"|HANDLERS_SNAPSHOT|",
428-
handlersSnapshotContent,
429-
"all"
430-
)
427+
var handlersSnapshotContent = generateHandlersSnapshot( arguments.directory, arguments.templateType )
428+
content = replaceNoCase( content, "|HANDLERS_SNAPSHOT|", handlersSnapshotContent, "all" )
429+
430+
// Generate interceptors snapshot
431+
var interceptorsSnapshotContent = generateInterceptorsSnapshot( arguments.directory, arguments.templateType )
432+
content = replaceNoCase( content, "|INTERCEPTORS_SNAPSHOT|", interceptorsSnapshotContent, "all" )
433+
434+
// Generate layouts snapshot
435+
var layoutsSnapshotContent = generateLayoutsSnapshot( arguments.directory, arguments.templateType )
436+
content = replaceNoCase( content, "|LAYOUTS_SNAPSHOT|", layoutsSnapshotContent, "all" )
437+
438+
// Generate custom modules snapshot
439+
var customModulesContent = generateCustomModulesSnapshot( arguments.directory, arguments.templateType )
440+
content = replaceNoCase( content, "|CUSTOM_MODULES_SNAPSHOT|", customModulesContent, "all" )
431441

432442
// Add guidelines inventory (module and additional guidelines only)
433443
var guidelinesContent = generateGuidelinesContent(
@@ -876,43 +886,187 @@ component singleton {
876886
"onapplicationend"
877887
]
878888

879-
// Use a Java regex to extract public function names
880-
var pattern = createObject( "java", "java.util.regex.Pattern" ).compile(
881-
"(?i)(?:^|\s)(?:public\s+)?(?:\w+\s+)?function\s+(\w+)\s*\("
882-
)
883-
884-
var handlerFiles = directoryList(
885-
handlersRoot,
886-
false,
887-
"path",
888-
"*.cfc|*.bx"
889-
)
890-
var lines = []
889+
var handlerFiles = directoryList( handlersRoot, false, "path", "*.cfc|*.bx" )
890+
var lines = []
891891

892892
for ( var handlerFile in handlerFiles ) {
893893
var handlerName = listFirst( getFileFromPath( handlerFile ), "." )
894-
var source = fileRead( handlerFile )
895-
var matcher = pattern.matcher( source )
896-
var actions = []
897-
898-
while ( matcher.find() ) {
899-
var fnName = matcher.group( 1 )
900-
if ( !lifecycleMethods.findNoCase( fnName ) ) {
901-
if ( !actions.findNoCase( fnName ) ) {
902-
actions.append( fnName )
903-
}
904-
}
894+
var actions = extractFunctionNames( fileRead( handlerFile ), lifecycleMethods )
895+
896+
lines.append(
897+
actions.len()
898+
? "- **#handlerName#**: #actions.toList( ', ' )#"
899+
: "- **#handlerName#**: _(no public actions)_"
900+
)
901+
}
902+
903+
if ( !lines.len() ) {
904+
return "No handlers found."
905+
}
906+
907+
lines.sort( "textnocase" )
908+
return lines.toList( chr( 10 ) )
909+
}
910+
911+
/**
912+
* Generate a snapshot of existing interceptors and their interception point methods
913+
*
914+
* @directory The project directory
915+
* @templateType "modern" or "flat"
916+
*
917+
* @return Formatted markdown bullet list of interceptors and their announced points
918+
*/
919+
private function generateInterceptorsSnapshot(
920+
required string directory,
921+
required string templateType
922+
){
923+
var interceptorsRoot = arguments.templateType == "modern"
924+
? "#arguments.directory#/app/interceptors"
925+
: "#arguments.directory#/interceptors"
926+
927+
if ( !directoryExists( interceptorsRoot ) ) {
928+
return "No interceptors found."
929+
}
930+
931+
// Methods to exclude — framework inherited methods, not interception points
932+
var excludedMethods = [
933+
"init",
934+
"configure",
935+
"getproperty",
936+
"setproperty",
937+
"getproperties"
938+
]
939+
940+
var interceptorFiles = directoryList( interceptorsRoot, false, "path", "*.cfc|*.bx" )
941+
var lines = []
942+
943+
for ( var interceptorFile in interceptorFiles ) {
944+
var interceptorName = listFirst( getFileFromPath( interceptorFile ), "." )
945+
var points = extractFunctionNames( fileRead( interceptorFile ), excludedMethods )
946+
947+
lines.append(
948+
points.len()
949+
? "- **#interceptorName#**: #points.toList( ', ' )#"
950+
: "- **#interceptorName#**: _(no interception points declared)_"
951+
)
952+
}
953+
954+
if ( !lines.len() ) {
955+
return "No interceptors found."
956+
}
957+
958+
lines.sort( "textnocase" )
959+
return lines.toList( chr( 10 ) )
960+
}
961+
962+
/**
963+
* Extract unique public function names from CFML/BoxLang source using the shared compiled pattern.
964+
* The matched names are filtered against the provided exclusion list.
965+
*
966+
* @source Raw source code string to scan
967+
* @excludedMethods Array of method names (case-insensitive) to omit from results
968+
*
969+
* @return Ordered array of unique, non-excluded function names found in the source
970+
*/
971+
private array function extractFunctionNames(
972+
required string source,
973+
required array excludedMethods
974+
){
975+
var matcher = variables.FUNCTION_PATTERN.matcher( arguments.source )
976+
var names = []
977+
978+
while ( matcher.find() ) {
979+
var fnName = matcher.group( 1 )
980+
if ( !arguments.excludedMethods.findNoCase( fnName ) && !names.findNoCase( fnName ) ) {
981+
names.append( fnName )
982+
}
983+
}
984+
985+
return names
986+
}
987+
988+
/**
989+
* Generate a snapshot of available layouts
990+
*
991+
* @directory The project directory
992+
* @templateType "modern" or "flat"
993+
*
994+
* @return Formatted markdown bullet list of layout files
995+
*/
996+
private function generateLayoutsSnapshot(
997+
required string directory,
998+
required string templateType
999+
){
1000+
var layoutsRoot = arguments.templateType == "modern"
1001+
? "#arguments.directory#/app/layouts"
1002+
: "#arguments.directory#/layouts"
1003+
1004+
if ( !directoryExists( layoutsRoot ) ) {
1005+
return "No layouts found."
1006+
}
1007+
1008+
var layoutFiles = directoryList( layoutsRoot, false, "path", "*.cfm|*.bxm" )
1009+
var lines = []
1010+
1011+
for ( var layoutFile in layoutFiles ) {
1012+
var layoutName = getFileFromPath( layoutFile )
1013+
lines.append( "- **#layoutName#**" )
1014+
}
1015+
1016+
if ( !lines.len() ) {
1017+
return "No layouts found."
1018+
}
1019+
1020+
lines.sort( "textnocase" )
1021+
return lines.toList( chr( 10 ) )
1022+
}
1023+
1024+
/**
1025+
* Generate a snapshot of application-level custom modules
1026+
*
1027+
* Modern template checks: /app/modules
1028+
* Flat template checks: /modules_app
1029+
* Both check the alternate as a fallback if the primary is missing or empty.
1030+
*
1031+
* @directory The project directory
1032+
* @templateType "modern" or "flat"
1033+
*
1034+
* @return Formatted markdown bullet list of custom module names
1035+
*/
1036+
private function generateCustomModulesSnapshot(
1037+
required string directory,
1038+
required string templateType
1039+
){
1040+
// Build candidate paths (primary first, then fallback)
1041+
var candidates = arguments.templateType == "modern"
1042+
? [ "#arguments.directory#/app/modules", "#arguments.directory#/modules_app" ]
1043+
: [ "#arguments.directory#/modules_app", "#arguments.directory#/app/modules" ]
1044+
1045+
var lines = []
1046+
1047+
for ( var modulesRoot in candidates ) {
1048+
if ( !directoryExists( modulesRoot ) ) {
1049+
continue;
9051050
}
9061051

907-
if ( actions.len() ) {
908-
lines.append( "- **#handlerName#**: #actions.toList( ", " )#" )
909-
} else {
910-
lines.append( "- **#handlerName#**: _(no public actions)_" )
1052+
// Each subdirectory is a module
1053+
var moduleDirs = directoryList( modulesRoot, false, "path" )
1054+
if ( !moduleDirs.len() ) {
1055+
continue;
1056+
}
1057+
1058+
var label = modulesRoot.replace( arguments.directory, "" ).replaceAll( "^[/\\]", "" )
1059+
1060+
for ( var moduleDir in moduleDirs ) {
1061+
if ( directoryExists( moduleDir ) ) {
1062+
var moduleName = getFileFromPath( moduleDir )
1063+
lines.append( "- **#moduleName#** (`#label#`)" )
1064+
}
9111065
}
9121066
}
9131067

9141068
if ( !lines.len() ) {
915-
return "No handlers found."
1069+
return "No custom modules found."
9161070
}
9171071

9181072
lines.sort( "textnocase" )

templates/ai/agents/agent-flat-instructions.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,24 @@ Current event handlers and their public actions (auto-updated on `coldbox ai ref
5656

5757
|HANDLERS_SNAPSHOT|
5858

59+
## Interceptors Snapshot
60+
61+
Registered interceptors and their interception points (auto-updated on `coldbox ai refresh`):
62+
63+
|INTERCEPTORS_SNAPSHOT|
64+
65+
## Layouts
66+
67+
Available layouts (auto-updated on `coldbox ai refresh`):
68+
69+
|LAYOUTS_SNAPSHOT|
70+
71+
## Custom Modules
72+
73+
Application-level modules located in `/modules_app` (auto-updated on `coldbox ai refresh`):
74+
75+
|CUSTOM_MODULES_SNAPSHOT|
76+
5977
## AI Integration & Resources
6078

6179
This project includes AI-powered development assistance with on-demand guidelines, skills, and MCP documentation servers.

templates/ai/agents/agent-modern-instructions.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,24 @@ Current event handlers and their public actions (auto-updated on `coldbox ai ref
8383

8484
|HANDLERS_SNAPSHOT|
8585

86+
## Interceptors Snapshot
87+
88+
Registered interceptors and their interception points (auto-updated on `coldbox ai refresh`):
89+
90+
|INTERCEPTORS_SNAPSHOT|
91+
92+
## Layouts
93+
94+
Available layouts (auto-updated on `coldbox ai refresh`):
95+
96+
|LAYOUTS_SNAPSHOT|
97+
98+
## Custom Modules
99+
100+
Application-level modules located in `/app/modules` (auto-updated on `coldbox ai refresh`):
101+
102+
|CUSTOM_MODULES_SNAPSHOT|
103+
86104
## AI Integration & Resources
87105

88106
This project includes AI-powered development assistance with on-demand guidelines, skills, and MCP documentation servers.

0 commit comments

Comments
 (0)