Follow-up to #2211.
The fix in #2211 addressed the framework-not-found path specifically. scaffoldNewApp() and its caller new() in cli/lucli/Module.cfc have three remaining error paths that still return "" and silently exit 0 — same root cause, same fix pattern.
Affected paths
-
Directory already exists — cli/lucli/Module.cfc:3217-3220
if (directoryExists(targetDir)) {
out("Directory already exists: #appName#", "red");
return "";
}
-
App name required — cli/lucli/Module.cfc:446-450
if (!len(appName)) {
out("Error: app name is required.", "red");
out("Usage: wheels new <appname>");
return "";
}
-
Project template not found — cli/lucli/Module.cfc:3237-3240
if (!directoryExists(templateDir)) {
out("Project template not found at: #templateDir#", "red");
return "";
}
All three print a user-facing error, then return an empty string that LuCLI prints as nothing with exit code 0 — fooling automation in the same way #2211 did.
Proposed fix
Mirror the pattern from #2211: after the friendly out() block, throw a typed exception so Picocli's ExecutionExceptionHandler produces exit 1.
Wheels.TargetDirectoryExists for case 1
Wheels.InvalidArguments for case 2
Wheels.TemplateNotFound for case 3
Acceptance
Not in scope
Usage/help output when no args are passed is ambiguous — arguably the user wanted help, not an error. Current behavior prints usage and returns "". If we throw here, the "help me" experience degrades. Keep case 2 narrower: throw only when an arg was provided but parsing yielded no app name, not when zero args were passed.
Follow-up to #2211.
The fix in #2211 addressed the framework-not-found path specifically.
scaffoldNewApp()and its callernew()incli/lucli/Module.cfchave three remaining error paths that stillreturn ""and silently exit 0 — same root cause, same fix pattern.Affected paths
Directory already exists — cli/lucli/Module.cfc:3217-3220
if (directoryExists(targetDir)) { out("Directory already exists: #appName#", "red"); return ""; }App name required — cli/lucli/Module.cfc:446-450
if (!len(appName)) { out("Error: app name is required.", "red"); out("Usage: wheels new <appname>"); return ""; }Project template not found — cli/lucli/Module.cfc:3237-3240
if (!directoryExists(templateDir)) { out("Project template not found at: #templateDir#", "red"); return ""; }All three print a user-facing error, then return an empty string that LuCLI prints as nothing with exit code 0 — fooling automation in the same way #2211 did.
Proposed fix
Mirror the pattern from #2211: after the friendly
out()block, throw a typed exception so Picocli'sExecutionExceptionHandlerproduces exit 1.Wheels.TargetDirectoryExistsfor case 1Wheels.InvalidArgumentsfor case 2Wheels.TemplateNotFoundfor case 3Acceptance
wheels new <existing-dir-name>exits non-zerowheels new(no args) exits non-zerowheels new foowith a broken install (missingtemplates/app/) exits non-zeroNot in scope
Usage/help output when no args are passed is ambiguous — arguably the user wanted help, not an error. Current behavior prints usage and returns "". If we throw here, the "help me" experience degrades. Keep case 2 narrower: throw only when an arg was provided but parsing yielded no app name, not when zero args were passed.