Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
743ce22
Version bump
Apr 28, 2026
b9b2148
Bump taiki-e/create-gh-release-action from 1.9.3 to 1.11.0
dependabot[bot] May 1, 2026
c299f9c
more skills
lmajano May 1, 2026
de71926
more updates for ai agents
lmajano May 1, 2026
f6f9359
change to bxformat
lmajano May 1, 2026
7fb052e
- **VSCode Copilot MCP Mirroring**
lmajano May 1, 2026
85e3bf6
more udpates on guidelines
lmajano May 1, 2026
eb0359a
Initial plan
Copilot May 6, 2026
e19fb55
Merge pull request #59 from ColdBox/dependabot/github_actions/taiki-e…
lmajano May 6, 2026
214c62f
feat: separate custom skills into skills-custom/ folder with dedicate…
Copilot May 6, 2026
2b00991
fix: address code review issues - path consistency, redundant checks,…
Copilot May 6, 2026
d47f3ee
fix: address additional code review issues - null checks, performance…
Copilot May 6, 2026
26a2c9b
Merge pull request #65 from ColdBox/copilot/preserve-custom-skills-fo…
lmajano May 6, 2026
9b54c89
Initial plan
Copilot May 6, 2026
c251cf5
fix: use .agents directory in doctor and uninstall commands instead o…
Copilot May 6, 2026
2545364
docs: add changelog entry for .ai vs .agents directory fix
Copilot May 6, 2026
b400e59
Merge pull request #67 from ColdBox/copilot/fix-coldbox-ai-directory-…
lmajano May 8, 2026
45cbd45
- `coldbox ai skills add slug --list` was not working.
lmajano May 11, 2026
e96ce17
- New progress bar when doing `coldbox ai skills list --outdated` to …
lmajano May 11, 2026
afc3c92
- `coldbox ai skills list --json` flag to output the skills manifest …
lmajano May 11, 2026
b121dbb
small fixes on case
lmajano May 11, 2026
ca7d030
- `coldbox ai skills update` command to re-download and overwrite all…
lmajano May 11, 2026
a53968c
Initial plan
Copilot May 11, 2026
1dbc68f
fix: prevent re-installation of explicitly removed skills during refresh
Copilot May 11, 2026
33ab6ab
fix: address code review - semicolon consistency and rename closure p…
Copilot May 11, 2026
029efb4
docs: add changelog entry for skills remove exclusion fix
Copilot May 11, 2026
e55a86b
Merge pull request #68 from ColdBox/copilot/fix-coldbox-ai-skills-remove
lmajano May 11, 2026
c9b4039
more remove goodness
lmajano May 11, 2026
b482e77
formatting updates
lmajano May 11, 2026
64347d4
Apply cfformat changes
lmajano May 11, 2026
e4e43c9
Version bump
May 11, 2026
bf01983
Initial plan
Copilot May 14, 2026
c94e74d
Add DB_SCHEMA key to env.example template
Copilot May 14, 2026
1a576a4
Fix ai refresh custom skills closure scoping and preserve AGENTS sect…
Copilot May 14, 2026
c788aaa
Merge pull request #70 from ColdBox/copilot/fix-missing-db-schema-key
lmajano May 14, 2026
5558e7b
Merge pull request #71 from ColdBox/copilot/fix-coldbox-ai-refresh-issue
lmajano May 14, 2026
ee130d7
Apply cfformat changes
lmajano May 14, 2026
17aa8df
Initial plan
Copilot May 18, 2026
fe70c41
Propagate boxlang flag to handler-generated views
Copilot May 18, 2026
e401166
Add changelog entry for handler view language flag fix
Copilot May 18, 2026
6ca21c0
Merge pull request #74 from ColdBox/copilot/fix-handler-view-generation
lmajano May 18, 2026
2477cd8
fix edge cases
lmajano May 19, 2026
d0acc28
introducing the tiered app template
lmajano May 20, 2026
f02f100
- `coldbox create model --tests` now prefixes the right location of t…
lmajano May 20, 2026
bb5867a
Apply cfformat changes
lmajano May 20, 2026
2422913
Initial plan
Copilot May 28, 2026
6efbd32
fix: respect server.json webroot in watch-reinit
Copilot May 28, 2026
3eca856
docs: add watch-reinit fix to changelog and changelog rule
Copilot May 28, 2026
b6167a3
Merge pull request #77 from ColdBox/copilot/fix-watch-reinit-webroot-…
lmajano May 28, 2026
627fee5
Apply cfformat changes
lmajano May 28, 2026
1169071
Merge branch 'master' into development
lmajano May 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ Each command extends `BaseCommand.cfc` (or `BaseAICommand.cfc` for AI commands)
- **Always lint markdown files after editing** - Run `npx markdownlint-cli -f {filename}` after any markdown file modifications
- Markdown linting configuration is in `.markdownlint.json`
- Fix any linting errors before committing changes
- **Always update `changelog.md`** for every fix, update, or addition

## Development Workflows

Expand Down
2 changes: 1 addition & 1 deletion box.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name":"ColdBox CLI",
"version":"8.12.0",
"version":"8.13.0",
"location":"https://downloads.ortussolutions.com/ortussolutions/commandbox-modules/coldbox-cli/@build.version@/coldbox-cli-@build.version@.zip",
"slug":"coldbox-cli",
"author":"Ortus Solutions, Corp",
Expand Down
6 changes: 6 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Fixed

- `coldbox create handler --boxlang` / `--noboxlang` now propagates language selection to auto-generated views so view extensions match the requested mode (`.bxm` for BoxLang, `.cfm` for CFML)
- `coldbox create model --tests` now prefixes the right location of the models
- `coldbox watch-reinit` now honors `server.json` webroot-based server discovery so running apps in subdirectory webroots are correctly found and reinitialized

## [8.12.0] - 2026-05-11

### Fixed
Expand Down
4 changes: 2 additions & 2 deletions commands/coldbox/create/app-wizard.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,8 @@ component extends="app" {
.options( [
{
accessKey : 1,
value : "modern",
display : "Modern Template - Security-first CFML and BoxLang template with /app outside webroot",
value : "tiered",
display : "Tiered Template - Security-first CFML and BoxLang template with /app outside webroot",
selected : true
},
{
Expand Down
14 changes: 7 additions & 7 deletions commands/coldbox/create/app.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@
*
* - BoxLang (Default)
* - BoxLang Desktop
* - Modern (CFML + BoxLang Default)
* - Tiered (CFML + BoxLang Default)
* - flat (CFML + BoxLang Flat)
* - rest (CFML + BoxLang RESTful API)
* - rest-hmvc (HMVC + REST)
* - supersimple (bare bones)
* - vite (flat + vite)
* .
* {code:bash}
* coldbox create app skeleton=modern
* coldbox create app skeleton=tiered
* // Same as
* coldbox create app --cfml
* {code}
Expand All @@ -48,7 +48,7 @@ component extends="coldbox-cli.models.BaseCommand" {
"flat" : "cbtemplate-flat",
"boxlang" : "cbtemplate-boxlang",
"desktop" : "cbtemplate-boxlang-desktop",
"modern" : "cbtemplate-modern",
"tiered" : "cbtemplate-tiered",
"rest" : "cbtemplate-rest",
"rest-hmvc" : "cbtemplate-rest-hmvc",
"vite" : "cbtemplate-vite",
Expand All @@ -75,7 +75,7 @@ component extends="coldbox-cli.models.BaseCommand" {
* @migrations Run migration init after creation
* @boxlang Set the language to BoxLang
* @docker Include Docker files and setup Docker configuration
* @vite Setup Vite for frontend asset building (For BoxLang or Modern apps only)
* @vite Setup Vite for frontend asset building (For BoxLang or Tiered apps only)
* @rest Is this a REST API project? (For BoxLang apps only)
* @cfml Set the language to CFML explicitly (overrides boxlang)
* @ai Enable AI integration for the application
Expand Down Expand Up @@ -117,7 +117,7 @@ component extends="coldbox-cli.models.BaseCommand" {
if ( arguments.cfml ) {
arguments.boxlang = false;
if ( arguments.skeleton == variables.defaultSkeleton ) {
arguments.skeleton = "modern";
arguments.skeleton = "tiered";
}
printInfo( "⚡Language set to CFML" )
} else {
Expand Down Expand Up @@ -251,8 +251,8 @@ component extends="coldbox-cli.models.BaseCommand" {

// VITE Setup
if ( arguments.vite ) {
if ( !arguments.skeleton.reFindNoCase( "(modern|boxlang)" ) ) {
printWarn( "⚠️ Vite setup is only supported for 'modern' or 'boxlang' skeletons. Skipping Vite setup." )
if ( !arguments.skeleton.reFindNoCase( "(tiered|boxlang)" ) ) {
printWarn( "⚠️ Vite setup is only supported for 'tiered' or 'boxlang' skeletons. Skipping Vite setup." )
} else {
printInfo( "🥊 Setting up Vite for your frontend build system" )
fileCopy(
Expand Down
6 changes: 4 additions & 2 deletions commands/coldbox/create/handler.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,8 @@ component aliases="coldbox create controller" extends="coldbox-cli.models.BaseCo
boolean open,
boolean rest,
boolean force,
boolean resource
boolean resource,
boolean boxlang
){
var results = { actions : "", tests : "" }
var actionContent = fileRead(
Expand Down Expand Up @@ -249,7 +250,8 @@ component aliases="coldbox create controller" extends="coldbox-cli.models.BaseCo
content : "<h1>#camelCaseHandlerName#.#thisAction#</h1>",
directory: arguments.viewsDirectory,
force : arguments.force,
open : arguments.open
open : arguments.open,
boxlang : arguments.boxlang
)
.run();
}
Expand Down
4 changes: 3 additions & 1 deletion commands/coldbox/create/model.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -408,9 +408,11 @@ component extends="coldbox-cli.models.BaseCommand" {

// Generate Tests
if ( arguments.tests ) {
var appPrefix = getAppPrefixDot( getCWD() )
var modelPrefix = appPrefix.isEmpty() ? "models." & arguments.name : appPrefix & "models." & arguments.name
command( "coldbox create model-test" )
.params(
path : arguments.name,
path : modelPrefix,
force : arguments.force,
open : arguments.open,
methods: arguments.methods,
Expand Down
8 changes: 6 additions & 2 deletions commands/coldbox/watch-reinit.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,12 @@ component {
"removed" : "red",
"changed" : "yellow"
}
var serverDetails = serverService.resolveServerDetails( {} );
var serverStatus = serverService.isServerRunning( serverDetails.serverInfo );
var defaultServer = serverService.getServerInfoByDiscovery( serverConfigFile = "server.json" );
var serverDetails = serverService.resolveServerDetails( {
name : defaultServer.keyExists( "name" ) ? defaultServer.name : "",
directory : getCWD()
} );
var serverStatus = serverService.isServerRunning( serverDetails.serverInfo );

// Tabula rasa
command( "cls" ).run();
Expand Down
51 changes: 29 additions & 22 deletions models/AgentRegistry.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -139,13 +139,13 @@ component singleton {
* Merges newly generated managed content with any user-authored content from an existing file.
*
* The managed section is delimited by COLDBOX-CLI:START and COLDBOX-CLI:END HTML comment
* markers. On refresh, only the content between those markers is replaced; everything after
* the end marker (i.e. the user's custom documentation) is preserved unchanged.
* markers. On refresh, only the content between those markers is replaced; user-authored
* content before the start marker and after the end marker is preserved unchanged.
*
* Behavior:
* - File does not exist → return newContent as-is (first-time write).
* - File exists but has no end marker → return newContent as-is (old format, no user section to preserve).
* - File exists with end marker → replace managed section, keep user section intact.
* - File exists but has no start/end marker pair → return newContent as-is.
* - File exists with a start/end marker pair → replace managed section, preserve user sections.
*
* @filePath Absolute path to the existing agent config file (may not exist yet).
* @newContent Freshly generated content that includes both START and END markers.
Expand All @@ -156,45 +156,52 @@ component singleton {
required string filePath,
required string newContent
){
var endMarker = static.MANAGED_SECTION_END
var startMarker = static.MANAGED_SECTION_START
var endMarker = static.MANAGED_SECTION_END

// Nothing to preserve — first-time write
if ( !fileExists( filePath ) ) {
return newContent
}

var existingContent = fileRead( filePath )
// Read existing content and locate markers
var existingContent = fileRead( filePath ).trim()
var startPos = findNoCase( startMarker, existingContent )
var endPos = findNoCase( endMarker, existingContent )
Comment on lines +167 to +170

// Find the end marker in the existing file
var endPos = findNoCase( endMarker, existingContent )
// If existing content is empty or markers are not properly found, return new content as-is
if ( !len( existingContent ) ) {
return newContent
}

// Old-format file (no markers) — write fresh content, no user section to preserve
if ( !endPos ) {
// Old-format file (no marker pair) — write fresh content
if ( !startPos || !endPos || endPos <= startPos ) {
return newContent
}

// Extract user content: everything that comes after the end marker
var userStartPos = endPos + len( endMarker )
var userContent = mid(
// Preserve user-authored content around managed section
var userContentBeforeManaged = startPos > 1 ? left( existingContent, startPos - 1 ) : ""
var userStartPos = endPos + len( endMarker )
var userContentAfterManaged = mid(
existingContent,
userStartPos,
len( existingContent ) - userStartPos + 1
)

// Find the end marker position in the newly generated content
var newEndPos = findNoCase( endMarker, newContent )
if ( !newEndPos ) {
// New template has no end marker — return new content plus preserved user section
return newContent & userContent
// Slice managed portion from the newly generated content
var newStartPos = findNoCase( startMarker, newContent )
var newEndPos = findNoCase( endMarker, newContent )
if ( !newStartPos || !newEndPos || newEndPos <= newStartPos ) {
return newContent & userContentAfterManaged
}

// Slice off the managed portion of the new content (up to and including the end marker)
var managedContent = left(
var managedContent = mid(
newContent,
newEndPos + len( endMarker ) - 1
newStartPos,
newEndPos + len( endMarker ) - newStartPos
)

return managedContent & userContent
return userContentBeforeManaged & managedContent & userContentAfterManaged
}

/**
Expand Down
13 changes: 13 additions & 0 deletions models/BaseCommand.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,19 @@ component accessors="true" {
return variables.utility.detectTemplateType( cwd ) == "modern" ? "app/" : "";
}

/**
* Detects the application layout and returns the appropriate path prefix.
* In a modern layout (app/ and public/ directories exist), returns "app/".
* In a flat layout, returns "".
*
* @cwd The current working directory
*
* @return string "app." for modern layout, "" for flat layout
*/
function getAppPrefixDot( required cwd ){
return variables.utility.detectTemplateType( cwd ) == "modern" ? "app." : "";
}

/**
* Detects the application layout and returns the appropriate modules directory path.
* In a modern layout (or BoxLang project), modules live under lib/modules.
Expand Down
6 changes: 3 additions & 3 deletions models/SkillManager.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@ component singleton {
// Remove custom skills whose files were deleted by the user
missingCustomSkills.each( ( name ) => {
variables.print.yellowLine( " 🧹 Removing deleted custom skill entry: #name#" ).toConsole()
arguments.manifest.customSkills = arguments.manifest.customSkills.filter( ( s ) => s.name != name )
manifest.customSkills = manifest.customSkills.filter( ( s ) => s.name != name )
changes.removed.append( name )
} )

Expand All @@ -497,7 +497,7 @@ component singleton {
return;
}

var alreadyInManifest = !arguments.manifest.customSkills.filter( ( s ) => s.name == dirName ).isEmpty()
var alreadyInManifest = !manifest.customSkills.filter( ( s ) => s.name == dirName ).isEmpty()
if ( alreadyInManifest ) {
return;
}
Expand All @@ -508,7 +508,7 @@ component singleton {
var parsed = variables.utility.parseFrontmatter( content )
var description = parsed.frontmatter.description ?: ""

arguments.manifest.customSkills.append( {
manifest.customSkills.append( {
"name" : dirName,
"description" : description,
"syncedAt" : dateTimeFormat( now(), "iso" )
Expand Down
1 change: 1 addition & 0 deletions templates/env.example
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ DB_DRIVER=MySQL
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=coldbox
DB_SCHEMA=coldbox
DB_USER=root
DB_PASSWORD=

Expand Down