This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new a342d94f4d68 camel-tui - Include YAML DSL model in camel-catalog for 
runtime loading and prettify discard popup
a342d94f4d68 is described below

commit a342d94f4d68a0b01db91ae84074a55b00cc0c6b
Author: Claus Ibsen <[email protected]>
AuthorDate: Thu Aug 6 11:36:54 2026 +0200

    camel-tui - Include YAML DSL model in camel-catalog for runtime loading and 
prettify discard popup
    
    - Copy camelYamlDsl-model.json into camel-catalog schemas directory via
      PrepareCatalogMojo so it is available at runtime through the catalog's
      version manager classloader (adapts to the Camel version in use)
    - Load the completion tree from the catalog instead of local classpath
    - Prettify the discard confirmation popup: wider, centered message,
      padded key hints in footer
    - Document the model JSON in camel-catalog and yaml-dsl docs
    
    camel-tui - Unify blank line indent derivation into shared methods
    
    Replace 7 duplicate blank-line indent derivation blocks with two shared
    methods:
    - deriveBlankLineIndent: for context detection (min of predecessor and
      successor indent)
    - deriveInsertionIndent: for text insertion (predecessor only, with
      - key: +4 and key: +2 offsets)
    
    Both only activate on truly empty lines (0 spaces). Lines with actual
    spaces use their indent directly. Fixes incorrect indentation when
    inserting keys after list items like - setHeader:.
    
    camel-tui - Add fallback schema path for completion tree and reset cache on 
integration change
    
    - Try both catalog schemas path and direct schema path when loading
      the completion tree, for compatibility across Camel versions
    - Reset completionTree cache when integration changes so it reloads
      from the correct catalog version
    
    camel-tui - Bundle YAML DSL model JSON in TUI plugin JAR via 
maven-resources-plugin
    
    Copy camelYamlDsl-model.json from camel-yaml-dsl into the TUI plugin
    JAR during build, so the completion tree is always available without
    depending on the catalog classloader resolving it at runtime. Falls
    back to the catalog version manager for different Camel versions.
    
    camel-tui - Add listChildren/isListItem hints to model JSON and simplify 
indent derivation
    
    - Model generator now marks nodes with listChildren (root, steps) and
      isListItem (EIPs, top-level elements) flags for editor tooling
    - Simplify indent derivation to use predecessor-only approach: after
      - key: → indent + 4, after key: → indent + 2, after key: value → same
    - Remove unreliable successor-based indent guessing that caused wrong
      context detection when successor was in a different block
    
    camel-tui - Prefix list item insertions with - and restyle popups to match 
quit dialog
    
    - EIP step completions from steps: now insert with - prefix (e.g. - bean:)
      using the listChildren flag from the model JSON
    - Discard and validation popups use inline bold key hints instead of
      footer, matching the quit dialog style
    - Discard flow changed to Enter confirm / Esc cancel (more intuitive)
    
    camel-tui - Use bold + accent color for scope line highlight in edit mode
    
    Makes the EIP/uri scope line stand out more clearly when editing YAML
    routes, using the theme accent color instead of plain bold.
    
    camel-tui - Smart Enter indentation, scope line fix, and steps sorted last
    
    - Enter after key: auto-indents children (+2 or +4 for list items),
      and prefixes with - for listChildren nodes (e.g., steps:)
    - Fix scope line highlighting uri: instead of route: for blank lines
      inside from: block
    - Sort steps/outputs to bottom of completion popup since they are
      always added last
    
    camel-tui - Fix Tab completion on bare list item lines (- ) and scope line
    
    - Strip bare - prefix same as - prefix so filter is empty, not -
    - Return null from findEnclosingComponent for - prefixed lines (step
      items, not parameters)
    - No scope line highlight on bare - lines (no EIP selected yet)
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
    
    Regen
---
 .../camel/catalog/schemas}/camelYamlDsl-model.json |  85 +++++++
 .../modules/ROOT/pages/camel-catalog.adoc          |   9 +-
 dsl/camel-jbang/camel-jbang-plugin-tui/pom.xml     |  23 ++
 .../jbang/core/commands/tui/AutocompletePopup.java |  10 +
 .../dsl/jbang/core/commands/tui/SourceTab.java     |  31 ++-
 .../dsl/jbang/core/commands/tui/SourceViewer.java  | 277 ++++++++++-----------
 .../core/commands/tui/SourceViewerEditTest.java    |   4 +-
 .../core/commands/tui/YamlCompletionTest.java      |  21 ++
 .../maven/dsl/yaml/GenerateYamlCompletionMojo.java |  46 +++-
 .../resources/schema/camelYamlDsl-model.json       |  85 +++++++
 .../camel/maven/packaging/PrepareCatalogMojo.java  |  11 +
 11 files changed, 452 insertions(+), 150 deletions(-)

diff --git 
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl-model.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camelYamlDsl-model.json
similarity index 99%
copy from 
dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl-model.json
copy to 
catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camelYamlDsl-model.json
index 9d022f1ff00c..ff289173abc1 100644
--- 
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl-model.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camelYamlDsl-model.json
@@ -3,6 +3,7 @@
     "root" : {
       "title" : "Root",
       "description" : "Top-level YAML DSL elements",
+      "listChildren" : true,
       "children" : [ {
         "name" : "beans",
         "type" : "object",
@@ -128,6 +129,7 @@
     "steps" : {
       "title" : "Steps",
       "description" : "Processing steps that can be used inside a route",
+      "listChildren" : true,
       "children" : [ {
         "name" : "a2aSubTask",
         "type" : "object",
@@ -781,12 +783,15 @@
       } ]
     },
     "beansDeserializer" : {
+      "isListItem" : true,
       "children" : [ ]
     },
     "dataFormatsDefinitionDeserializer" : {
+      "isListItem" : true,
       "children" : [ ]
     },
     "errorHandlerDeserializer" : {
+      "isListItem" : true,
       "children" : [ {
         "name" : "deadLetterChannel",
         "type" : "object",
@@ -846,6 +851,7 @@
       } ]
     },
     "routeFromDefinitionDeserializer" : {
+      "isListItem" : true,
       "children" : [ {
         "name" : "description",
         "type" : "string"
@@ -875,6 +881,7 @@
     "a2ASubTask" : {
       "title" : "A2A Sub Task",
       "description" : "Groups route steps and emits A2A (Agent-to-Agent) 
protocol progress events before, after, or when the grouped work fails",
+      "isListItem" : true,
       "children" : [ {
         "name" : "description",
         "type" : "string",
@@ -930,6 +937,7 @@
       "aliases" : [ "fan-in", "reduce", "join", "merge" ],
       "input" : true,
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -1270,6 +1278,7 @@
       "description" : "Calls a Java bean method",
       "label" : "language,core,java",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -1487,6 +1496,7 @@
     "catch" : {
       "title" : "Do Catch",
       "description" : "Catches specific exceptions within a doTry block, 
allowing fine-grained exception handling within the route",
+      "isListItem" : true,
       "children" : [ {
         "name" : "description",
         "type" : "string",
@@ -1531,6 +1541,7 @@
       "label" : "eip,routing",
       "aliases" : [ "router", "dispatch" ],
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -1609,6 +1620,7 @@
       "aliases" : [ "circuit-breaker" ],
       "input" : true,
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -1700,6 +1712,7 @@
       "label" : "eip,enrichment,routing",
       "aliases" : [ "claim-check", "stash" ],
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -1827,6 +1840,7 @@
     "convertBody" : {
       "title" : "Convert Body To",
       "description" : "Converts the message body to a specified Java type 
using Camel's built-in type converters",
+      "isListItem" : true,
       "children" : [ {
         "name" : "charset",
         "type" : "string",
@@ -1870,6 +1884,7 @@
     "convertHeader" : {
       "title" : "Convert Header To",
       "description" : "Converts a message header value to a specified Java 
type using Camel's built-in type converters",
+      "isListItem" : true,
       "children" : [ {
         "name" : "charset",
         "type" : "string",
@@ -1924,6 +1939,7 @@
     "convertVariable" : {
       "title" : "Convert Variable To",
       "description" : "Converts a variable value to a specified Java type 
using Camel's built-in type converters",
+      "isListItem" : true,
       "children" : [ {
         "name" : "charset",
         "type" : "string",
@@ -1987,6 +2003,7 @@
       "label" : "eip,flowcontrol,routing",
       "aliases" : [ "debounce", "delay" ],
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -2076,6 +2093,7 @@
       "label" : "eip,routing",
       "aliases" : [ "dispatch" ],
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -2164,6 +2182,7 @@
       "label" : "eip,enrichment,transformation",
       "aliases" : [ "enrich", "hydrate", "augment" ],
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -2611,6 +2630,7 @@
       "aliases" : [ "filter" ],
       "input" : true,
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -2679,6 +2699,7 @@
     "finally" : {
       "title" : "Do Finally",
       "description" : "Defines steps to always execute after a doTry block 
completes, regardless of whether an exception was thrown or caught",
+      "isListItem" : true,
       "children" : [ {
         "name" : "description",
         "type" : "string",
@@ -2806,6 +2827,7 @@
       "aliases" : [ "dedup", "deduplicate" ],
       "input" : true,
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -2974,6 +2996,7 @@
       "label" : "configuration",
       "input" : true,
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -3034,6 +3057,7 @@
       "label" : "configuration",
       "input" : true,
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -3103,6 +3127,7 @@
       "label" : "configuration",
       "input" : true,
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -3193,6 +3218,7 @@
       "label" : "eip,endpoint,routing",
       "input" : true,
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "note",
         "type" : "string",
@@ -3231,6 +3257,7 @@
       "aliases" : [ "load-balance" ],
       "input" : true,
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -3308,6 +3335,7 @@
       "description" : "Logs a message using an expression that can include 
message body, headers, and other exchange data",
       "label" : "eip,routing",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -3415,6 +3443,7 @@
       "aliases" : [ "loop", "iterate" ],
       "input" : true,
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -3519,6 +3548,7 @@
       "label" : "eip,dataformat,transformation",
       "aliases" : [ "serialize" ],
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -3776,6 +3806,7 @@
       "aliases" : [ "fan-out", "broadcast" ],
       "input" : true,
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -3951,6 +3982,7 @@
       "label" : "configuration",
       "input" : true,
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -4075,6 +4107,7 @@
       "label" : "error,errorhandling",
       "input" : true,
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -4550,6 +4583,7 @@
       "description" : "Pauses a consumer based on a condition, allowing it to 
be resumed later from the last known offset. Useful for controlling ingestion 
rate on polling consumers.",
       "label" : "eip,routing",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -4617,6 +4651,7 @@
       "aliases" : [ "pipeline", "chain" ],
       "input" : true,
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -4666,6 +4701,7 @@
       "description" : "Applies a policy to the route, such as a transactional 
policy or a custom policy for cross-cutting concerns",
       "label" : "configuration",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -4726,6 +4762,7 @@
       "label" : "eip,enrichment,routing",
       "aliases" : [ "poll", "pull" ],
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -4805,6 +4842,7 @@
       "label" : "eip,enrichment,transformation",
       "aliases" : [ "enrich", "hydrate" ],
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -4963,6 +5001,7 @@
       "description" : "Invokes a custom Camel Processor for programmatic 
message processing in Java",
       "label" : "eip,endpoint",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -5071,6 +5110,7 @@
       "description" : "Routes a message to a list of dynamically calculated 
endpoints, determined at runtime from an expression. Each recipient receives a 
copy of the message.",
       "label" : "eip,routing",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -5555,6 +5595,7 @@
       "description" : "Removes a specific header from the message by name",
       "label" : "eip,messaging,transformation",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -5610,6 +5651,7 @@
       "description" : "Removes all message headers whose names match a given 
pattern. Useful for stripping internal Camel headers before sending to external 
systems.",
       "label" : "eip,messaging,transformation",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -5675,6 +5717,7 @@
       "description" : "Removes all exchange properties whose names match a 
given pattern",
       "label" : "eip,messaging,transformation",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -5740,6 +5783,7 @@
       "description" : "Removes a specific exchange property by name",
       "label" : "eip,messaging,transformation",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -5795,6 +5839,7 @@
       "description" : "Removes a specific variable by name",
       "label" : "eip,messaging,transformation",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -5851,6 +5896,7 @@
       "label" : "eip,flowcontrol,routing",
       "input" : true,
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -6234,6 +6280,7 @@
       "description" : "Enables resuming processing from the last known offset 
after a restart, using a resume strategy to track and restore position",
       "label" : "eip,routing",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -6313,6 +6360,7 @@
       "label" : "eip,errorhandling,routing",
       "aliases" : [ "rollback" ],
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -6428,6 +6476,7 @@
       "title" : "Route Configuration",
       "description" : "Defines reusable configuration that is automatically 
applied to matching routes, such as shared error handling or interceptors",
       "label" : "configuration",
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -6524,6 +6573,7 @@
       "label" : "configuration",
       "input" : true,
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -6698,6 +6748,7 @@
       "description" : "Defines a parameterized route template that can be 
instantiated multiple times with different parameter values",
       "label" : "configuration",
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -6775,6 +6826,7 @@
       "description" : "Routes a message through a pre-determined sequence of 
endpoints defined in a header or expression (the routing slip). The list of 
endpoints is evaluated once upfront.",
       "label" : "eip,routing",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -6864,6 +6916,7 @@
       "aliases" : [ "compensate" ],
       "input" : true,
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -6983,6 +7036,7 @@
     "sampling" : {
       "title" : "Sample",
       "description" : "Samples a subset of messages passing through the route, 
either by frequency count or time interval, and discards the rest",
+      "isListItem" : true,
       "children" : [ {
         "name" : "description",
         "type" : "string",
@@ -7022,6 +7076,7 @@
       "description" : "Executes an expression or script in a chosen language 
for side effects without modifying the message body",
       "label" : "eip,transformation",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -7079,6 +7134,7 @@
       "label" : "eip,messaging,transformation",
       "aliases" : [ "map", "transform" ],
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -7135,6 +7191,7 @@
       "description" : "Sets the message exchange pattern (MEP) on the 
exchange, such as InOnly for one-way or InOut for request-reply",
       "label" : "configuration,messaging",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -7191,6 +7248,7 @@
       "description" : "Sets a message header to a value computed by an 
expression",
       "label" : "eip,messaging,transformation",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -7257,6 +7315,7 @@
       "description" : "Sets multiple message headers at once, each computed by 
its own expression",
       "label" : "eip,messaging,transformation",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -7313,6 +7372,7 @@
       "description" : "Sets an exchange property to a value computed by an 
expression",
       "label" : "eip,messaging,transformation",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -7379,6 +7439,7 @@
       "description" : "Sets a variable to a value computed by an expression",
       "label" : "eip,messaging,transformation",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -7445,6 +7506,7 @@
       "description" : "Sets multiple variables at once, each computed by its 
own expression",
       "label" : "eip,messaging,transformation",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -7501,6 +7563,7 @@
       "description" : "Sorts the items in a message body that is a List, using 
a specified comparator or the default ordering",
       "label" : "eip,transformation",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -7569,6 +7632,7 @@
       "aliases" : [ "split", "chunk" ],
       "input" : true,
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -7825,6 +7889,7 @@
       "label" : "eip,routing",
       "input" : true,
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -7874,6 +7939,7 @@
       "description" : "Stops processing of the current message and marks the 
exchange as completed without sending it to any further steps",
       "label" : "eip,flowcontrol,routing",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -7918,6 +7984,7 @@
       "title" : "Templated Route",
       "description" : "Creates a route instance from a route template, binding 
specific parameter values to the template's parameters",
       "label" : "configuration",
+      "isListItem" : true,
       "children" : [ {
         "name" : "routeTemplateRef",
         "type" : "string",
@@ -8103,6 +8170,7 @@
       "description" : "Offloads processing of subsequent steps in the route to 
a thread pool, enabling asynchronous and concurrent message handling",
       "label" : "eip,flowcontrol,routing",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -8249,6 +8317,7 @@
       "label" : "eip,flowcontrol,routing",
       "aliases" : [ "rate-limit", "throttle" ],
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -8379,6 +8448,7 @@
       "description" : "Throws an exception during route processing, either 
creating a new exception instance or re-throwing an existing one",
       "label" : "error,errorhandling",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -8453,6 +8523,7 @@
       "label" : "eip,endpoint,routing",
       "aliases" : [ "sink", "egress" ],
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -8538,6 +8609,7 @@
     "toDynamic" : {
       "title" : "To D",
       "description" : "Sends the message to an endpoint URI computed 
dynamically from an expression, allowing the destination to vary per message",
+      "isListItem" : true,
       "children" : [ {
         "name" : "allowOptimisedComponents",
         "type" : "boolean",
@@ -8619,6 +8691,7 @@
       "description" : "Tokenizes the message body for AI processing, splitting 
text into chunks suitable for embedding or LLM input",
       "label" : "eip,transformation,ai",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -8690,6 +8763,7 @@
       "description" : "Wraps the route in a transaction, ensuring that all 
steps within the transacted block either complete together or roll back on 
failure",
       "label" : "configuration",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -8748,6 +8822,7 @@
       "description" : "Transforms the message body between known data types 
(such as XML, JSON, Java objects) using registered data type transformers",
       "label" : "eip,transformation",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -8813,6 +8888,7 @@
       "label" : "eip,transformation",
       "aliases" : [ "map", "transform" ],
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -8867,6 +8943,7 @@
     "try" : {
       "title" : "Do Try",
       "description" : "Wraps route steps in a try-catch-finally block for 
fine-grained exception handling within the route",
+      "isListItem" : true,
       "children" : [ {
         "name" : "description",
         "type" : "string",
@@ -8912,6 +8989,7 @@
       "label" : "eip,dataformat,transformation",
       "aliases" : [ "deserialize" ],
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -9227,6 +9305,7 @@
       "label" : "eip,transformation",
       "aliases" : [ "validate", "guard" ],
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -9371,6 +9450,7 @@
       "label" : "eip,endpoint,routing",
       "aliases" : [ "tap", "observe" ],
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -9581,6 +9661,7 @@
       } ]
     },
     "sSLContextParameters" : {
+      "isListItem" : true,
       "children" : [ {
         "name" : "certAlias",
         "type" : "string"
@@ -18189,6 +18270,7 @@
       "title" : "Rest Configuration",
       "description" : "Configures global settings for the REST DSL, such as 
host, port, context path, binding mode, and the underlying HTTP component to 
use",
       "label" : "rest",
+      "isListItem" : true,
       "children" : [ {
         "name" : "component",
         "type" : "enum",
@@ -18527,6 +18609,7 @@
       "description" : "Defines a REST service with HTTP operations (GET, POST, 
PUT, DELETE, etc.) using the Camel REST DSL",
       "label" : "rest",
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -19575,6 +19658,7 @@
       "title" : "Transformations",
       "description" : "Container for defining data type transformer 
definitions",
       "label" : "transformation",
+      "isListItem" : true,
       "children" : [ {
         "name" : "customTransformer",
         "type" : "object",
@@ -19689,6 +19773,7 @@
       "title" : "Validations",
       "description" : "Container for defining data type validator definitions",
       "label" : "validation",
+      "isListItem" : true,
       "children" : [ {
         "name" : "customValidator",
         "type" : "object",
diff --git a/docs/user-manual/modules/ROOT/pages/camel-catalog.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-catalog.adoc
index 638294fee2ff..e50c178e9566 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-catalog.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-catalog.adoc
@@ -59,7 +59,7 @@ org
       ├── models-app (JSON schema)
       ├── others (JSON schema)
       ├── releases (JSON schema)
-      ├── schemas (XML schema)
+      ├── schemas (XML and JSON schemas)
       ├── test-infra (JSON schema)
       └── transformers (JSON schema)
 ----
@@ -72,6 +72,13 @@ The `docs` directory contains the AsciiDoc documentation 
pages for all component
 data formats, languages, and other artifacts. A `docs.properties` index file 
lists all
 available documentation names.
 
+The `schemas` directory contains the XML schemas for the XML DSLs 
(`camel-spring.xsd`,
+`camel-xml-io.xsd`) and the YAML DSL model (`camelYamlDsl-model.json`).
+The YAML DSL model is a generated data structure describing every valid key at 
every
+nesting level in the YAML DSL, with types, descriptions, required flags, 
default values,
+and enum choices. It can be used by third-party tooling (editors, IDE plugins, 
visual
+designers) to provide context-aware code completion and validation for YAML 
DSL routes.
+
 === Documentation in the Catalog
 
 The catalog includes the AsciiDoc documentation pages from all modules. This 
makes the full
diff --git a/dsl/camel-jbang/camel-jbang-plugin-tui/pom.xml 
b/dsl/camel-jbang/camel-jbang-plugin-tui/pom.xml
index 9f68638c6b2f..ee171389e468 100644
--- a/dsl/camel-jbang/camel-jbang-plugin-tui/pom.xml
+++ b/dsl/camel-jbang/camel-jbang-plugin-tui/pom.xml
@@ -135,6 +135,29 @@
 
     <build>
         <plugins>
+            <plugin>
+                <artifactId>maven-resources-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>copy-yaml-dsl-model</id>
+                        <phase>generate-resources</phase>
+                        <goals>
+                            <goal>copy-resources</goal>
+                        </goals>
+                        <configuration>
+                            
<outputDirectory>${project.build.outputDirectory}/schema</outputDirectory>
+                            <resources>
+                                <resource>
+                                    
<directory>${project.basedir}/../../camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema</directory>
+                                    <includes>
+                                        
<include>camelYamlDsl-model.json</include>
+                                    </includes>
+                                </resource>
+                            </resources>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
             <plugin>
                 <groupId>org.apache.rat</groupId>
                 <artifactId>apache-rat-plugin</artifactId>
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/AutocompletePopup.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/AutocompletePopup.java
index 4b57abc28d19..dcb2ca9a30b1 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/AutocompletePopup.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/AutocompletePopup.java
@@ -440,6 +440,16 @@ class AutocompletePopup {
         this.titlePrefix = titlePrefix;
     }
 
+    private boolean listItemInsertion;
+
+    void setListItemInsertion(boolean listItemInsertion) {
+        this.listItemInsertion = listItemInsertion;
+    }
+
+    boolean isListItemInsertion() {
+        return listItemInsertion;
+    }
+
     private void rebuildList() {
         if (!filter.hasFilter()) {
             filteredItems = new ArrayList<>(allItems);
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SourceTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SourceTab.java
index e49dcd0daba4..a67e4ce45234 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SourceTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SourceTab.java
@@ -155,6 +155,8 @@ class SourceTab extends AbstractTab {
         sourceViewer.reset();
         focusOnViewer = false;
         leftPanelWidth = -1;
+        completionTreeLoaded = false;
+        completionTree = null;
         refreshFiles();
     }
 
@@ -559,6 +561,7 @@ class SourceTab extends AbstractTab {
                         
sourceViewer.setAutocompleteProvider(this::provideYamlKeyCompletions);
                         
sourceViewer.setAutocompleteValueProvider(this::provideYamlValueCompletions);
                         
sourceViewer.setEndpointValidator(this::validateYamlEndpoints);
+                        
sourceViewer.setListItemNodeChecker(this::isListChildrenNode);
                     } else {
                         sourceViewer.setAutocompleteProvider(null);
                         sourceViewer.setAutocompleteValueProvider(null);
@@ -1070,18 +1073,39 @@ class SourceTab extends AbstractTab {
         return items;
     }
 
+    private boolean isListChildrenNode(String nodeName) {
+        JsonObject node = getTreeNode(nodeName);
+        return node != null && Boolean.TRUE.equals(node.get("listChildren"));
+    }
+
     private static final Set<String> TREE_BOILERPLATE = Set.of("id", "note", 
"description", "disabled");
 
     private JsonObject getCompletionTree() {
         if (!completionTreeLoaded) {
             completionTreeLoaded = true;
+            // try bundled resource first
             try (var is = 
getClass().getResourceAsStream("/schema/camelYamlDsl-model.json")) {
                 if (is != null) {
                     String json = new String(is.readAllBytes(), 
java.nio.charset.StandardCharsets.UTF_8);
                     completionTree = (JsonObject) 
org.apache.camel.util.json.Jsoner.deserialize(json);
                 }
             } catch (Exception e) {
-                // ignore — tree not available
+                // ignore
+            }
+            // fallback: try catalog version manager (may have a different 
Camel version)
+            if (completionTree == null) {
+                CamelCatalog cat = getCatalog();
+                if (cat != null) {
+                    try (var is = cat.getVersionManager()
+                            
.getResourceAsStream("org/apache/camel/catalog/schemas/camelYamlDsl-model.json"))
 {
+                        if (is != null) {
+                            String json = new String(is.readAllBytes(), 
java.nio.charset.StandardCharsets.UTF_8);
+                            completionTree = (JsonObject) 
org.apache.camel.util.json.Jsoner.deserialize(json);
+                        }
+                    } catch (Exception e) {
+                        // ignore — tree not available for this Camel version
+                    }
+                }
             }
         }
         return completionTree;
@@ -1147,6 +1171,11 @@ class SourceTab extends AbstractTab {
         }
 
         
items.sort(Comparator.comparing(AutocompletePopup.CompletionItem::deprecated)
+                .thenComparing((a, b) -> {
+                    boolean aIsSteps = "steps".equals(a.key()) || 
"outputs".equals(a.key());
+                    boolean bIsSteps = "steps".equals(b.key()) || 
"outputs".equals(b.key());
+                    return Boolean.compare(aIsSteps, bIsSteps);
+                })
                 .thenComparing((a, b) -> Boolean.compare(b.required(), 
a.required())));
         return items;
     }
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SourceViewer.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SourceViewer.java
index ffc6a7dabd19..e42a1f129d04 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SourceViewer.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SourceViewer.java
@@ -144,6 +144,7 @@ class SourceViewer {
     private BiConsumer<String, Boolean> notificationCallback;
     private AutocompletePopup.AutocompleteProvider autocompleteProvider;
     private AutocompletePopup.ValueProvider autocompleteValueProvider;
+    private java.util.function.Predicate<String> listItemNodeChecker;
     private AutocompletePopup autocompletePopup;
     private boolean validateOnSave = true;
     private org.apache.camel.dsl.yaml.validator.YamlValidator yamlValidator;
@@ -185,6 +186,10 @@ class SourceViewer {
         this.autocompleteValueProvider = provider;
     }
 
+    void setListItemNodeChecker(java.util.function.Predicate<String> checker) {
+        this.listItemNodeChecker = checker;
+    }
+
     void setValidateOnSave(boolean validateOnSave) {
         this.validateOnSave = validateOnSave;
     }
@@ -284,11 +289,14 @@ class SourceViewer {
             autocompletePopup = null;
             return true;
         }
-        if (dirty && !pendingDiscard) {
+        if (pendingDiscard) {
+            pendingDiscard = false;
+            return true;
+        }
+        if (dirty) {
             pendingDiscard = true;
             return true;
         }
-        pendingDiscard = false;
         exitEditMode();
         return true;
     }
@@ -464,12 +472,13 @@ class SourceViewer {
         }
         if (autocompletePopup != null) {
             boolean wasValueMode = autocompletePopup.isValueMode();
+            boolean wasListItem = autocompletePopup.isListItemInsertion();
             AutocompletePopup.Result result = 
autocompletePopup.handleKeyEvent(ke);
             if (result == AutocompletePopup.Result.CLOSED) {
                 AutocompletePopup.CompletionItem item = 
autocompletePopup.consumeSelectedItem();
                 autocompletePopup = null;
                 if (item != null) {
-                    insertCompletion(item, wasValueMode);
+                    insertCompletion(item, wasValueMode, wasListItem);
                 }
             } else if (result == AutocompletePopup.Result.CURSOR_RIGHT) {
                 editState.moveCursorRight();
@@ -478,15 +487,20 @@ class SourceViewer {
             }
             return true;
         }
-        if (!ke.isCancel()) {
-            pendingDiscard = false;
+        if (pendingDiscard) {
+            if (ke.isConfirm()) {
+                pendingDiscard = false;
+                exitEditMode();
+            } else if (ke.isCancel()) {
+                pendingDiscard = false;
+            }
+            return true;
         }
         if (ke.isCancel()) {
-            if (dirty && !pendingDiscard) {
+            if (dirty) {
                 pendingDiscard = true;
                 return true;
             }
-            pendingDiscard = false;
             exitEditMode();
             return true;
         }
@@ -502,8 +516,21 @@ class SourceViewer {
             int prevRow = editState.cursorRow();
             String prevLine = editState.getLine(prevRow);
             int indent = countLeadingSpaces(prevLine);
+            String pt = prevLine.trim();
             editState.insert('\n');
-            if (indent > 0) {
+            if (isCamelYamlFile() && pt.endsWith(":")) {
+                // parent key with no value — indent deeper for children
+                String key = extractEipName(pt);
+                if (listItemNodeChecker != null && key != null
+                        && listItemNodeChecker.test(dashToCamelCase(key))) {
+                    // children are list items (e.g., steps:, root)
+                    int childIndent = indent + (pt.startsWith("- ") ? 4 : 2);
+                    editState.insert(" ".repeat(childIndent) + "- ");
+                } else {
+                    int childIndent = indent + (pt.startsWith("- ") ? 4 : 2);
+                    editState.insert(" ".repeat(childIndent));
+                }
+            } else if (indent > 0) {
                 editState.insert(" ".repeat(indent));
             }
             dirty = true;
@@ -628,15 +655,24 @@ class SourceViewer {
         String cursorLine = editState.getLine(fromRow);
         int cursorIndent = countLeadingSpaces(cursorLine);
 
+        // list items (- key:) are inside steps, not inside parameters
+        if (!cursorLine.isBlank() && cursorLine.trim().startsWith("- ")) {
+            return null;
+        }
+
         // blank lines: find the nearest preceding non-blank line for context
         if (cursorLine.isBlank()) {
             for (int i = fromRow - 1; i >= 0; i--) {
                 String prev = editState.getLine(i);
                 if (!prev.isBlank()) {
-                    if (prev.trim().startsWith("parameters:")) {
+                    String pt = prev.trim();
+                    if (pt.startsWith("parameters:")) {
                         // blank line right after parameters: — cursor is 
inside the block
                         cursorIndent = countLeadingSpaces(prev) + 1;
                         fromRow = i;
+                    } else if (pt.startsWith("- ") || pt.startsWith("steps:")) 
{
+                        // inside a steps block or list item — not inside 
parameters
+                        return null;
                     } else {
                         return findEnclosingComponent(i);
                     }
@@ -662,8 +698,17 @@ class SourceViewer {
                 break;
             }
             if (i < fromRow && indent < cursorIndent && 
!trimmed.startsWith("#")) {
+                // stop if we hit a structural boundary (steps:, from:, etc.)
                 break;
             }
+            // also stop if we hit a list item at a shallower or equal indent 
— we've left the parameters scope
+            if (i < fromRow && indent <= cursorIndent) {
+                String key = extractEipName(trimmed);
+                if (key != null && ("steps".equals(key) || "from".equals(key)
+                        || trimmed.startsWith("- "))) {
+                    break;
+                }
+            }
         }
 
         if (parametersRow < 0) {
@@ -841,34 +886,36 @@ class SourceViewer {
     record YamlEipContext(String eipName) {
     }
 
+    int deriveBlankLineIndent(int fromRow) {
+        return deriveIndentFromPredecessor(fromRow);
+    }
+
+    private int deriveInsertionIndent(int fromRow) {
+        return deriveIndentFromPredecessor(fromRow);
+    }
+
+    private int deriveIndentFromPredecessor(int fromRow) {
+        for (int i = fromRow - 1; i >= 0; i--) {
+            String prev = editState.getLine(i);
+            if (prev.isBlank()) {
+                continue;
+            }
+            int indent = countLeadingSpaces(prev);
+            String pt = prev.trim();
+            if (pt.endsWith(":")) {
+                return indent + (pt.startsWith("- ") ? 4 : 2);
+            }
+            return indent;
+        }
+        return 0;
+    }
+
     String findParentYamlKey(int fromRow) {
         String cursorLine = editState.getLine(fromRow);
         int cursorIndent = countLeadingSpaces(cursorLine);
 
         if (cursorLine.isBlank() && cursorIndent == 0) {
-            int lineCount = editState.lineCount();
-            for (int i = fromRow + 1; i < lineCount; i++) {
-                String next = editState.getLine(i);
-                if (!next.isBlank()) {
-                    cursorIndent = countLeadingSpaces(next);
-                    break;
-                }
-            }
-            if (cursorIndent == 0) {
-                for (int i = fromRow - 1; i >= 0; i--) {
-                    String prev = editState.getLine(i);
-                    if (!prev.isBlank()) {
-                        cursorIndent = countLeadingSpaces(prev);
-                        String pt = prev.trim();
-                        if (pt.startsWith("- ") && pt.endsWith(":")) {
-                            cursorIndent += 4;
-                        } else if (pt.endsWith(":")) {
-                            cursorIndent += 2;
-                        }
-                        break;
-                    }
-                }
-            }
+            cursorIndent = deriveBlankLineIndent(fromRow);
         }
 
         // walk up to find parent key at lower indent
@@ -898,32 +945,8 @@ class SourceViewer {
         String cursorLine = editState.getLine(fromRow);
         int cursorIndent = countLeadingSpaces(cursorLine);
 
-        // blank lines: derive indent from context
-        if (cursorLine.isBlank()) {
-            if (cursorIndent == 0) {
-                // truly empty line — look at successor first, then predecessor
-                int succIndent = -1;
-                int lineCount = editState.lineCount();
-                for (int i = fromRow + 1; i < lineCount; i++) {
-                    String next = editState.getLine(i);
-                    if (!next.isBlank()) {
-                        succIndent = countLeadingSpaces(next);
-                        break;
-                    }
-                }
-                if (succIndent > 0) {
-                    cursorIndent = succIndent;
-                } else {
-                    for (int i = fromRow - 1; i >= 0; i--) {
-                        String prev = editState.getLine(i);
-                        if (!prev.isBlank()) {
-                            // treat cursor as sibling of predecessor
-                            cursorIndent = countLeadingSpaces(prev);
-                            break;
-                        }
-                    }
-                }
-            }
+        if (cursorLine.isBlank() && cursorIndent == 0) {
+            cursorIndent = deriveBlankLineIndent(fromRow);
         }
 
         // if cursor is inside a parameters: block, defer to component 
completion
@@ -972,29 +995,8 @@ class SourceViewer {
         String cursorLine = editState.getLine(fromRow);
         int cursorIndent = countLeadingSpaces(cursorLine);
 
-        // for blank lines, check both directions and use the deeper indent 
(sibling level)
-        if (cursorLine.isBlank()) {
-            int succIndent = -1;
-            int predIndent = -1;
-            int lineCount2 = editState.lineCount();
-            for (int i = fromRow + 1; i < lineCount2; i++) {
-                String next = editState.getLine(i);
-                if (!next.isBlank()) {
-                    succIndent = countLeadingSpaces(next);
-                    break;
-                }
-            }
-            for (int i = fromRow - 1; i >= 0; i--) {
-                String prev = editState.getLine(i);
-                if (!prev.isBlank()) {
-                    predIndent = countLeadingSpaces(prev);
-                    break;
-                }
-            }
-            cursorIndent = Math.max(succIndent, predIndent);
-            if (cursorIndent < 0) {
-                cursorIndent = 0;
-            }
+        if (cursorLine.isBlank() && cursorIndent == 0) {
+            cursorIndent = deriveBlankLineIndent(fromRow);
         }
 
         // scan upward for siblings at same indent
@@ -1065,6 +1067,11 @@ class SourceViewer {
             trimmed = trimmed.substring(2).trim();
         }
 
+        // bare list item (- ) with no key yet — no scope
+        if (cursorLine.trim().startsWith("- ") && trimmed.isEmpty()) {
+            return -1;
+        }
+
         // if cursor is on a uri: line, scope is this row
         if (trimmed.startsWith("uri:")) {
             return cursorRow;
@@ -1085,27 +1092,8 @@ class SourceViewer {
 
         int cursorIndent = countLeadingSpaces(cursorLine);
 
-        // for blank lines, derive indent from context
         if (cursorLine.isBlank()) {
-            if (cursorIndent == 0) {
-                int lineCount = editState.lineCount();
-                for (int i = cursorRow + 1; i < lineCount; i++) {
-                    String next = editState.getLine(i);
-                    if (!next.isBlank()) {
-                        cursorIndent = countLeadingSpaces(next);
-                        break;
-                    }
-                }
-                if (cursorIndent == 0) {
-                    for (int i = cursorRow - 1; i >= 0; i--) {
-                        String prev = editState.getLine(i);
-                        if (!prev.isBlank()) {
-                            cursorIndent = countLeadingSpaces(prev);
-                            break;
-                        }
-                    }
-                }
-            }
+            cursorIndent = deriveBlankLineIndent(cursorRow);
         }
 
         // walk up looking for the scope line
@@ -1129,6 +1117,16 @@ class SourceViewer {
                 if (eipName != null && !STRUCTURAL_KEYS.contains(eipName)) {
                     return i;
                 }
+                // for from:/to: blocks, look for uri: sibling as scope
+                if (eipName != null && ("from".equals(eipName) || 
CONSUMER_EIPS.contains(eipName)
+                        || PRODUCER_EIPS.contains(eipName))) {
+                    for (int j = i + 1; j < cursorRow; j++) {
+                        String jl = editState.getLine(j);
+                        if (!jl.isBlank() && jl.trim().startsWith("uri:")) {
+                            return j;
+                        }
+                    }
+                }
                 cursorIndent = indent;
             }
         }
@@ -1286,6 +1284,8 @@ class SourceViewer {
         String trimmed = lineText.trim();
         if (trimmed.startsWith("- ")) {
             trimmed = trimmed.substring(2).trim();
+        } else if (trimmed.equals("-")) {
+            trimmed = "";
         }
 
         // try component name completion on uri: lines first
@@ -1321,7 +1321,7 @@ class SourceViewer {
                     }
                 }
             } else {
-                String filter = colonIdx > 0 ? trimmed.substring(0, 
colonIdx).trim() : trimmed;
+                String filter = trimmed;
                 String role = ctx.consumer() ? "consumer" : "producer";
                 java.util.Set<String> existing = 
collectExistingParameters(row);
                 String context = "yaml:" + ctx.component() + ":" + role;
@@ -1341,6 +1341,7 @@ class SourceViewer {
         if (autocompleteProvider != null) {
             String parentKey = findParentYamlKey(row);
             int colonIdx = trimmed.indexOf(':');
+
             if (colonIdx > 0) {
                 // value completion
                 String optionName = trimmed.substring(0, colonIdx).trim();
@@ -1370,16 +1371,19 @@ class SourceViewer {
                 if (items != null && !items.isEmpty()) {
                     autocompletePopup = new AutocompletePopup(items, filter, 
filter);
                     autocompletePopup.setTitlePrefix(parentKey);
+                    if (listItemNodeChecker != null && 
listItemNodeChecker.test(parentKey)) {
+                        autocompletePopup.setListItemInsertion(true);
+                    }
                 }
             }
         }
     }
 
-    private void insertCompletion(AutocompletePopup.CompletionItem item, 
boolean valueMode) {
+    private void insertCompletion(AutocompletePopup.CompletionItem item, 
boolean valueMode, boolean listItem) {
         dirty = true;
         String currentLine = editState.getLine(editState.cursorRow());
         if (isCamelYamlFile()) {
-            insertYamlCompletion(item, valueMode, currentLine);
+            insertYamlCompletion(item, valueMode, currentLine, listItem);
         } else {
             insertPropertiesCompletion(item, valueMode, currentLine);
         }
@@ -1411,34 +1415,14 @@ class SourceViewer {
     }
 
     void insertYamlCompletion(AutocompletePopup.CompletionItem item, boolean 
valueMode, String currentLine) {
+        insertYamlCompletion(item, valueMode, currentLine, false);
+    }
+
+    private void insertYamlCompletion(
+            AutocompletePopup.CompletionItem item, boolean valueMode, String 
currentLine, boolean listItem) {
         int indent = countLeadingSpaces(currentLine);
-        // blank lines: derive indent from context
-        if (currentLine.isBlank() && indent == 0) {
-            int row = editState.cursorRow();
-            // look at next non-blank line first (sibling indent)
-            int lineCount = editState.lineCount();
-            for (int i = row + 1; i < lineCount; i++) {
-                String next = editState.getLine(i);
-                if (!next.isBlank()) {
-                    indent = countLeadingSpaces(next);
-                    break;
-                }
-            }
-            if (indent == 0) {
-                // no successor — derive from predecessor
-                for (int i = row - 1; i >= 0; i--) {
-                    String prev = editState.getLine(i);
-                    if (!prev.isBlank()) {
-                        indent = countLeadingSpaces(prev);
-                        String trimmed = prev.trim();
-                        if (trimmed.endsWith(":")) {
-                            // cursor is inside this block — indent deeper
-                            indent += trimmed.startsWith("- ") ? 4 : 2;
-                        }
-                        break;
-                    }
-                }
-            }
+        if (currentLine.isBlank()) {
+            indent = deriveInsertionIndent(editState.cursorRow());
         }
         String indentStr = " ".repeat(indent);
 
@@ -1476,10 +1460,11 @@ class SourceViewer {
                 }
             }
         } else {
-            editState.insert(indentStr + item.key() + ":");
+            String prefix = listItem ? "- " : "";
+            editState.insert(indentStr + prefix + item.key() + ":");
             if ("object".equals(item.type()) || "array".equals(item.type())) {
                 editState.insert('\n');
-                editState.insert(indentStr + "  ");
+                editState.insert(indentStr + (listItem ? "    " : "  "));
             } else {
                 editState.insert(' ');
             }
@@ -1663,12 +1648,13 @@ class SourceViewer {
         if (editMode) {
             if (autocompletePopup != null) {
                 boolean wasValueMode = autocompletePopup.isValueMode();
+                boolean wasListItem = autocompletePopup.isListItemInsertion();
                 AutocompletePopup.Result result = 
autocompletePopup.handleMouseEvent(me);
                 if (result == AutocompletePopup.Result.CLOSED) {
                     AutocompletePopup.CompletionItem item = 
autocompletePopup.consumeSelectedItem();
                     autocompletePopup = null;
                     if (item != null) {
-                        insertCompletion(item, wasValueMode);
+                        insertCompletion(item, wasValueMode, wasListItem);
                     }
                 }
                 return true;
@@ -1932,7 +1918,7 @@ class SourceViewer {
                 if (relativeRow >= 0 && relativeRow < inner.height()) {
                     int screenY = inner.top() + relativeRow;
                     Rect lineRect = new Rect(inner.left(), screenY, 
inner.width(), 1);
-                    frame.buffer().setStyle(lineRect, Style.EMPTY.bold());
+                    frame.buffer().setStyle(lineRect, 
Style.EMPTY.bold().fg(Theme.accent()));
                 }
             }
         }
@@ -1963,6 +1949,9 @@ class SourceViewer {
             String msg = validationErrors.get(i);
             wrapText(msg, innerW, allLines);
         }
+        allLines.add(Line.empty());
+        allLines.add(Line.from(Span.raw("  "),
+                Span.styled("Esc", Style.EMPTY.bold()), Span.raw(" close")));
 
         int contentH = allLines.size();
         int popupH = Math.min(contentH + 2, area.height() - 4);
@@ -1977,8 +1966,6 @@ class SourceViewer {
         Block block = Block.builder()
                 .borderType(BorderType.ROUNDED).borders(Borders.ALL)
                 .title(Title.from(Line.from(Span.styled(titleText, 
Theme.error().bold()))))
-                .titleBottom(Title.from(Line.from(
-                        Span.styled(" Esc", Theme.hintKey()), Span.raw(" close 
"))))
                 .build();
         frame.renderWidget(block, popup);
         Rect inner = block.inner(popup);
@@ -1997,9 +1984,8 @@ class SourceViewer {
     }
 
     private void renderDiscardPopup(Frame frame, Rect area) {
-        String msg = "Unsaved changes will be lost.";
-        int popupW = Math.min(msg.length() + 6, area.width() - 4);
-        int popupH = 5;
+        int popupW = Math.min(40, area.width() - 4);
+        int popupH = 6;
         int x = area.left() + Math.max(0, (area.width() - popupW) / 2);
         int y = area.top() + Math.max(0, (area.height() - popupH) / 2);
         Rect popup = new Rect(x, y, popupW, popupH);
@@ -2009,16 +1995,19 @@ class SourceViewer {
         Block block = Block.builder()
                 .borderType(BorderType.ROUNDED).borders(Borders.ALL)
                 .title(Title.from(Line.from(Span.styled(" Discard Changes? ", 
Theme.warning().bold()))))
-                .titleBottom(Title.from(Line.from(
-                        Span.styled(" Esc", Theme.hintKey()), Span.raw(" 
discard  "),
-                        Span.styled("any key", Theme.hintKey()), Span.raw(" 
cancel "))))
                 .build();
         frame.renderWidget(block, popup);
         Rect inner = block.inner(popup);
 
         frame.renderWidget(
                 Paragraph.builder().text(Text.from(
-                        Line.from(Span.styled(msg, Theme.warning())))).build(),
+                        Line.empty(),
+                        Line.from(Span.raw(" Unsaved changes will be lost.")),
+                        Line.empty(),
+                        Line.from(Span.raw("  "),
+                                Span.styled("Enter", Style.EMPTY.bold()), 
Span.raw(" confirm  "),
+                                Span.styled("Esc", Style.EMPTY.bold()), 
Span.raw(" cancel"))))
+                        .build(),
                 inner);
     }
 
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/SourceViewerEditTest.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/SourceViewerEditTest.java
index a70e9610fab2..748aa9e38b79 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/SourceViewerEditTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/SourceViewerEditTest.java
@@ -150,10 +150,10 @@ class SourceViewerEditTest {
         for (char ch : "CHANGED".toCharArray()) {
             viewer.handleKeyEvent(KeyEvent.ofChar(ch, KeyModifiers.NONE));
         }
-        // first Esc shows discard warning, second Esc confirms
+        // first Esc shows discard warning, Enter confirms discard
         viewer.handleKeyEvent(KeyEvent.ofKey(KeyCode.ESCAPE, 
KeyModifiers.NONE));
         assertThat(viewer.isEditMode()).isTrue();
-        viewer.handleKeyEvent(KeyEvent.ofKey(KeyCode.ESCAPE, 
KeyModifiers.NONE));
+        viewer.handleKeyEvent(KeyEvent.ofKey(KeyCode.ENTER, 
KeyModifiers.NONE));
 
         assertThat(viewer.isEditMode()).isFalse();
         assertThat(Files.readString(sourceFile, 
StandardCharsets.UTF_8)).isEqualTo(original);
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/YamlCompletionTest.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/YamlCompletionTest.java
index 6c09dd13d2d7..fa636d202aab 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/YamlCompletionTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/YamlCompletionTest.java
@@ -1049,6 +1049,27 @@ class YamlCompletionTest {
         assertThat(viewer.findParentYamlKey(3)).isEqualTo("steps");
     }
 
+    @Test
+    void findParentYamlKeyOnDashLineInsideSteps() throws IOException {
+        String yaml = String.join("\n",
+                "- from:",
+                "    uri: timer:tick",
+                "    steps:",
+                "      - ",
+                "");
+
+        Path file = tempDir.resolve("route.camel.yaml");
+        Files.writeString(file, yaml);
+
+        SourceViewer viewer = new SourceViewer();
+        viewer.loadFile(file);
+        viewer.enterEditMode();
+
+        // "      - " is a list item starter inside steps
+        assertThat(viewer.findParentYamlKey(3)).isEqualTo("steps");
+        assertThat(viewer.findEnclosingComponent(3)).isNull();
+    }
+
     @Test
     void findParentYamlKeyInsideRoute() throws IOException {
         String yaml = String.join("\n",
diff --git 
a/dsl/camel-yaml-dsl/camel-yaml-dsl-maven-plugin/src/main/java/org/apache/camel/maven/dsl/yaml/GenerateYamlCompletionMojo.java
 
b/dsl/camel-yaml-dsl/camel-yaml-dsl-maven-plugin/src/main/java/org/apache/camel/maven/dsl/yaml/GenerateYamlCompletionMojo.java
index e4b04711e77f..bd9448ce10db 100644
--- 
a/dsl/camel-yaml-dsl/camel-yaml-dsl-maven-plugin/src/main/java/org/apache/camel/maven/dsl/yaml/GenerateYamlCompletionMojo.java
+++ 
b/dsl/camel-yaml-dsl/camel-yaml-dsl-maven-plugin/src/main/java/org/apache/camel/maven/dsl/yaml/GenerateYamlCompletionMojo.java
@@ -22,10 +22,12 @@ import java.io.StringWriter;
 import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
@@ -99,6 +101,27 @@ public class GenerateYamlCompletionMojo extends 
AbstractMojo {
             ObjectNode nodes = mapper.createObjectNode();
             root.set("nodes", nodes);
 
+            // collect which FQ definitions are step-capable (children of 
ProcessorDefinition)
+            Set<String> stepDefinitions = new java.util.HashSet<>();
+            JsonNode processorDef = definitions.get(PROCESSOR_DEFINITION);
+            if (processorDef != null && processorDef.has("properties")) {
+                processorDef.get("properties").fields().forEachRemaining(e -> {
+                    String ref = resolveRefFq(e.getValue());
+                    if (ref != null) {
+                        stepDefinitions.add(ref);
+                    }
+                });
+            }
+
+            // collect which FQ definitions are top-level elements
+            Set<String> topLevelDefinitions = new java.util.HashSet<>();
+            topLevelProps.fields().forEachRemaining(e -> {
+                String ref = resolveRefFq(e.getValue());
+                if (ref != null) {
+                    topLevelDefinitions.add(ref);
+                }
+            });
+
             // root node — top-level elements
             buildRootNode(nodes, topLevelProps);
 
@@ -109,7 +132,7 @@ public class GenerateYamlCompletionMojo extends 
AbstractMojo {
             buildExpressionNode(nodes, definitions);
 
             // all other definition nodes (EIPs, languages, data formats, etc.)
-            buildDefinitionNodes(nodes, definitions);
+            buildDefinitionNodes(nodes, definitions, stepDefinitions, 
topLevelDefinitions);
 
             // write output
             StringWriter sw = new StringWriter();
@@ -170,6 +193,7 @@ public class GenerateYamlCompletionMojo extends 
AbstractMojo {
         ObjectNode rootNode = mapper.createObjectNode();
         rootNode.put("title", "Root");
         rootNode.put("description", "Top-level YAML DSL elements");
+        rootNode.put("listChildren", true);
 
         ArrayNode children = mapper.createArrayNode();
         Iterator<Map.Entry<String, JsonNode>> fields = topLevelProps.fields();
@@ -207,6 +231,7 @@ public class GenerateYamlCompletionMojo extends 
AbstractMojo {
         ObjectNode stepsNode = mapper.createObjectNode();
         stepsNode.put("title", "Steps");
         stepsNode.put("description", "Processing steps that can be used inside 
a route");
+        stepsNode.put("listChildren", true);
 
         ArrayNode children = mapper.createArrayNode();
         JsonNode props = processorDef.get("properties");
@@ -293,7 +318,9 @@ public class GenerateYamlCompletionMojo extends 
AbstractMojo {
         nodes.set("expression", exprNode);
     }
 
-    private void buildDefinitionNodes(ObjectNode nodes, JsonNode definitions) {
+    private void buildDefinitionNodes(
+            ObjectNode nodes, JsonNode definitions,
+            Set<String> stepDefinitions, Set<String> topLevelDefinitions) {
         Iterator<Map.Entry<String, JsonNode>> fields = definitions.fields();
         while (fields.hasNext()) {
             Map.Entry<String, JsonNode> entry = fields.next();
@@ -318,6 +345,11 @@ public class GenerateYamlCompletionMojo extends 
AbstractMojo {
             ObjectNode node = mapper.createObjectNode();
             enrichNodeMetadata(node, nodeName, fqName, def);
 
+            // mark nodes that appear as list items (in steps or at root level)
+            if (stepDefinitions.contains(fqName) || 
topLevelDefinitions.contains(fqName)) {
+                node.put("isListItem", true);
+            }
+
             ArrayNode children = buildChildrenFromDefinition(def, fqName);
             node.set("children", children);
 
@@ -525,6 +557,16 @@ public class GenerateYamlCompletionMojo extends 
AbstractMojo {
         return optMap;
     }
 
+    private String resolveRefFq(JsonNode prop) {
+        if (prop.has("$ref")) {
+            return prop.get("$ref").asText().replace("#/items/definitions/", 
"");
+        }
+        if (prop.has("items") && prop.get("items").has("$ref")) {
+            return 
prop.get("items").get("$ref").asText().replace("#/items/definitions/", "");
+        }
+        return null;
+    }
+
     private String resolveRef(JsonNode prop) {
         // direct $ref
         if (prop.has("$ref")) {
diff --git 
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl-model.json
 
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl-model.json
index 9d022f1ff00c..ff289173abc1 100644
--- 
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl-model.json
+++ 
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl-model.json
@@ -3,6 +3,7 @@
     "root" : {
       "title" : "Root",
       "description" : "Top-level YAML DSL elements",
+      "listChildren" : true,
       "children" : [ {
         "name" : "beans",
         "type" : "object",
@@ -128,6 +129,7 @@
     "steps" : {
       "title" : "Steps",
       "description" : "Processing steps that can be used inside a route",
+      "listChildren" : true,
       "children" : [ {
         "name" : "a2aSubTask",
         "type" : "object",
@@ -781,12 +783,15 @@
       } ]
     },
     "beansDeserializer" : {
+      "isListItem" : true,
       "children" : [ ]
     },
     "dataFormatsDefinitionDeserializer" : {
+      "isListItem" : true,
       "children" : [ ]
     },
     "errorHandlerDeserializer" : {
+      "isListItem" : true,
       "children" : [ {
         "name" : "deadLetterChannel",
         "type" : "object",
@@ -846,6 +851,7 @@
       } ]
     },
     "routeFromDefinitionDeserializer" : {
+      "isListItem" : true,
       "children" : [ {
         "name" : "description",
         "type" : "string"
@@ -875,6 +881,7 @@
     "a2ASubTask" : {
       "title" : "A2A Sub Task",
       "description" : "Groups route steps and emits A2A (Agent-to-Agent) 
protocol progress events before, after, or when the grouped work fails",
+      "isListItem" : true,
       "children" : [ {
         "name" : "description",
         "type" : "string",
@@ -930,6 +937,7 @@
       "aliases" : [ "fan-in", "reduce", "join", "merge" ],
       "input" : true,
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -1270,6 +1278,7 @@
       "description" : "Calls a Java bean method",
       "label" : "language,core,java",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -1487,6 +1496,7 @@
     "catch" : {
       "title" : "Do Catch",
       "description" : "Catches specific exceptions within a doTry block, 
allowing fine-grained exception handling within the route",
+      "isListItem" : true,
       "children" : [ {
         "name" : "description",
         "type" : "string",
@@ -1531,6 +1541,7 @@
       "label" : "eip,routing",
       "aliases" : [ "router", "dispatch" ],
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -1609,6 +1620,7 @@
       "aliases" : [ "circuit-breaker" ],
       "input" : true,
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -1700,6 +1712,7 @@
       "label" : "eip,enrichment,routing",
       "aliases" : [ "claim-check", "stash" ],
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -1827,6 +1840,7 @@
     "convertBody" : {
       "title" : "Convert Body To",
       "description" : "Converts the message body to a specified Java type 
using Camel's built-in type converters",
+      "isListItem" : true,
       "children" : [ {
         "name" : "charset",
         "type" : "string",
@@ -1870,6 +1884,7 @@
     "convertHeader" : {
       "title" : "Convert Header To",
       "description" : "Converts a message header value to a specified Java 
type using Camel's built-in type converters",
+      "isListItem" : true,
       "children" : [ {
         "name" : "charset",
         "type" : "string",
@@ -1924,6 +1939,7 @@
     "convertVariable" : {
       "title" : "Convert Variable To",
       "description" : "Converts a variable value to a specified Java type 
using Camel's built-in type converters",
+      "isListItem" : true,
       "children" : [ {
         "name" : "charset",
         "type" : "string",
@@ -1987,6 +2003,7 @@
       "label" : "eip,flowcontrol,routing",
       "aliases" : [ "debounce", "delay" ],
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -2076,6 +2093,7 @@
       "label" : "eip,routing",
       "aliases" : [ "dispatch" ],
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -2164,6 +2182,7 @@
       "label" : "eip,enrichment,transformation",
       "aliases" : [ "enrich", "hydrate", "augment" ],
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -2611,6 +2630,7 @@
       "aliases" : [ "filter" ],
       "input" : true,
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -2679,6 +2699,7 @@
     "finally" : {
       "title" : "Do Finally",
       "description" : "Defines steps to always execute after a doTry block 
completes, regardless of whether an exception was thrown or caught",
+      "isListItem" : true,
       "children" : [ {
         "name" : "description",
         "type" : "string",
@@ -2806,6 +2827,7 @@
       "aliases" : [ "dedup", "deduplicate" ],
       "input" : true,
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -2974,6 +2996,7 @@
       "label" : "configuration",
       "input" : true,
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -3034,6 +3057,7 @@
       "label" : "configuration",
       "input" : true,
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -3103,6 +3127,7 @@
       "label" : "configuration",
       "input" : true,
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -3193,6 +3218,7 @@
       "label" : "eip,endpoint,routing",
       "input" : true,
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "note",
         "type" : "string",
@@ -3231,6 +3257,7 @@
       "aliases" : [ "load-balance" ],
       "input" : true,
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -3308,6 +3335,7 @@
       "description" : "Logs a message using an expression that can include 
message body, headers, and other exchange data",
       "label" : "eip,routing",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -3415,6 +3443,7 @@
       "aliases" : [ "loop", "iterate" ],
       "input" : true,
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -3519,6 +3548,7 @@
       "label" : "eip,dataformat,transformation",
       "aliases" : [ "serialize" ],
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -3776,6 +3806,7 @@
       "aliases" : [ "fan-out", "broadcast" ],
       "input" : true,
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -3951,6 +3982,7 @@
       "label" : "configuration",
       "input" : true,
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -4075,6 +4107,7 @@
       "label" : "error,errorhandling",
       "input" : true,
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -4550,6 +4583,7 @@
       "description" : "Pauses a consumer based on a condition, allowing it to 
be resumed later from the last known offset. Useful for controlling ingestion 
rate on polling consumers.",
       "label" : "eip,routing",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -4617,6 +4651,7 @@
       "aliases" : [ "pipeline", "chain" ],
       "input" : true,
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -4666,6 +4701,7 @@
       "description" : "Applies a policy to the route, such as a transactional 
policy or a custom policy for cross-cutting concerns",
       "label" : "configuration",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -4726,6 +4762,7 @@
       "label" : "eip,enrichment,routing",
       "aliases" : [ "poll", "pull" ],
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -4805,6 +4842,7 @@
       "label" : "eip,enrichment,transformation",
       "aliases" : [ "enrich", "hydrate" ],
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -4963,6 +5001,7 @@
       "description" : "Invokes a custom Camel Processor for programmatic 
message processing in Java",
       "label" : "eip,endpoint",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -5071,6 +5110,7 @@
       "description" : "Routes a message to a list of dynamically calculated 
endpoints, determined at runtime from an expression. Each recipient receives a 
copy of the message.",
       "label" : "eip,routing",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -5555,6 +5595,7 @@
       "description" : "Removes a specific header from the message by name",
       "label" : "eip,messaging,transformation",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -5610,6 +5651,7 @@
       "description" : "Removes all message headers whose names match a given 
pattern. Useful for stripping internal Camel headers before sending to external 
systems.",
       "label" : "eip,messaging,transformation",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -5675,6 +5717,7 @@
       "description" : "Removes all exchange properties whose names match a 
given pattern",
       "label" : "eip,messaging,transformation",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -5740,6 +5783,7 @@
       "description" : "Removes a specific exchange property by name",
       "label" : "eip,messaging,transformation",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -5795,6 +5839,7 @@
       "description" : "Removes a specific variable by name",
       "label" : "eip,messaging,transformation",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -5851,6 +5896,7 @@
       "label" : "eip,flowcontrol,routing",
       "input" : true,
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -6234,6 +6280,7 @@
       "description" : "Enables resuming processing from the last known offset 
after a restart, using a resume strategy to track and restore position",
       "label" : "eip,routing",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -6313,6 +6360,7 @@
       "label" : "eip,errorhandling,routing",
       "aliases" : [ "rollback" ],
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -6428,6 +6476,7 @@
       "title" : "Route Configuration",
       "description" : "Defines reusable configuration that is automatically 
applied to matching routes, such as shared error handling or interceptors",
       "label" : "configuration",
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -6524,6 +6573,7 @@
       "label" : "configuration",
       "input" : true,
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -6698,6 +6748,7 @@
       "description" : "Defines a parameterized route template that can be 
instantiated multiple times with different parameter values",
       "label" : "configuration",
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -6775,6 +6826,7 @@
       "description" : "Routes a message through a pre-determined sequence of 
endpoints defined in a header or expression (the routing slip). The list of 
endpoints is evaluated once upfront.",
       "label" : "eip,routing",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -6864,6 +6916,7 @@
       "aliases" : [ "compensate" ],
       "input" : true,
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -6983,6 +7036,7 @@
     "sampling" : {
       "title" : "Sample",
       "description" : "Samples a subset of messages passing through the route, 
either by frequency count or time interval, and discards the rest",
+      "isListItem" : true,
       "children" : [ {
         "name" : "description",
         "type" : "string",
@@ -7022,6 +7076,7 @@
       "description" : "Executes an expression or script in a chosen language 
for side effects without modifying the message body",
       "label" : "eip,transformation",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -7079,6 +7134,7 @@
       "label" : "eip,messaging,transformation",
       "aliases" : [ "map", "transform" ],
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -7135,6 +7191,7 @@
       "description" : "Sets the message exchange pattern (MEP) on the 
exchange, such as InOnly for one-way or InOut for request-reply",
       "label" : "configuration,messaging",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -7191,6 +7248,7 @@
       "description" : "Sets a message header to a value computed by an 
expression",
       "label" : "eip,messaging,transformation",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -7257,6 +7315,7 @@
       "description" : "Sets multiple message headers at once, each computed by 
its own expression",
       "label" : "eip,messaging,transformation",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -7313,6 +7372,7 @@
       "description" : "Sets an exchange property to a value computed by an 
expression",
       "label" : "eip,messaging,transformation",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -7379,6 +7439,7 @@
       "description" : "Sets a variable to a value computed by an expression",
       "label" : "eip,messaging,transformation",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -7445,6 +7506,7 @@
       "description" : "Sets multiple variables at once, each computed by its 
own expression",
       "label" : "eip,messaging,transformation",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -7501,6 +7563,7 @@
       "description" : "Sorts the items in a message body that is a List, using 
a specified comparator or the default ordering",
       "label" : "eip,transformation",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -7569,6 +7632,7 @@
       "aliases" : [ "split", "chunk" ],
       "input" : true,
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -7825,6 +7889,7 @@
       "label" : "eip,routing",
       "input" : true,
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -7874,6 +7939,7 @@
       "description" : "Stops processing of the current message and marks the 
exchange as completed without sending it to any further steps",
       "label" : "eip,flowcontrol,routing",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -7918,6 +7984,7 @@
       "title" : "Templated Route",
       "description" : "Creates a route instance from a route template, binding 
specific parameter values to the template's parameters",
       "label" : "configuration",
+      "isListItem" : true,
       "children" : [ {
         "name" : "routeTemplateRef",
         "type" : "string",
@@ -8103,6 +8170,7 @@
       "description" : "Offloads processing of subsequent steps in the route to 
a thread pool, enabling asynchronous and concurrent message handling",
       "label" : "eip,flowcontrol,routing",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -8249,6 +8317,7 @@
       "label" : "eip,flowcontrol,routing",
       "aliases" : [ "rate-limit", "throttle" ],
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -8379,6 +8448,7 @@
       "description" : "Throws an exception during route processing, either 
creating a new exception instance or re-throwing an existing one",
       "label" : "error,errorhandling",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -8453,6 +8523,7 @@
       "label" : "eip,endpoint,routing",
       "aliases" : [ "sink", "egress" ],
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -8538,6 +8609,7 @@
     "toDynamic" : {
       "title" : "To D",
       "description" : "Sends the message to an endpoint URI computed 
dynamically from an expression, allowing the destination to vary per message",
+      "isListItem" : true,
       "children" : [ {
         "name" : "allowOptimisedComponents",
         "type" : "boolean",
@@ -8619,6 +8691,7 @@
       "description" : "Tokenizes the message body for AI processing, splitting 
text into chunks suitable for embedding or LLM input",
       "label" : "eip,transformation,ai",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -8690,6 +8763,7 @@
       "description" : "Wraps the route in a transaction, ensuring that all 
steps within the transacted block either complete together or roll back on 
failure",
       "label" : "configuration",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -8748,6 +8822,7 @@
       "description" : "Transforms the message body between known data types 
(such as XML, JSON, Java objects) using registered data type transformers",
       "label" : "eip,transformation",
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -8813,6 +8888,7 @@
       "label" : "eip,transformation",
       "aliases" : [ "map", "transform" ],
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -8867,6 +8943,7 @@
     "try" : {
       "title" : "Do Try",
       "description" : "Wraps route steps in a try-catch-finally block for 
fine-grained exception handling within the route",
+      "isListItem" : true,
       "children" : [ {
         "name" : "description",
         "type" : "string",
@@ -8912,6 +8989,7 @@
       "label" : "eip,dataformat,transformation",
       "aliases" : [ "deserialize" ],
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -9227,6 +9305,7 @@
       "label" : "eip,transformation",
       "aliases" : [ "validate", "guard" ],
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -9371,6 +9450,7 @@
       "label" : "eip,endpoint,routing",
       "aliases" : [ "tap", "observe" ],
       "input" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -9581,6 +9661,7 @@
       } ]
     },
     "sSLContextParameters" : {
+      "isListItem" : true,
       "children" : [ {
         "name" : "certAlias",
         "type" : "string"
@@ -18189,6 +18270,7 @@
       "title" : "Rest Configuration",
       "description" : "Configures global settings for the REST DSL, such as 
host, port, context path, binding mode, and the underlying HTTP component to 
use",
       "label" : "rest",
+      "isListItem" : true,
       "children" : [ {
         "name" : "component",
         "type" : "enum",
@@ -18527,6 +18609,7 @@
       "description" : "Defines a REST service with HTTP operations (GET, POST, 
PUT, DELETE, etc.) using the Camel REST DSL",
       "label" : "rest",
       "output" : true,
+      "isListItem" : true,
       "children" : [ {
         "name" : "id",
         "type" : "string",
@@ -19575,6 +19658,7 @@
       "title" : "Transformations",
       "description" : "Container for defining data type transformer 
definitions",
       "label" : "transformation",
+      "isListItem" : true,
       "children" : [ {
         "name" : "customTransformer",
         "type" : "object",
@@ -19689,6 +19773,7 @@
       "title" : "Validations",
       "description" : "Container for defining data type validator definitions",
       "label" : "validation",
+      "isListItem" : true,
       "children" : [ {
         "name" : "customValidator",
         "type" : "object",
diff --git 
a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareCatalogMojo.java
 
b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareCatalogMojo.java
index 09a0d6ae29cf..cfd0d6d071dc 100644
--- 
a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareCatalogMojo.java
+++ 
b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareCatalogMojo.java
@@ -225,6 +225,12 @@ public class PrepareCatalogMojo extends AbstractMojo {
     @Parameter(defaultValue = 
"${project.basedir}/../../core/camel-xml-io/target/classes")
     protected File xmlioSchemaDir;
 
+    /**
+     * The directory where the camel-yaml-dsl model schema are
+     */
+    @Parameter(defaultValue = 
"${project.basedir}/../../dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema")
+    protected File yamlDslSchemaDir;
+
     /**
      * The directory where the camel-main metadata are
      */
@@ -1026,6 +1032,11 @@ public class PrepareCatalogMojo extends AbstractMojo {
         copyFile(this.springSchemaDir.toPath().resolve("camel-spring.xsd"), 
schemasOutDir);
         getLog().info("Copying XML-IO schema");
         copyFile(this.xmlioSchemaDir.toPath().resolve("camel-xml-io.xsd"), 
schemasOutDir);
+        Path yamlModel = 
this.yamlDslSchemaDir.toPath().resolve("camelYamlDsl-model.json");
+        if (Files.exists(yamlModel)) {
+            getLog().info("Copying YAML DSL model");
+            copyFile(yamlModel, schemasOutDir);
+        }
     }
 
     protected void executeMain() throws Exception {

Reply via email to