[ 
https://issues.apache.org/jira/browse/CAMEL-23810?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18136142#comment-18136142
 ] 

Claus Ibsen commented on CAMEL-23810:
-------------------------------------

Notes for coding the switch (2026-11-01)

h3. Done on picocli before the switch
* CAMEL-26455 (#28792, merged):
** A default from {{camel config set}} is now looked up by every long name of 
an option, the command's own key first ({{camel.run.dev}}), then the key for 
all commands ({{dev}}). Before, picocli used only the longest name, so 
{{dev=true}} did not set {{--reload,--dev}}. The aesh {{DefaultValueProvider}} 
must do the same lookup. {{UserConfigDefaultsTest}} covers it.
** {{camel dependency update}} now sets the files of the export from its own 
target files, because aesh fills only the subclass's {{@Arguments}} 
(aeshell/aesh#699).
** {{--output-directory}} of {{camel dependency copy}} is no longer required 
next to its default (aeshell/aesh#698).
* #28793: the tests parse with {{CommandLineTestHelper.parse(command, 
args...)}}, so at the switch only that helper changes, not the tests. A parse 
error gives a {{CliException}} with the usage exit code. The 32 test files left 
on picocli on purpose are listed in the PR: model walkers, test commands with 
their own annotations, and the TUI tests that expect a {{ParameterException}}.
* The golden test ({{CliParseGoldenTest}}, #28791) is the check for the switch. 
Regenerate it with {{-Dcamel.golden.update=true}}, and explain every changed 
line.

h3. aesh fixes (all from Claus's fork, waiting for review)
||Issue||PR||Workaround if it is not released in time||
|#697 the initial value of a primitive option field is 
lost|aeshell/aesh#710|repeat the value in {{defaultValue}}; not possible for 
computed ones such as {{EnvironmentHelper.isColorEnabled()}}|
|#702 arguments on a group command|aeshell/aesh#711|only {{camel semantic}} and 
{{camel tui}} need it|
|#701 a broken definition is reported as "Command not found" 
(127)|aeshell/aesh#713|none needed, but annotation mistakes are hard to find 
without it|
|#703 an optional value as the next word|closed|a custom {{OptionParser}} 
({{parser=}} on {{@Option}}) that peeks at the next word|
|aesh's own tests fail on a locale with a decimal comma|aeshell/aesh#712|build 
aesh with {{-DargLine="-Duser.language=en -Duser.country=US"}}|

h3. camel shell and the shell panel of the TUI
* Keep JLine 4's shell ({{org.jline.shell.ShellBuilder}}). Only 
{{PicocliCommandRegistry}} (from {{jline-picocli}}) touches picocli. Everything 
else in {{Shell.java}} is JLine and stays: prompt, history, aliases, the init 
script, the JLine built-in commands and the tooltips.
* Write a Camel {{AeshCommandGroup}} (about 200 lines) that implements 
{{org.jline.shell.CommandGroup}}, in place of {{PicocliCommandRegistry}}:
** {{commands()}}: names, aliases and descriptions from the aesh registry, or 
from our own command tree.
** {{describe(args)}}: the tooltips, from aesh's model of the command (options, 
arguments, descriptions).
** {{execute(session, args)}}: run through {{CliRunner}}, as {{camel ask}} and 
the AI panel of the TUI do.
** {{completer()}}: {{runtime.complete(new AeshCompleteOperation("camel " + 
line, cursor))}}, with each candidate turned into a JLine {{Candidate}}. This 
is the same headless completion as aesh's {{--aesh-complete}}.
* {{CamelShellCommandRegistry}} only changes its base class: the {{camel}} 
prefix and the {{CliRunner.LOCK}} wrapper are JLine types. {{Shell.java}} and 
{{ShellPanel}} change only the line that creates the registry. Drop the 
{{jline-picocli}} dependency.
* Not aesh's own console ({{AeshConsoleRunner}}): Camel keeps JLine anyway 
(TUI, nano, ask, debug), and the shell panel runs inside TamboUI on a JLine 
virtual terminal.
* Tests: {{CamelShellCommandRegistryTest}}, plus a look at the four 
{{ShellPanel}} tests.
* Small gap: aesh's completion candidates have no description. The runner looks 
them up in a private method ({{buildCompletionDescriptions}}), so the group 
does its own lookup until aesh has a public method.

h3. camel completion
* aesh generates static and dynamic completion scripts for bash, zsh, fish and 
PowerShell ({{ShellCompletionGenerator}}). The dynamic script calls the program 
back with {{--aesh-complete}}, so completion runs in Java at Tab time.
* {{camel completion}} prints the script through {{ShellCompletionGenerator}}, 
in place of picocli's {{AutoComplete}}, and the command stays. The runner's own 
{{--aesh-completion}} flags are not the Camel user interface.
* The completion candidate classes (35 on main, 30 of them used by an option) 
become {{OptionCompleter}} classes ({{@Option(completer = ...)}}). The same 
completers then also serve {{camel shell}}.
* {{$\{COMPLETION-CANDIDATES\}}} in a description is filled only from a fixed 
value list; from a completer it needs aeshell/aesh#708.

_Claude Code on behalf of davsclaus (Claus Ibsen)_


> camel-jbang - Port from picolli to aesh
> ---------------------------------------
>
>                 Key: CAMEL-23810
>                 URL: https://issues.apache.org/jira/browse/CAMEL-23810
>             Project: Camel
>          Issue Type: Improvement
>            Reporter: Claus Ibsen
>            Assignee: Claus Ibsen
>            Priority: Major
>             Fix For: 4.24.0
>
>
> Port the Camel CLI (dsl/camel-jbang) from picocli to aesh, as JBang did: 
> [https://www.jbang.dev/learn/from-picocli-to-sh-how-porting-jbang-s-cli-made-everything-better/]
>  (jbangdev/jbang#2453).
> Starts from the state after CAMEL-25388 (exit codes 0/1/2/3/70/124, 
> CAMEL-25389) and CAMEL-24724 stage 1 and 2 (run and export are the 
> picocli-free camel-jbang-run engine), and keeps the exit code contract.
> h2. What reaches beyond the command layer
> * *The plugin SPI is picocli*: {{Plugin.customize(CommandLine, 
> CamelJBangMain)}} is public, and plugins outside Camel implement it: forage 
> (Kaoto), kit, and the test plugin mounts the picocli commands of Citrus 
> ({{org.citrusframework.jbang.cli}}) with a picocli execution strategy.
> * *The metadata and docs mojo reads the source*: 
> {{PrepareCamelJBangCommandsMojo}} regex-parses the {{addSubcommand}} chains 
> of {{CamelJBangMain}} and the picocli annotations (Roaster). The 175 pages 
> under {{jbang-commands/}} and the JSON that AskTools uses come from it.
> * *{{camel shell}} and the shell panel of the TUI* use jline's 
> {{PicocliCommandRegistry}}.
> h2. Size (main, 2026-10-31)
> 164 {{@Command}}, 861 {{@Option}}, 355 boolean options (160 {{arity="0..1"}}, 
> 89 {{fallbackValue="true"}}), 59 {{@Mixin}}, 5 converters, 17 parameter 
> consumers ({{DebugConsumer}} looks ahead), 42 completion candidate classes, 
> {{scope=INHERIT}} on {{--profile}}, user configuration via 
> {{PicocliPropertiesDefaultProvider}}, {{originalArgs()}} to start the CLI 
> again in another process ({{Run}}, {{Debug}}, {{InfraRun}}), 96 test files 
> using picocli directly.
> h2. aesh (checked 2026-10-31)
> * 3.18.6 ({{org.aesh:aesh}}, {{aesh-processor}}, {{aesh-bom}}), Apache-2.0, 
> Java 8 baseline. Annotation processor (no reflection, one registry per jar), 
> {{@Mixin}}, negatable, {{fallbackValue}}/{{optionalValue}}, {{inherited}}, 
> converters, completers, {{DefaultValueProvider}}, 
> {{CommandResult.valueOf(int)}}, {{MutableCommandRegistry}} for commands added 
> at runtime, AsciiDoc doc and bash/zsh/fish completion generators.
> * No picocli compatibility layer: every annotation is rewritten (JBang: one 
> PR, 134 files).
> * Risks: jbang#2504 (primitive boolean options) still open, JBang worked 
> around it with boxed {{Boolean}}; bus factor about 1; about 40 releases in 
> 2026 with API churn ({{@GroupCommandDefinition}} removed in 3.15); stricter 
> parsing than picocli around attached values ({{-R-Xmx4G}}, {{-D k=v}}). Pin 
> an exact version.
> h2. Plan
> As stage 2 of CAMEL-24724: a guard first, seams while still on picocli, then 
> one switch. Not per command group (two parsers in one command tree).
> # *Measure* the startup of {{camel --help}}, {{camel ps}}, {{camel version}} 
> on the JVM and the share of picocli (part may be the eager creation of 143 
> subcommands and the plugins, which picocli could do lazily too). A decision 
> point: if the gain is small, the reasons are completion, the native launcher 
> and staying aligned with JBang.
> # *A golden guard of the CLI surface*, on picocli: the committed metadata 
> JSON and pages, plus a {{CliParseGoldenTest}} recording command lines per 
> command, the field values after parsing, the exit code and the help (booleans 
> {{0..1}}, {{--profile}}, the lookahead consumers, {{split}}, converters, user 
> configuration, {{$\{camel-version\}}}). The port keeps it unchanged, except 
> the differences listed on purpose.
> # *Seams in core*, on picocli, no behaviour change: the uses of {{spec}} and 
> {{ParseResult}} behind {{CamelCommand}} helpers ({{isOptionGiven}}, the 
> original arguments, {{printHelp}}, {{runDefault}}, the configuration dump, 
> the placeholders); a test helper instead of {{populateCommand}}/{{parseArgs}} 
> in the tests.
> # *A plugin SPI without picocli*, on picocli: a new {{Plugin}} method 
> registering command classes with names and aliases; {{customize(CommandLine, 
> ...)}} deprecated but working in 4.24. Tell the forage, kit and Citrus 
> maintainers.
> # *The mojo reads a list of commands* in code (used by {{CamelJBangMain}} 
> too), not the source text. The generated output does not change.
> # *The switch*, one PR, mostly scripted: aesh pinned via {{aesh-bom}} and 
> {{aesh-processor}}; the exit codes mapped in one place on the base command; 
> installing a missing plugin on first use without matching picocli's message 
> text; the grouped command list of the help via {{HelpSectionProvider}}; 
> {{camel config}} via {{DefaultValueProvider}}; completion via aesh's 
> generator; the shell and the TUI shell panel on a command registry of aesh; 
> booleans boxed where needed.
> # *Cleanup*: remove picocli and {{jline-picocli}}, the old SPI (or its 
> bridge), upgrade-guide entry (plugin SPI, regenerate the completion script).
> h2. Open decisions
> * Release: proposal is steps 1-5 in 4.24 (old SPI deprecated), the switch in 
> 4.25, so forage, kit and Citrus have a release to move.
> * Plugin compatibility: a bridge for the old picocli SPI for one release 
> (picocli optional), or a break.
> * Citrus: ask to port citrus-jbang to aesh, or keep the test plugin on a 
> picocli bridge.
> * aesh risks (bus factor, jbang#2504, churn): acceptable with an exact 
> version and the golden guard of step 2.
> _Plan by Claude Code on behalf of davsclaus (Claus Ibsen)_



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to