[
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)