You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2023/02/02 14:56:03 UTC

[camel] branch camel-3.20.x updated: CAMEL-19001: camel-jbang - Backport 3.21 fixes and others to 3.20.x

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

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


The following commit(s) were added to refs/heads/camel-3.20.x by this push:
     new e649884dc95 CAMEL-19001: camel-jbang - Backport 3.21 fixes and others to 3.20.x
e649884dc95 is described below

commit e649884dc9589819de6ac8c3dc651cd3923a6bc9
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Thu Feb 2 15:49:30 2023 +0100

    CAMEL-19001: camel-jbang - Backport 3.21 fixes and others to 3.20.x
---
 .../apache/camel/dsl/jbang/core/commands/Bind.java |  18 +-
 .../dsl/jbang/core/commands/CamelJBangMain.java    |  11 +-
 .../dsl/jbang/core/commands/CodeRestGenerator.java |  19 +-
 .../CamelTop.java => DependencyCommand.java}       |  17 +-
 .../dsl/jbang/core/commands/DependencyCopy.java    | 107 +++++
 .../{DependencyTree.java => DependencyList.java}   |   6 +-
 .../dsl/jbang/core/commands/ExportBaseCommand.java |  63 +--
 .../dsl/jbang/core/commands/ExportQuarkus.java     |  61 +++
 .../apache/camel/dsl/jbang/core/commands/Init.java |   2 +-
 .../apache/camel/dsl/jbang/core/commands/Run.java  | 250 ++++++++++--
 .../core/commands/action/ActionBaseCommand.java    |   4 -
 .../ActionWatchCommand.java}                       |  38 +-
 .../jbang/core/commands/action/CamelLogAction.java | 449 +++++++++++++++++++++
 .../jbang/core/commands/action/CamelSourceTop.java |   5 +-
 .../core/commands/action/CamelThreadDump.java      |   5 +-
 .../commands/action/RouteControllerAction.java     |   5 +-
 .../core/commands/catalog/CatalogBaseCommand.java  |   1 +
 .../jbang/core/commands/catalog/CatalogDoc.java    |   2 +-
 .../core/commands/catalog/CatalogKamelet.java      |   2 +-
 .../core/commands/process/CamelContextStatus.java  |   4 +-
 .../core/commands/process/CamelContextTop.java     |   4 +-
 .../jbang/core/commands/process/CamelCount.java    |   4 +-
 .../commands/process/CamelProcessorStatus.java     |   4 +-
 .../core/commands/process/CamelRouteStatus.java    |   4 +-
 .../jbang/core/commands/process/CamelStatus.java   |   9 +-
 .../dsl/jbang/core/commands/process/CamelTop.java  |   9 +-
 .../dsl/jbang/core/commands/process/Hawtio.java    |   4 +-
 .../jbang/core/commands/process/ListBlocked.java   |   4 +-
 .../core/commands/process/ListCircuitBreaker.java  |   4 +-
 ...{CamelEndpointStatus.java => ListEndpoint.java} |   6 +-
 .../dsl/jbang/core/commands/process/ListEvent.java |   4 +-
 .../jbang/core/commands/process/ListHealth.java    |   4 +-
 .../jbang/core/commands/process/ListInflight.java  |   4 +-
 .../jbang/core/commands/process/ListMetric.java    |   4 +-
 .../jbang/core/commands/process/ListProcess.java   |   5 +-
 .../jbang/core/commands/process/ListService.java   |   4 +-
 .../dsl/jbang/core/commands/process/ListVault.java |   4 +-
 .../{CamelStatus.java => ProcessWatchCommand.java} |  40 +-
 .../camel/dsl/jbang/core/common/RuntimeUtil.java   |  14 +-
 .../catalog => common}/VersionHelper.java          |   4 +-
 .../camel/dsl/jbang/core/common/XmlHelper.java     |   5 +
 ...ipe.properties => log4j2-background.properties} |  11 +-
 .../src/main/resources/log4j2-export.properties    |   2 +-
 .../src/main/resources/log4j2-no-color.properties  |   2 +-
 .../src/main/resources/log4j2-pipe.properties      |   2 +-
 .../src/main/resources/log4j2.properties           |  15 +-
 .../templates/run-custom-camel-version.tmpl}       |  33 +-
 47 files changed, 1094 insertions(+), 184 deletions(-)

diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Bind.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Bind.java
index 4f8d25739f5..6741b8019f9 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Bind.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Bind.java
@@ -27,6 +27,7 @@ import java.util.Stack;
 import org.apache.camel.github.GitHubResourceResolver;
 import org.apache.camel.impl.engine.DefaultResourceResolvers;
 import org.apache.camel.spi.Resource;
+import org.apache.camel.spi.ResourceResolver;
 import org.apache.camel.util.FileUtil;
 import org.apache.camel.util.IOHelper;
 import org.snakeyaml.engine.v2.api.LoadSettings;
@@ -131,15 +132,26 @@ class Bind extends CamelCommand {
 
         InputStream is;
         String loc;
+        Resource res;
 
         // try local disk first before github
-        Resource res = new DefaultResourceResolvers.FileResolver().resolve("file:" + kamelet + ".kamelet.yaml");
+        ResourceResolver resolver = new DefaultResourceResolvers.FileResolver();
+        try {
+            res = resolver.resolve("file:" + kamelet + ".kamelet.yaml");
+        } finally {
+            resolver.close();
+        }
         if (res.exists()) {
             is = res.getInputStream();
             loc = res.getLocation();
         } else {
-            res = new GitHubResourceResolver().resolve(
-                    "github:apache:camel-kamelets:main:kamelets/" + kamelet + ".kamelet.yaml");
+            resolver = new GitHubResourceResolver();
+            try {
+                res = resolver.resolve(
+                        "github:apache:camel-kamelets:main:kamelets/" + kamelet + ".kamelet.yaml");
+            } finally {
+                resolver.close();
+            }
             loc = res.getLocation();
             URL u = new URL(loc);
             is = u.openStream();
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
index 49ed050991b..5176926abe2 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
@@ -22,6 +22,7 @@ import org.apache.camel.catalog.CamelCatalog;
 import org.apache.camel.catalog.DefaultCamelCatalog;
 import org.apache.camel.dsl.jbang.core.commands.action.CamelAction;
 import org.apache.camel.dsl.jbang.core.commands.action.CamelGCAction;
+import org.apache.camel.dsl.jbang.core.commands.action.CamelLogAction;
 import org.apache.camel.dsl.jbang.core.commands.action.CamelReloadAction;
 import org.apache.camel.dsl.jbang.core.commands.action.CamelResetStatsAction;
 import org.apache.camel.dsl.jbang.core.commands.action.CamelRouteStartAction;
@@ -41,7 +42,6 @@ import org.apache.camel.dsl.jbang.core.commands.catalog.CatalogOther;
 import org.apache.camel.dsl.jbang.core.commands.process.CamelContextStatus;
 import org.apache.camel.dsl.jbang.core.commands.process.CamelContextTop;
 import org.apache.camel.dsl.jbang.core.commands.process.CamelCount;
-import org.apache.camel.dsl.jbang.core.commands.process.CamelEndpointStatus;
 import org.apache.camel.dsl.jbang.core.commands.process.CamelProcessorStatus;
 import org.apache.camel.dsl.jbang.core.commands.process.CamelProcessorTop;
 import org.apache.camel.dsl.jbang.core.commands.process.CamelRouteStatus;
@@ -52,6 +52,7 @@ import org.apache.camel.dsl.jbang.core.commands.process.Hawtio;
 import org.apache.camel.dsl.jbang.core.commands.process.Jolokia;
 import org.apache.camel.dsl.jbang.core.commands.process.ListBlocked;
 import org.apache.camel.dsl.jbang.core.commands.process.ListCircuitBreaker;
+import org.apache.camel.dsl.jbang.core.commands.process.ListEndpoint;
 import org.apache.camel.dsl.jbang.core.commands.process.ListEvent;
 import org.apache.camel.dsl.jbang.core.commands.process.ListHealth;
 import org.apache.camel.dsl.jbang.core.commands.process.ListInflight;
@@ -72,6 +73,7 @@ public class CamelJBangMain implements Callable<Integer> {
         commandLine = new CommandLine(main)
                 .addSubcommand("init", new CommandLine(new Init(main)))
                 .addSubcommand("run", new CommandLine(new Run(main)))
+                .addSubcommand("log", new CommandLine(new CamelLogAction(main)))
                 .addSubcommand("ps", new CommandLine(new ListProcess(main)))
                 .addSubcommand("stop", new CommandLine(new StopProcess(main)))
                 .addSubcommand("get", new CommandLine(new CamelStatus(main))
@@ -80,7 +82,7 @@ public class CamelJBangMain implements Callable<Integer> {
                         .addSubcommand("processor", new CommandLine(new CamelProcessorStatus(main)))
                         .addSubcommand("count", new CommandLine(new CamelCount(main)))
                         .addSubcommand("health", new CommandLine(new ListHealth(main)))
-                        .addSubcommand("endpoint", new CommandLine(new CamelEndpointStatus(main)))
+                        .addSubcommand("endpoint", new CommandLine(new ListEndpoint(main)))
                         .addSubcommand("event", new CommandLine(new ListEvent(main)))
                         .addSubcommand("inflight", new CommandLine(new ListInflight(main)))
                         .addSubcommand("blocked", new CommandLine(new ListBlocked(main)))
@@ -103,6 +105,9 @@ public class CamelJBangMain implements Callable<Integer> {
                         .addSubcommand("thread-dump", new CommandLine(new CamelThreadDump(main)))
                         .addSubcommand("logger", new CommandLine(new LoggerAction(main)))
                         .addSubcommand("gc", new CommandLine(new CamelGCAction(main))))
+                .addSubcommand("dependency", new CommandLine(new DependencyCommand(main))
+                        .addSubcommand("list", new CommandLine(new DependencyList(main)))
+                        .addSubcommand("copy", new CommandLine(new DependencyCopy(main))))
                 .addSubcommand("generate", new CommandLine(new CodeGenerator(main))
                         .addSubcommand("rest", new CommandLine(new CodeRestGenerator(main))))
                 .addSubcommand("catalog", new CommandLine(new CatalogCommand(main))
@@ -116,7 +121,7 @@ public class CamelJBangMain implements Callable<Integer> {
                 .addSubcommand("hawtio", new CommandLine(new Hawtio(main)))
                 .addSubcommand("bind", new CommandLine(new Bind(main)))
                 .addSubcommand("pipe", new CommandLine(new Pipe(main)))
-                .addSubcommand("dependencies", new CommandLine(new DependencyTree(main)))
+                .addSubcommand("dependencies", new CommandLine(new DependencyList(main)))
                 .addSubcommand("export", new CommandLine(new Export(main)))
                 .addSubcommand("completion", new CommandLine(new Complete(main)));
 
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CodeRestGenerator.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CodeRestGenerator.java
index 7db7d0785d7..41787ebfe36 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CodeRestGenerator.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CodeRestGenerator.java
@@ -56,7 +56,8 @@ public class CodeRestGenerator extends CamelCommand {
     private boolean generateRoutes;
     @CommandLine.Option(names = { "-d", "--dto" }, description = "Data Objects")
     private boolean generateDataObjects;
-    @CommandLine.Option(names = { "-run", "--runtime" }, description = "Runtime (quarkus, spring-boot)", defaultValue = "quarkus")
+    @CommandLine.Option(names = { "-run", "--runtime" }, description = "Runtime (quarkus, spring-boot)",
+                        defaultValue = "quarkus")
     private String runtime;
     @CommandLine.Option(names = { "-p", "--package" }, description = "Package for generated models", defaultValue = "model")
     private String packageName;
@@ -104,14 +105,14 @@ public class CodeRestGenerator extends CamelCommand {
     }
 
     private void generateDto() throws IOException {
-        final String CODE = "code";
-        final String GENERATOR_NAME = "quarkus".equals(runtime) ? "jaxrs-spec" : "java-camel";
-        final String LIBRARY = "quarkus".equals(runtime) ? "quarkus" : "spring-boot";
+        final String code = "code";
+        final String generatorName = "quarkus".equals(runtime) ? "jaxrs-spec" : "java-camel";
+        final String library = "quarkus".equals(runtime) ? "quarkus" : "spring-boot";
         File output = Files.createTempDirectory("gendto").toFile();
 
         final CodegenConfigurator configurator = new CodegenConfigurator()
-                .setGeneratorName(GENERATOR_NAME)
-                .setLibrary(LIBRARY)
+                .setGeneratorName(generatorName)
+                .setLibrary(library)
                 .setInputSpec(input)
                 .setModelPackage(packageName)
                 .setAdditionalProperties(
@@ -122,14 +123,12 @@ public class CodeRestGenerator extends CamelCommand {
                                 GENERATE_MODELS, "true",
                                 "generatePom", "false",
                                 "generateApis", "false",
-                                "sourceFolder", CODE
-                        )
-                )
+                                "sourceFolder", code))
                 .setOutputDir(output.getAbsolutePath());
 
         final ClientOptInput clientOptInput = configurator.toClientOptInput();
         new DefaultGenerator().opts(clientOptInput).generate();
-        File generated = new File(Paths.get(output.getAbsolutePath(), CODE, packageName).toUri());
+        File generated = new File(Paths.get(output.getAbsolutePath(), code, packageName).toUri());
         generated.renameTo(new File(packageName));
     }
 }
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelTop.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/DependencyCommand.java
similarity index 64%
copy from dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelTop.java
copy to dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/DependencyCommand.java
index 9f0b3b8c1a0..e34619741ec 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelTop.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/DependencyCommand.java
@@ -14,24 +14,23 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.dsl.jbang.core.commands.process;
+package org.apache.camel.dsl.jbang.core.commands;
 
-import org.apache.camel.dsl.jbang.core.commands.CamelCommand;
-import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
 import picocli.CommandLine;
 
-@CommandLine.Command(name = "top",
-                     description = "Top status of Camel integrations (use top --help to see sub commands)")
-public class CamelTop extends CamelCommand {
+@CommandLine.Command(name = "dependency",
+                     description = "Displays all Camel dependencies required to run (use dependency --help to see sub commands)")
+public class DependencyCommand extends CamelCommand {
 
-    public CamelTop(CamelJBangMain main) {
+    public DependencyCommand(CamelJBangMain main) {
         super(main);
     }
 
     @Override
     public Integer call() throws Exception {
-        // default to top the integrations
-        new CommandLine(new CamelContextTop(getMain())).execute();
+        // default to list
+        new CommandLine(new DependencyList(getMain())).execute();
         return 0;
     }
+
 }
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/DependencyCopy.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/DependencyCopy.java
new file mode 100644
index 00000000000..bd033fa954f
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/DependencyCopy.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.dsl.jbang.core.commands;
+
+import java.io.File;
+import java.util.Properties;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.camel.dsl.jbang.core.common.RuntimeUtil;
+import org.apache.camel.util.CamelCaseOrderedProperties;
+import org.apache.camel.util.FileUtil;
+import picocli.CommandLine;
+
+@CommandLine.Command(name = "copy",
+                     description = "Copies all Camel dependencies required to run to a specific directory")
+public class DependencyCopy extends Export {
+
+    protected static final String EXPORT_DIR = ".camel-jbang/export";
+
+    @CommandLine.Option(names = { "--output-directory" }, description = "Directory where dependencies should be copied",
+                        defaultValue = "lib", required = true)
+    protected String outputDirectory;
+
+    public DependencyCopy(CamelJBangMain main) {
+        super(main);
+    }
+
+    @Override
+    protected Integer export() throws Exception {
+        this.quiet = true; // be quiet and generate from fresh data to ensure the output is up-to-date
+
+        Integer answer = doExport();
+        if (answer == 0) {
+            File buildDir = new File(EXPORT_DIR);
+            Process p = Runtime.getRuntime()
+                    .exec("mvn dependency:copy-dependencies -DincludeScope=compile -DexcludeGroupIds=org.fusesource.jansi,org.apache.logging.log4j -DoutputDirectory=../../"
+                          + outputDirectory,
+                            null,
+                            buildDir);
+            boolean done = p.waitFor(30, TimeUnit.SECONDS);
+            if (!done) {
+                answer = 1;
+            }
+            // cleanup dir after complete
+            FileUtil.removeDir(buildDir);
+        }
+        return answer;
+    }
+
+    protected Integer doExport() throws Exception {
+        // read runtime and gav from profile if not configured
+        File profile = new File(getProfile() + ".properties");
+        if (profile.exists()) {
+            Properties prop = new CamelCaseOrderedProperties();
+            RuntimeUtil.loadProperties(prop, profile);
+            if (this.runtime == null) {
+                this.runtime = prop.getProperty("camel.jbang.runtime");
+            }
+            if (this.gav == null) {
+                this.gav = prop.getProperty("camel.jbang.gav");
+            }
+            // allow configuring versions from profile
+            this.javaVersion = prop.getProperty("camel.jbang.javaVersion", this.javaVersion);
+            this.kameletsVersion = prop.getProperty("camel.jbang.kameletsVersion", this.kameletsVersion);
+            this.localKameletDir = prop.getProperty("camel.jbang.localKameletDir", this.localKameletDir);
+            this.quarkusGroupId = prop.getProperty("camel.jbang.quarkusGroupId", this.quarkusGroupId);
+            this.quarkusArtifactId = prop.getProperty("camel.jbang.quarkusArtifactId", this.quarkusArtifactId);
+            this.quarkusVersion = prop.getProperty("camel.jbang.quarkusVersion", this.quarkusVersion);
+            this.springBootVersion = prop.getProperty("camel.jbang.springBootVersion", this.springBootVersion);
+        }
+
+        // use temporary export dir
+        exportDir = EXPORT_DIR;
+        if (gav == null) {
+            gav = "org.apache.camel:camel-jbang-dummy:1.0";
+        }
+        if (runtime == null) {
+            runtime = "camel-main";
+        }
+
+        if ("spring-boot".equals(runtime) || "camel-spring-boot".equals(runtime)) {
+            return export(new ExportSpringBoot(getMain()));
+        } else if ("quarkus".equals(runtime) || "camel-quarkus".equals(runtime)) {
+            return export(new ExportQuarkus(getMain()));
+        } else if ("main".equals(runtime) || "camel-main".equals(runtime)) {
+            return export(new ExportCamelMain(getMain()));
+        } else {
+            System.err.println("Unknown runtime: " + runtime);
+            return 1;
+        }
+    }
+
+}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/DependencyTree.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/DependencyList.java
similarity index 98%
rename from dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/DependencyTree.java
rename to dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/DependencyList.java
index 040150d1123..3dc475b2cad 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/DependencyTree.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/DependencyList.java
@@ -35,16 +35,16 @@ import org.apache.camel.util.CamelCaseOrderedProperties;
 import org.apache.camel.util.FileUtil;
 import picocli.CommandLine;
 
-@CommandLine.Command(name = "dependencies",
+@CommandLine.Command(name = "list",
                      description = "Displays all Camel dependencies required to run")
-public class DependencyTree extends Export {
+public class DependencyList extends Export {
 
     protected static final String EXPORT_DIR = ".camel-jbang/export";
 
     @CommandLine.Option(names = { "--output" }, description = "Output format (gav or maven)", defaultValue = "gav")
     protected String output;
 
-    public DependencyTree(CamelJBangMain main) {
+    public DependencyList(CamelJBangMain main) {
         super(main);
     }
 
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportBaseCommand.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportBaseCommand.java
index 54139ce6228..4016c4cc556 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportBaseCommand.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportBaseCommand.java
@@ -79,7 +79,7 @@ abstract class ExportBaseCommand extends CamelCommand {
     protected String javaVersion;
 
     @CommandLine.Option(names = {
-            "--kamelets-version" }, description = "Apache Camel Kamelets version", defaultValue = "3.20.0")
+            "--kamelets-version" }, description = "Apache Camel Kamelets version", defaultValue = "3.20.1.1")
     protected String kameletsVersion;
 
     @CommandLine.Option(names = { "--local-kamelet-dir" },
@@ -370,13 +370,16 @@ abstract class ExportBaseCommand extends CamelCommand {
         if (profile.exists()) {
             RuntimeUtil.loadProperties(prop2, profile);
         }
+        prop2.putAll(prop);
+        prepareApplicationProperties(prop2);
 
         for (Map.Entry<Object, Object> entry : prop.entrySet()) {
             String key = entry.getKey().toString();
-            boolean skip = "camel.main.routesCompileDirectory".equals(key)
+            boolean skip = !key.startsWith("camel.main")
+                    || "camel.main.routesCompileDirectory".equals(key)
                     || "camel.main.routesReloadEnabled".equals(key);
-            if (!skip && key.startsWith("camel.main")) {
-                prop2.put(entry.getKey(), entry.getValue());
+            if (skip) {
+                prop2.remove(key);
             }
         }
 
@@ -385,33 +388,39 @@ abstract class ExportBaseCommand extends CamelCommand {
         }
 
         FileOutputStream fos = new FileOutputStream(new File(targetDir, "application.properties"), false);
-        for (Map.Entry<Object, Object> entry : prop2.entrySet()) {
-            String k = entry.getKey().toString();
-            String v = entry.getValue().toString();
+        try {
+            for (Map.Entry<Object, Object> entry : prop2.entrySet()) {
+                String k = entry.getKey().toString();
+                String v = entry.getValue().toString();
 
-            boolean skip = k.startsWith("camel.jbang.") || k.startsWith("jkube.");
-            if (skip) {
-                continue;
-            }
+                boolean skip = k.startsWith("camel.jbang.") || k.startsWith("jkube.");
+                if (skip) {
+                    continue;
+                }
 
-            // files are now loaded in classpath
-            v = v.replaceAll("file:", "classpath:");
-            if ("camel.main.routesIncludePattern".equals(k)) {
-                // camel.main.routesIncludePattern should remove all .java as we use spring boot
-                // to load them
-                // camel.main.routesIncludePattern should remove all file: classpath: as we copy
-                // them to src/main/resources/camel where camel auto-load from
-                v = Arrays.stream(v.split(","))
-                        .filter(n -> !n.endsWith(".java") && !n.startsWith("file:") && !n.startsWith("classpath:"))
-                        .collect(Collectors.joining(","));
-            }
-            if (!v.isBlank()) {
-                String line = applicationPropertyLine(k, v);
-                fos.write(line.getBytes(StandardCharsets.UTF_8));
-                fos.write("\n".getBytes(StandardCharsets.UTF_8));
+                // files are now loaded in classpath
+                v = v.replaceAll("file:", "classpath:");
+                if ("camel.main.routesIncludePattern".equals(k)) {
+                    // camel.main.routesIncludePattern should remove all .java as we use move them to regular src/main/java
+                    // camel.main.routesIncludePattern should remove all file: classpath: as we copy
+                    // them to src/main/resources/camel where camel autoload from
+                    v = Arrays.stream(v.split(","))
+                            .filter(n -> !n.endsWith(".java") && !n.startsWith("file:") && !n.startsWith("classpath:"))
+                            .collect(Collectors.joining(","));
+                }
+                if (!v.isBlank()) {
+                    String line = applicationPropertyLine(k, v);
+                    fos.write(line.getBytes(StandardCharsets.UTF_8));
+                    fos.write("\n".getBytes(StandardCharsets.UTF_8));
+                }
             }
+        } finally {
+            IOHelper.close(fos);
         }
-        IOHelper.close(fos);
+    }
+
+    protected void prepareApplicationProperties(Properties properties) {
+        // noop
     }
 
     protected void copyMavenWrapper() throws Exception {
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportQuarkus.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportQuarkus.java
index cc44f627417..bdfcda47383 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportQuarkus.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportQuarkus.java
@@ -20,9 +20,13 @@ import java.io.File;
 import java.io.FileOutputStream;
 import java.io.InputStream;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
+import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
+import java.util.StringJoiner;
+import java.util.stream.Collectors;
 
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
@@ -143,6 +147,63 @@ class ExportQuarkus extends Export {
         return 0;
     }
 
+    @Override
+    protected void prepareApplicationProperties(Properties properties) {
+        // quarkus native compilation only works if we specify each resource explicit
+
+        StringJoiner sj = new StringJoiner(",");
+        StringJoiner sj2 = new StringJoiner(",");
+        for (Map.Entry<Object, Object> entry : properties.entrySet()) {
+            String k = entry.getKey().toString();
+            String v = entry.getValue().toString();
+
+            if ("camel.main.routesIncludePattern".equals(k)) {
+                v = Arrays.stream(v.split(","))
+                        .map(ExportQuarkus::removeScheme) // remove scheme and routes are in camel sub-folder
+                        .map(s -> "camel/" + s)
+                        .collect(Collectors.joining(","));
+                sj.add(v);
+            }
+            // extra classpath files
+            if ("camel.jbang.classpathFiles".equals(k)) {
+                v = Arrays.stream(v.split(","))
+                        .map(ExportQuarkus::removeScheme) // remove scheme
+                        .collect(Collectors.joining(","));
+                sj2.add(v);
+            }
+        }
+
+        String routes = sj.length() > 0 ? sj.toString() : null;
+        String extra = sj2.length() > 0 ? sj2.toString() : null;
+
+        if (routes != null || extra != null) {
+            sj = new StringJoiner(",");
+            String e = properties.getProperty("quarkus.native.resources.includes");
+            if (e != null) {
+                sj.add(e);
+            }
+            if (routes != null) {
+                sj.add(routes);
+            }
+            if (extra != null) {
+                sj.add(extra);
+            }
+            if (sj.length() > 0) {
+                properties.setProperty("quarkus.native.resources.includes", sj.toString());
+            }
+            if (routes != null) {
+                properties.setProperty("camel.main.routes-include-pattern", routes);
+            }
+        }
+    }
+
+    private static String removeScheme(String s) {
+        if (s.contains(":")) {
+            return StringHelper.after(s, ":");
+        }
+        return s;
+    }
+
     private void createGradleProperties(File output) throws Exception {
         InputStream is = ExportQuarkus.class.getClassLoader().getResourceAsStream("templates/quarkus-gradle-properties.tmpl");
         String context = IOHelper.loadText(is);
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Init.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Init.java
index 85ee118ff2b..1d3ce0d93e4 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Init.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Init.java
@@ -59,7 +59,7 @@ class Init extends CamelCommand {
     private String fromKamelet;
 
     @Option(names = {
-            "--kamelets-version" }, description = "Apache Camel Kamelets version", defaultValue = "3.20.0")
+            "--kamelets-version" }, description = "Apache Camel Kamelets version", defaultValue = "3.20.1.1")
     private String kameletsVersion;
 
     @Option(names = {
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java
index dd59b5d4eb5..a543981cd9f 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java
@@ -49,7 +49,9 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 import io.apicurio.datamodels.Library;
 import io.apicurio.datamodels.openapi.models.OasDocument;
 import org.apache.camel.CamelContext;
+import org.apache.camel.catalog.DefaultCamelCatalog;
 import org.apache.camel.dsl.jbang.core.common.RuntimeUtil;
+import org.apache.camel.dsl.jbang.core.common.VersionHelper;
 import org.apache.camel.generator.openapi.RestDslGenerator;
 import org.apache.camel.impl.lw.LightweightCamelContext;
 import org.apache.camel.main.KameletMain;
@@ -93,6 +95,8 @@ class Run extends CamelCommand {
     private boolean silentRun;
     private boolean pipeRun;
 
+    private File logFile;
+
     //CHECKSTYLE:OFF
     @Parameters(description = "The Camel file(s) to run. If no files specified then application.properties is used as source for which files to run.",
             arity = "0..9", paramLabel = "<files>", parameterConsumer = FilesConsumer.class)
@@ -100,6 +104,12 @@ class Run extends CamelCommand {
 
     List<String> files = new ArrayList<>();
 
+    @Option(names = { "--background" }, defaultValue = "false", description = "Run in the background")
+    boolean background;
+
+    @Option(names = { "--camel-version" }, description = "To run using a different Camel version than the default version.")
+    String camelVersion;
+
     @Option(names = { "--profile" }, scope = CommandLine.ScopeType.INHERIT, defaultValue = "application",
             description = "Profile to use, which refers to loading properties file with the given profile name. By default application.properties is loaded.")
     String profile;
@@ -264,32 +274,12 @@ class Run extends CamelCommand {
         removeDir(work);
         work.mkdirs();
 
-        Properties profileProperties = null;
-        File profilePropertiesFile = new File(getProfile() + ".properties");
-        if (profilePropertiesFile.exists()) {
-            profileProperties = loadProfileProperties(profilePropertiesFile);
-            // logging level/color may be configured in the properties file
-            loggingLevel = profileProperties.getProperty("loggingLevel", loggingLevel);
-            loggingColor
-                    = "true".equals(profileProperties.getProperty("loggingColor", loggingColor ? "true" : "false"));
-            loggingJson
-                    = "true".equals(profileProperties.getProperty("loggingJson", loggingJson ? "true" : "false"));
-            if (propertiesFiles == null) {
-                propertiesFiles = "file:" + profilePropertiesFile.getName();
-            } else {
-                propertiesFiles = propertiesFiles + ",file:" + profilePropertiesFile.getName();
-            }
-            repos = profileProperties.getProperty("camel.jbang.repos", repos);
-            mavenSettings = profileProperties.getProperty("camel.jbang.maven-settings", mavenSettings);
-            mavenSettingsSecurity = profileProperties.getProperty("camel.jbang.maven-settings-security", mavenSettingsSecurity);
-            openapi = profileProperties.getProperty("camel.jbang.openApi", openapi);
-            download = "true".equals(profileProperties.getProperty("camel.jbang.download", download ? "true" : "false"));
-        }
-
-        // generate open-api early
+        Properties profileProperties = loadProfileProperties();
+        configureLogging();
         if (openapi != null) {
             generateOpenApi();
         }
+
         // route code as option
         if (code != null) {
             // store code in temporary file
@@ -303,7 +293,9 @@ class Run extends CamelCommand {
             String routes = profileProperties != null ? profileProperties.getProperty("camel.main.routesIncludePattern") : null;
             if (routes == null) {
                 if (!silentRun) {
-                    System.out.println("Cannot run because " + getProfile() + ".properties file does not exist");
+                    System.out
+                            .println("Cannot run because " + getProfile()
+                                     + ".properties file does not exist or camel.main.routesIncludePattern is not configured");
                     return 1;
                 } else {
                     // silent-run then auto-detect all files (except properties as they are loaded explicit or via profile)
@@ -319,11 +311,7 @@ class Run extends CamelCommand {
             files = files.stream().distinct().collect(Collectors.toList());
         }
 
-        // configure logging first
-        configureLogging();
-
         final KameletMain main = createMainInstance();
-
         main.setRepos(repos);
         main.setDownload(download);
         main.setFresh(fresh);
@@ -344,11 +332,12 @@ class Run extends CamelCommand {
         if (modeline) {
             writeSetting(main, profileProperties, "camel.main.modeline", "true");
         }
-        writeSetting(main, profileProperties, "camel.jbang.openApi", openapi);
+        writeSetting(main, profileProperties, "camel.jbang.open-api", openapi);
         writeSetting(main, profileProperties, "camel.jbang.repos", repos);
         writeSetting(main, profileProperties, "camel.jbang.health", health ? "true" : "false");
         writeSetting(main, profileProperties, "camel.jbang.console", console ? "true" : "false");
-        writeSetting(main, profileProperties, "camel.main.routesCompileDirectory", WORK_DIR);
+        // the runtime version of Camel is what is loaded via the catalog
+        writeSetting(main, profileProperties, "camel.jbang.camel-version", new DefaultCamelCatalog().getCatalogVersion());
         // merge existing dependencies with --deps
         String deps = RuntimeUtil.getDependencies(profileProperties);
         if (deps.isBlank()) {
@@ -391,7 +380,7 @@ class Run extends CamelCommand {
                 () -> maxIdleSeconds > 0 ? String.valueOf(maxIdleSeconds) : null);
         writeSetting(main, profileProperties, "camel.jbang.platform-http.port",
                 () -> port > 0 ? String.valueOf(port) : null);
-        writeSetting(main, profileProperties, "camel.jbang.jfr", jfr || jfrProfile != null ? "jfr" : null);
+        writeSetting(main, profileProperties, "camel.jbang.jfr", jfr || jfrProfile != null ? "jfr" : null); // TODO: "true" instead of "jfr" ?
         writeSetting(main, profileProperties, "camel.jbang.jfr-profile", jfrProfile != null ? jfrProfile : null);
 
         StringJoiner js = new StringJoiner(",");
@@ -481,7 +470,6 @@ class Run extends CamelCommand {
                 sjReload.add(file.substring(5));
             }
         }
-
         writeSetting(main, profileProperties, "camel.main.name", name);
 
         if (js.length() > 0) {
@@ -557,9 +545,198 @@ class Run extends CamelCommand {
             writeSettings("camel.component.properties.location", loc);
         }
 
+        // okay we have validated all input and are ready to run
+        if (camelVersion != null) {
+            // run in another JVM with different camel version (foreground or background)
+            boolean custom = camelVersion.contains("-");
+            if (custom) {
+                // custom camel distribution
+                return runCustomCamelVersion(main);
+            } else {
+                // apache camel distribution
+                return runCamelVersion(main);
+            }
+        } else if (background) {
+            // spawn new JVM to run in background
+            return runBackground(main);
+        } else {
+            // run default in current JVM with same camel version
+            return runKameletMain(main);
+        }
+    }
+
+    private Properties loadProfileProperties() throws Exception {
+        Properties answer = null;
+
+        File profilePropertiesFile = new File(getProfile() + ".properties");
+        if (profilePropertiesFile.exists()) {
+            answer = loadProfileProperties(profilePropertiesFile);
+            // logging level/color may be configured in the properties file
+            loggingLevel = answer.getProperty("loggingLevel", loggingLevel);
+            loggingColor
+                    = "true".equals(answer.getProperty("loggingColor", loggingColor ? "true" : "false"));
+            loggingJson
+                    = "true".equals(answer.getProperty("loggingJson", loggingJson ? "true" : "false"));
+            if (propertiesFiles == null) {
+                propertiesFiles = "file:" + getProfile() + ".properties";
+            } else {
+                propertiesFiles = propertiesFiles + ",file:" + profilePropertiesFile.getName();
+            }
+            repos = answer.getProperty("camel.jbang.repos", repos);
+            mavenSettings = answer.getProperty("camel.jbang.maven-settings", mavenSettings);
+            mavenSettingsSecurity = answer.getProperty("camel.jbang.maven-settings-security", mavenSettingsSecurity);
+            openapi = answer.getProperty("camel.jbang.open-api", openapi);
+            download = "true".equals(answer.getProperty("camel.jbang.download", download ? "true" : "false"));
+            background = "true".equals(answer.getProperty("camel.jbang.background", background ? "true" : "false"));
+            camelVersion = answer.getProperty("camel.jbang.camel-version", camelVersion);
+        }
+        return answer;
+    }
+
+    protected int runCamelVersion(KameletMain main) throws Exception {
+        String cmd = ProcessHandle.current().info().commandLine().orElse(null);
+        if (cmd != null) {
+            cmd = StringHelper.after(cmd, "main.CamelJBang ");
+        }
+        if (cmd == null) {
+            System.err.println("No Camel integration files to run");
+            return 1;
+        }
+        if (background) {
+            cmd = cmd.replaceFirst("--background=true", "");
+            cmd = cmd.replaceFirst("--background", "");
+        }
+        cmd = cmd.replaceFirst("--camel-version=" + camelVersion, "");
+        // need to use jbang command to specify camel version
+        String jbang = "jbang run -Dcamel.jbang.version=" + camelVersion;
+        if (repos != null) {
+            jbang += " --repos=" + repos;
+        }
+        cmd = jbang + " camel@apache/camel " + cmd;
+
+        ProcessBuilder pb = new ProcessBuilder();
+        String[] arr = cmd.split("\\s+"); // TODO: safe split
+        List<String> args = Arrays.asList(arr);
+        pb.command(args);
+        if (background) {
+            Process p = pb.start();
+            System.out.println("Running Camel integration: " + name + " (version: " + camelVersion
+                               + ") in background with PID: " + p.pid());
+            return 0;
+        } else {
+            pb.inheritIO(); // run in foreground (with IO so logs are visible)
+            Process p = pb.start();
+            // wait for that process to exit as we run in foreground
+            return p.waitFor();
+        }
+    }
+
+    protected int runBackground(KameletMain main) throws Exception {
+        String cmd = ProcessHandle.current().info().commandLine().orElse(null);
+        if (cmd != null) {
+            cmd = StringHelper.after(cmd, "main.CamelJBang ");
+        }
+        if (cmd == null) {
+            System.err.println("No Camel integration files to run");
+            return 1;
+        }
+        cmd = cmd.replaceFirst("--background=true", "");
+        cmd = cmd.replaceFirst("--background", "");
+        cmd = "camel " + cmd;
+
+        ProcessBuilder pb = new ProcessBuilder();
+        String[] arr = cmd.split("\\s+"); // TODO: safe split
+        List<String> args = Arrays.asList(arr);
+        pb.command(args);
+        Process p = pb.start();
+        System.out.println("Running Camel integration: " + name + " in background with PID: " + p.pid());
+        return 0;
+    }
+
+    protected int runCustomCamelVersion(KameletMain main) throws Exception {
+        InputStream is = Run.class.getClassLoader().getResourceAsStream("templates/run-custom-camel-version.tmpl");
+        String content = IOHelper.loadText(is);
+        IOHelper.close(is);
+
+        content = content.replaceFirst("\\{\\{ \\.JavaVersion }}", "11"); // TODO: java 11 or 17
+        if (repos != null) {
+            content = content.replaceFirst("\\{\\{ \\.MavenRepositories }}", "//REPOS " + repos);
+        }
+
+        // use custom distribution of camel
+        StringBuilder sb = new StringBuilder();
+        sb.append(String.format("//DEPS org.apache.camel:camel-bom:%s@pom\n", camelVersion));
+        sb.append(String.format("//DEPS org.apache.camel:camel-core:%s\n", camelVersion));
+        sb.append(String.format("//DEPS org.apache.camel:camel-core-engine:%s\n", camelVersion));
+        sb.append(String.format("//DEPS org.apache.camel:camel-main:%s\n", camelVersion));
+        sb.append(String.format("//DEPS org.apache.camel:camel-java-joor-dsl:%s\n", camelVersion));
+        sb.append(String.format("//DEPS org.apache.camel:camel-kamelet:%s\n", camelVersion));
+        content = content.replaceFirst("\\{\\{ \\.CamelDependencies }}", sb.toString());
+
+        // use apache distribution of camel-jbang
+        String v = camelVersion.substring(0, camelVersion.lastIndexOf('.'));
+        sb = new StringBuilder();
+        sb.append(String.format("//DEPS org.apache.camel:camel-jbang-core:%s\n", v));
+        sb.append(String.format("//DEPS org.apache.camel:camel-kamelet-main:%s\n", v));
+        sb.append(String.format("//DEPS org.apache.camel:camel-resourceresolver-github:%s\n", v));
+        if (VersionHelper.isGE(v, "3.19.0")) {
+            sb.append(String.format("//DEPS org.apache.camel:camel-cli-connector:%s\n", v));
+        }
+        content = content.replaceFirst("\\{\\{ \\.CamelJBangDependencies }}", sb.toString());
+
+        String fn = WORK_DIR + "/CustomCamelJBang.java";
+        Files.write(Paths.get(fn), content.getBytes(StandardCharsets.UTF_8));
+
+        String cmd = ProcessHandle.current().info().commandLine().orElse(null);
+        if (cmd != null) {
+            cmd = StringHelper.after(cmd, "main.CamelJBang ");
+        }
+        if (cmd == null) {
+            System.err.println("No Camel integration files to run");
+            return 1;
+        }
+        if (background) {
+            cmd = cmd.replaceFirst("--background=true", "");
+            cmd = cmd.replaceFirst("--background", "");
+        }
+        if (repos != null) {
+            if (!VersionHelper.isGE(v, "3.18.1")) {
+                // --repos is not supported in 3.18.0 or older, so remove
+                cmd = cmd.replaceFirst("--repos=" + repos, "");
+            }
+        }
+
+        cmd = cmd.replaceFirst("--camel-version=" + camelVersion, "");
+        // need to use jbang command to specify camel version
+        String jbang = "jbang " + WORK_DIR + "/CustomCamelJBang.java ";
+        cmd = jbang + cmd;
+
+        ProcessBuilder pb = new ProcessBuilder();
+        String[] arr = cmd.split("\\s+"); // TODO: safe split
+        List<String> args = Arrays.asList(arr);
+        pb.command(args);
+        if (background) {
+            Process p = pb.start();
+            System.out.println("Running Camel integration: " + name + " (version: " + camelVersion
+                               + ") in background with PID: " + p.pid());
+            return 0;
+        } else {
+            pb.inheritIO(); // run in foreground (with IO so logs are visible)
+            Process p = pb.start();
+            // wait for that process to exit as we run in foreground
+            return p.waitFor();
+        }
+    }
+
+    protected int runKameletMain(KameletMain main) throws Exception {
         main.start();
         main.run();
 
+        // cleanup and delete log file
+        if (logFile != null) {
+            FileUtil.deleteFile(logFile);
+        }
+
         return main.getExitCode();
     }
 
@@ -667,7 +844,7 @@ class Run extends CamelCommand {
         return file;
     }
 
-    private KameletMain createMainInstance() throws Exception {
+    private KameletMain createMainInstance() {
         KameletMain main;
         if (localKameletDir == null || localKameletDir.isEmpty()) {
             main = new KameletMain();
@@ -701,6 +878,13 @@ class Run extends CamelCommand {
             writeSettings("loggingLevel", loggingLevel);
             writeSettings("loggingColor", loggingColor ? "true" : "false");
             writeSettings("loggingJson", loggingJson ? "true" : "false");
+            if (!pipeRun) {
+                // remember log file
+                File dir = new File(System.getProperty("user.home"), ".camel");
+                String name = RuntimeUtil.getPid() + ".log";
+                logFile = new File(dir, name);
+                logFile.deleteOnExit();
+            }
         } else {
             RuntimeUtil.configureLog("off", false, false, false, false);
             writeSettings("loggingLevel", "off");
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/ActionBaseCommand.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/ActionBaseCommand.java
index 4381965d9d6..ff2f019c13e 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/ActionBaseCommand.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/ActionBaseCommand.java
@@ -20,7 +20,6 @@ import java.io.File;
 import java.io.FileInputStream;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.regex.Pattern;
 
 import org.apache.camel.dsl.jbang.core.commands.CamelCommand;
 import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
@@ -33,9 +32,6 @@ import org.apache.camel.util.json.Jsoner;
 
 abstract class ActionBaseCommand extends CamelCommand {
 
-    private static final String[] DSL_EXT = new String[] { "groovy", "java", "js", "jsh", "kts", "xml", "yaml" };
-    private static final Pattern PATTERN = Pattern.compile("([\\w|\\-.])+");
-
     public ActionBaseCommand(CamelJBangMain main) {
         super(main);
     }
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelStatus.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/ActionWatchCommand.java
similarity index 51%
copy from dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelStatus.java
copy to dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/ActionWatchCommand.java
index 3f3c44df414..8fbd5421db5 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelStatus.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/ActionWatchCommand.java
@@ -14,24 +14,44 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.dsl.jbang.core.commands.process;
+package org.apache.camel.dsl.jbang.core.commands.action;
 
-import org.apache.camel.dsl.jbang.core.commands.CamelCommand;
 import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import org.fusesource.jansi.Ansi;
+import org.fusesource.jansi.AnsiConsole;
 import picocli.CommandLine;
 
-@CommandLine.Command(name = "get",
-                     description = "Get status of Camel integrations (use get --help to see sub commands)")
-public class CamelStatus extends CamelCommand {
+abstract class ActionWatchCommand extends ActionBaseCommand {
 
-    public CamelStatus(CamelJBangMain main) {
+    @CommandLine.Option(names = { "--watch" },
+                        description = "Execute periodically and showing output fullscreen")
+    boolean watch;
+
+    public ActionWatchCommand(CamelJBangMain main) {
         super(main);
     }
 
     @Override
     public Integer call() throws Exception {
-        // default to get the integrations
-        new CommandLine(new CamelContextStatus(getMain())).execute();
-        return 0;
+        int exit;
+        if (watch) {
+            do {
+                exit = doCall();
+                if (exit == 0) {
+                    // use 2-sec delay in watch mode
+                    Thread.sleep(2000);
+                }
+            } while (exit == 0);
+        } else {
+            exit = doCall();
+        }
+        return exit;
+    }
+
+    protected void clearScreen() {
+        AnsiConsole.out().print(Ansi.ansi().eraseScreen().cursor(1, 1));
     }
+
+    protected abstract Integer doCall() throws Exception;
+
 }
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelLogAction.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelLogAction.java
new file mode 100644
index 00000000000..75d934dadc6
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelLogAction.java
@@ -0,0 +1,449 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.dsl.jbang.core.commands.action;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.LineNumberReader;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
+import java.util.Set;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.regex.Pattern;
+
+import org.apache.camel.catalog.impl.TimePatternConverter;
+import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import org.apache.camel.dsl.jbang.core.common.ProcessHelper;
+import org.apache.camel.util.StopWatch;
+import org.apache.camel.util.StringHelper;
+import org.apache.camel.util.json.JsonObject;
+import org.fusesource.jansi.Ansi;
+import org.fusesource.jansi.AnsiConsole;
+import picocli.CommandLine;
+
+@CommandLine.Command(name = "log",
+                     description = "Tail logs from running Camel integrations")
+public class CamelLogAction extends ActionBaseCommand {
+
+    private static final int NAME_MAX_WIDTH = 25;
+    private static final int NAME_MIN_WIDTH = 10;
+
+    @CommandLine.Parameters(description = "Name or pid of running Camel integration. (default selects all)", arity = "0..1")
+    String name = "*";
+
+    @CommandLine.Option(names = { "--logging-color" }, defaultValue = "true", description = "Use colored logging")
+    boolean loggingColor = true;
+
+    @CommandLine.Option(names = { "--timestamp" }, defaultValue = "true",
+                        description = "Print timestamp.")
+    boolean timestamp = true;
+
+    @CommandLine.Option(names = { "--follow" }, defaultValue = "true",
+                        description = "Keep following and outputting new log lines (use ctrl + c to exit).")
+    boolean follow = true;
+
+    @CommandLine.Option(names = { "--prefix" }, defaultValue = "true",
+                        description = "Print prefix with running Camel integration name.")
+    boolean prefix = true;
+
+    @CommandLine.Option(names = { "--tail" },
+                        description = "The number of lines from the end of the logs to show. Defaults to showing all logs.")
+    int tail;
+
+    @CommandLine.Option(names = { "--since" },
+                        description = "Return logs newer than a relative duration like 5s, 2m, or 1h. The value is in seconds if no unit specified.")
+    String since;
+
+    @CommandLine.Option(names = { "--find" },
+                        description = "Find and highlight matching text (ignore case).", arity = "0..*")
+    String[] find;
+
+    @CommandLine.Option(names = { "--grep" },
+                        description = "Filter logs to only output lines matching text (ignore case).", arity = "0..*")
+    String[] grep;
+
+    String findAnsi;
+
+    private int nameMaxWidth;
+
+    private final Map<String, Ansi.Color> colors = new HashMap<>();
+
+    public CamelLogAction(CamelJBangMain main) {
+        super(main);
+    }
+
+    @Override
+    public Integer call() throws Exception {
+        Map<Long, Row> rows = new LinkedHashMap<>();
+
+        // find new pids
+        updatePids(rows);
+        if (!rows.isEmpty()) {
+            // read existing log files (skip by tail/since)
+            if (find != null) {
+                findAnsi = Ansi.ansi().fg(Ansi.Color.BLACK).bg(Ansi.Color.YELLOW).a("$0").reset().toString();
+                for (int i = 0; i < find.length; i++) {
+                    String f = find[i];
+                    f = Pattern.quote(f);
+                    find[i] = f;
+                }
+            }
+            if (grep != null) {
+                findAnsi = Ansi.ansi().fg(Ansi.Color.BLACK).bg(Ansi.Color.YELLOW).a("$0").reset().toString();
+                for (int i = 0; i < grep.length; i++) {
+                    String f = grep[i];
+                    f = Pattern.quote(f);
+                    grep[i] = f;
+                }
+            }
+            Date limit = null;
+            if (since != null) {
+                long millis;
+                if (StringHelper.isDigit(since)) {
+                    // is in seconds by default
+                    millis = TimePatternConverter.toMilliSeconds(since) * 1000;
+                } else {
+                    millis = TimePatternConverter.toMilliSeconds(since);
+                }
+                limit = new Date(System.currentTimeMillis() - millis);
+            }
+
+            // dump existing log lines
+            tailLogFiles(rows, tail, limit);
+            dumpLogFiles(rows, tail);
+        }
+
+        if (follow) {
+            boolean waitMessage = true;
+            StopWatch watch = new StopWatch();
+            do {
+                if (rows.isEmpty()) {
+                    if (waitMessage) {
+                        System.out.println("Waiting for logs ...");
+                        waitMessage = false;
+                    }
+                    Thread.sleep(500);
+                    updatePids(rows);
+                } else {
+                    waitMessage = true;
+                    if (watch.taken() > 500) {
+                        // check for new logs
+                        updatePids(rows);
+                        watch.restart();
+                    }
+                    int lines = readLogFiles(rows);
+                    if (lines > 0) {
+                        dumpLogFiles(rows, 0);
+                    } else {
+                        Thread.sleep(100);
+                    }
+                }
+            } while (true);
+        }
+
+        return 0;
+    }
+
+    private void updatePids(Map<Long, Row> rows) {
+        List<Long> pids = findPids(name);
+        ProcessHandle.allProcesses()
+                .filter(ph -> pids.contains(ph.pid()))
+                .forEach(ph -> {
+                    JsonObject root = loadStatus(ph.pid());
+                    if (root != null) {
+                        Row row = new Row();
+                        row.pid = "" + ph.pid();
+                        JsonObject context = (JsonObject) root.get("context");
+                        if (context == null) {
+                            return;
+                        }
+                        row.name = context.getString("name");
+                        if ("CamelJBang".equals(row.name)) {
+                            row.name = ProcessHelper.extractName(root, ph);
+                        }
+                        int len = row.name.length();
+                        if (len < NAME_MIN_WIDTH) {
+                            len = NAME_MIN_WIDTH;
+                        }
+                        if (len > NAME_MAX_WIDTH) {
+                            len = NAME_MAX_WIDTH;
+                        }
+                        if (len > nameMaxWidth) {
+                            nameMaxWidth = len;
+                        }
+                        if (!rows.containsKey(ph.pid())) {
+                            rows.put(ph.pid(), row);
+                        }
+                    }
+                });
+
+        // remove pids that are no long active from the rows
+        Set<Long> remove = new HashSet<>();
+        for (long pid : rows.keySet()) {
+            if (!pids.contains(pid)) {
+                remove.add(pid);
+            }
+        }
+        for (long pid : remove) {
+            rows.remove(pid);
+        }
+    }
+
+    private int readLogFiles(Map<Long, Row> rows) throws Exception {
+        int lines = 0;
+
+        for (Row row : rows.values()) {
+            if (row.reader == null) {
+                File log = logFile(row.pid);
+                if (log.exists()) {
+                    row.reader = new LineNumberReader(new FileReader(log));
+                }
+            }
+            if (row.reader != null) {
+                String line;
+                do {
+                    try {
+                        line = row.reader.readLine();
+                        if (line != null) {
+                            boolean valid = true;
+                            if (grep != null) {
+                                valid = isValidGrep(line);
+                            }
+                            if (valid) {
+                                lines++;
+                                // switch fifo to be unlimited as we use it for new log lines
+                                if (row.fifo == null || row.fifo instanceof ArrayBlockingQueue) {
+                                    row.fifo = new ArrayDeque<>();
+                                }
+                                row.fifo.offer(line);
+                            }
+                        }
+                    } catch (IOException e) {
+                        // ignore
+                        line = null;
+                    }
+                } while (line != null);
+            }
+        }
+
+        return lines;
+    }
+
+    private void dumpLogFiles(Map<Long, Row> rows, int tail) {
+        List<String> lines = new ArrayList<>();
+        for (Row row : rows.values()) {
+            Queue<String> queue = row.fifo;
+            if (queue != null) {
+                for (String l : queue) {
+                    lines.add(row.name + "| " + l);
+                }
+                row.fifo.clear();
+            }
+        }
+        // sort lines
+        lines.sort(this::compareLogLine);
+        if (tail > 0) {
+            // cut according to tail
+            int pos = lines.size() - tail;
+            if (pos > 0) {
+                lines = lines.subList(pos, lines.size());
+            }
+        }
+        lines.forEach(l -> {
+            String name = StringHelper.before(l, "| ");
+            String line = StringHelper.after(l, "| ");
+            printLine(name, line);
+        });
+    }
+
+    private int compareLogLine(String l1, String l2) {
+        l1 = unescapeAnsi(l1);
+        l2 = unescapeAnsi(l2);
+
+        String t1 = StringHelper.after(l1, "| ");
+        t1 = StringHelper.before(t1, "  ");
+        String t2 = StringHelper.after(l2, "| ");
+        t2 = StringHelper.before(t2, "  ");
+        return t1.compareTo(t2);
+    }
+
+    protected void printLine(String name, String line) {
+        if (!prefix) {
+            name = null;
+        }
+        if (!timestamp) {
+            // after timestamp is after 2 sine-space
+            int pos = line.indexOf(' ');
+            pos = line.indexOf(' ', pos + 1);
+            if (pos != -1) {
+                line = line.substring(pos + 1);
+            }
+        }
+        if (loggingColor) {
+            if (name != null) {
+                Ansi.Color color = colors.get(name);
+                if (color == null) {
+                    // grab a new color
+                    int idx = (colors.size() % 6) + 1;
+                    color = Ansi.Color.values()[idx];
+                    colors.put(name, color);
+                }
+                String n = String.format("%-" + nameMaxWidth + "s", name);
+                AnsiConsole.out().print(Ansi.ansi().fg(color).a(n).a("| ").reset());
+            }
+        } else {
+            line = unescapeAnsi(line);
+            if (name != null) {
+                String n = String.format("%-" + nameMaxWidth + "s", name);
+                System.out.print(n);
+                System.out.print("| ");
+            }
+        }
+        if (find != null || grep != null) {
+            String before = StringHelper.before(line, "---");
+            String after = StringHelper.after(line, "---");
+            if (find != null) {
+                for (String f : find) {
+                    after = after.replaceAll("(?i)" + f, findAnsi);
+                }
+            }
+            if (grep != null) {
+                for (String g : grep) {
+                    after = after.replaceAll("(?i)" + g, findAnsi);
+                }
+            }
+            line = before + "---" + after;
+        }
+        if (loggingColor) {
+            AnsiConsole.out().println(line);
+        } else {
+            System.out.println(line);
+        }
+    }
+
+    private static File logFile(String pid) {
+        File dir = new File(System.getProperty("user.home"), ".camel");
+        String name = pid + ".log";
+        return new File(dir, name);
+    }
+
+    private void tailLogFiles(Map<Long, Row> rows, int tail, Date limit) throws Exception {
+        for (Row row : rows.values()) {
+            File log = logFile(row.pid);
+            if (log.exists()) {
+                row.reader = new LineNumberReader(new FileReader(log));
+                String line;
+                if (tail == 0) {
+                    row.fifo = new ArrayDeque<>();
+                } else {
+                    row.fifo = new ArrayBlockingQueue<>(tail);
+                }
+                do {
+                    line = row.reader.readLine();
+                    if (line != null) {
+                        boolean valid = isValidSince(limit, line);
+                        if (valid && grep != null) {
+                            valid = isValidGrep(line);
+                        }
+                        if (valid) {
+                            while (!row.fifo.offer(line)) {
+                                row.fifo.poll();
+                            }
+                        }
+                    }
+                } while (line != null);
+            }
+        }
+    }
+
+    private boolean isValidSince(Date limit, String line) {
+        if (limit == null) {
+            return true;
+        }
+        // the log can be in color or not so we need to unescape always
+        line = unescapeAnsi(line);
+        String ts = StringHelper.before(line, "  ");
+
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
+        try {
+            Date row = sdf.parse(ts);
+            return row.compareTo(limit) >= 0;
+        } catch (ParseException e) {
+            // ignore
+        }
+        return false;
+    }
+
+    private boolean isValidGrep(String line) {
+        if (grep == null) {
+            return true;
+        }
+        // the log can be in color or not so we need to unescape always
+        line = unescapeAnsi(line);
+        String after = StringHelper.after(line, "---");
+        for (String g : grep) {
+            boolean m = Pattern.compile("(?i)" + g).matcher(after).find();
+            if (m) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private String unescapeAnsi(String line) {
+        // unescape ANSI colors
+        StringBuilder sb = new StringBuilder();
+        boolean escaping = false;
+        char[] arr = line.toCharArray();
+        for (int i = 0; i < arr.length; i++) {
+            char ch = arr[i];
+            if (escaping) {
+                if (ch == 'm') {
+                    escaping = false;
+                }
+                continue;
+            }
+            char ch2 = i < arr.length - 1 ? arr[i + 1] : 0;
+            if (ch == 27 && ch2 == '[') {
+                escaping = true;
+                continue;
+            }
+
+            sb.append(ch);
+        }
+        return sb.toString();
+    }
+
+    private static class Row {
+        String pid;
+        String name;
+        Queue<String> fifo;
+        LineNumberReader reader;
+
+    }
+
+}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelSourceTop.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelSourceTop.java
index 5c6a4215591..bda0bb38c11 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelSourceTop.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelSourceTop.java
@@ -33,7 +33,7 @@ import picocli.CommandLine;
 import picocli.CommandLine.Command;
 
 @Command(name = "source", description = "List top processors (source) in a running Camel integration")
-public class CamelSourceTop extends ActionBaseCommand {
+public class CamelSourceTop extends ActionWatchCommand {
 
     @CommandLine.Parameters(description = "Name or pid of running Camel integration", arity = "1")
     String name;
@@ -53,7 +53,7 @@ public class CamelSourceTop extends ActionBaseCommand {
     }
 
     @Override
-    public Integer call() throws Exception {
+    public Integer doCall() throws Exception {
         List<Row> rows = new ArrayList<>();
 
         List<Long> pids = findPids(name);
@@ -140,6 +140,7 @@ public class CamelSourceTop extends ActionBaseCommand {
         // sort rows
         rows.sort(this::sortRow);
 
+        clearScreen();
         if (!rows.isEmpty()) {
             printSource(rows);
         }
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelThreadDump.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelThreadDump.java
index e12dbd2dda0..1ee5b4c147f 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelThreadDump.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelThreadDump.java
@@ -38,7 +38,7 @@ import picocli.CommandLine;
 import picocli.CommandLine.Command;
 
 @Command(name = "thread-dump", description = "List threads in a running Camel integration")
-public class CamelThreadDump extends ActionBaseCommand {
+public class CamelThreadDump extends ActionWatchCommand {
 
     @CommandLine.Parameters(description = "Name or pid of running Camel integration", arity = "1")
     String name;
@@ -66,7 +66,7 @@ public class CamelThreadDump extends ActionBaseCommand {
     }
 
     @Override
-    public Integer call() throws Exception {
+    public Integer doCall() throws Exception {
         List<Row> rows = new ArrayList<>();
 
         List<Long> pids = findPids(name);
@@ -132,6 +132,7 @@ public class CamelThreadDump extends ActionBaseCommand {
         // sort rows
         rows.sort(this::sortRow);
 
+        clearScreen();
         if (!rows.isEmpty()) {
             int total = jo.getInteger("threadCount");
             int peak = jo.getInteger("peakThreadCount");
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/RouteControllerAction.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/RouteControllerAction.java
index 5412738ce7e..f5e0a85acfd 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/RouteControllerAction.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/RouteControllerAction.java
@@ -39,7 +39,7 @@ import picocli.CommandLine;
 import picocli.CommandLine.Command;
 
 @Command(name = "route-controller", description = "List status of route controller in a running Camel integration")
-public class RouteControllerAction extends ActionBaseCommand {
+public class RouteControllerAction extends ActionWatchCommand {
 
     @CommandLine.Parameters(description = "Name or pid of running Camel integration", arity = "1")
     String name;
@@ -67,7 +67,7 @@ public class RouteControllerAction extends ActionBaseCommand {
     }
 
     @Override
-    public Integer call() throws Exception {
+    public Integer doCall() throws Exception {
         List<Row> rows = new ArrayList<>();
 
         List<Long> pids = findPids(name);
@@ -134,6 +134,7 @@ public class RouteControllerAction extends ActionBaseCommand {
         // sort rows
         rows.sort(this::sortRow);
 
+        clearScreen();
         if (!rows.isEmpty()) {
             if (supervising) {
                 if (header) {
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogBaseCommand.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogBaseCommand.java
index 448bba7a364..5cb43bfe1ae 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogBaseCommand.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogBaseCommand.java
@@ -28,6 +28,7 @@ import org.apache.camel.catalog.CamelCatalog;
 import org.apache.camel.catalog.DefaultCamelCatalog;
 import org.apache.camel.dsl.jbang.core.commands.CamelCommand;
 import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import org.apache.camel.dsl.jbang.core.common.VersionHelper;
 import org.apache.camel.main.download.MavenGav;
 import org.apache.camel.tooling.model.ArtifactModel;
 import picocli.CommandLine;
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogDoc.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogDoc.java
index c5866b117fb..33297b470f2 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogDoc.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogDoc.java
@@ -70,7 +70,7 @@ public class CatalogDoc extends CamelCommand {
     boolean headers;
 
     @CommandLine.Option(names = {
-            "--kamelets-version" }, description = "Apache Camel Kamelets version", defaultValue = "3.20.0")
+            "--kamelets-version" }, description = "Apache Camel Kamelets version", defaultValue = "3.20.1.1")
     String kameletsVersion;
 
     final CamelCatalog catalog = new DefaultCamelCatalog(true);
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogKamelet.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogKamelet.java
index 0d9903a6ef0..bf8af192b3c 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogKamelet.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogKamelet.java
@@ -52,7 +52,7 @@ public class CatalogKamelet extends CamelCommand {
     String filterName;
 
     @CommandLine.Option(names = {
-            "--kamelets-version" }, description = "Apache Camel Kamelets version", defaultValue = "3.20.0")
+            "--kamelets-version" }, description = "Apache Camel Kamelets version", defaultValue = "3.20.1.1")
     String kameletsVersion;
 
     public CatalogKamelet(CamelJBangMain main) {
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelContextStatus.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelContextStatus.java
index 1a331516dba..eb87dc1f2fb 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelContextStatus.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelContextStatus.java
@@ -35,7 +35,7 @@ import picocli.CommandLine.Command;
 
 @Command(name = "context",
          description = "Get status of Camel integrations")
-public class CamelContextStatus extends ProcessBaseCommand {
+public class CamelContextStatus extends ProcessWatchCommand {
 
     @CommandLine.Parameters(description = "Name or pid of running Camel integration", arity = "0..1")
     String name = "*";
@@ -49,7 +49,7 @@ public class CamelContextStatus extends ProcessBaseCommand {
     }
 
     @Override
-    public Integer call() throws Exception {
+    public Integer doCall() throws Exception {
         List<Row> rows = new ArrayList<>();
 
         List<Long> pids = findPids(name);
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelContextTop.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelContextTop.java
index 9cdbcc8c334..ed36eb58b8e 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelContextTop.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelContextTop.java
@@ -34,7 +34,7 @@ import picocli.CommandLine.Command;
 
 @Command(name = "context",
          description = "Top status of Camel integrations")
-public class CamelContextTop extends ProcessBaseCommand {
+public class CamelContextTop extends ProcessWatchCommand {
 
     @CommandLine.Parameters(description = "Name or pid of running Camel integration", arity = "0..1")
     String name = "*";
@@ -48,7 +48,7 @@ public class CamelContextTop extends ProcessBaseCommand {
     }
 
     @Override
-    public Integer call() throws Exception {
+    public Integer doCall() throws Exception {
         List<Row> rows = new ArrayList<>();
 
         List<Long> pids = findPids(name);
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelCount.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelCount.java
index 69515307887..f43d3f6819c 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelCount.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelCount.java
@@ -34,7 +34,7 @@ import picocli.CommandLine.Command;
 
 @Command(name = "count",
          description = "Get total and failed exchanges for running integrations")
-public class CamelCount extends ProcessBaseCommand {
+public class CamelCount extends ProcessWatchCommand {
 
     @CommandLine.Parameters(description = "Name or pid of running Camel integration", arity = "0..1")
     String name = "*";
@@ -56,7 +56,7 @@ public class CamelCount extends ProcessBaseCommand {
     }
 
     @Override
-    public Integer call() throws Exception {
+    public Integer doCall() throws Exception {
         List<Row> rows = new ArrayList<>();
 
         List<Long> pids = findPids(name);
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelProcessorStatus.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelProcessorStatus.java
index 39a30060c69..f752d71da1d 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelProcessorStatus.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelProcessorStatus.java
@@ -35,7 +35,7 @@ import picocli.CommandLine;
 import picocli.CommandLine.Command;
 
 @Command(name = "processor", description = "Get status of Camel processors")
-public class CamelProcessorStatus extends ProcessBaseCommand {
+public class CamelProcessorStatus extends ProcessWatchCommand {
 
     @CommandLine.Parameters(description = "Name or pid of running Camel integration", arity = "0..1")
     String name = "*";
@@ -61,7 +61,7 @@ public class CamelProcessorStatus extends ProcessBaseCommand {
     }
 
     @Override
-    public Integer call() throws Exception {
+    public Integer doCall() throws Exception {
         List<Row> rows = new ArrayList<>();
 
         List<Long> pids = findPids(name);
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelRouteStatus.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelRouteStatus.java
index f5cb0545a34..2e65d9ec7a3 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelRouteStatus.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelRouteStatus.java
@@ -34,7 +34,7 @@ import picocli.CommandLine;
 import picocli.CommandLine.Command;
 
 @Command(name = "route", description = "Get status of Camel routes")
-public class CamelRouteStatus extends ProcessBaseCommand {
+public class CamelRouteStatus extends ProcessWatchCommand {
 
     @CommandLine.Parameters(description = "Name or pid of running Camel integration", arity = "0..1")
     String name = "*";
@@ -64,7 +64,7 @@ public class CamelRouteStatus extends ProcessBaseCommand {
     }
 
     @Override
-    public Integer call() throws Exception {
+    public Integer doCall() throws Exception {
         List<Row> rows = new ArrayList<>();
 
         List<Long> pids = findPids(name);
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelStatus.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelStatus.java
index 3f3c44df414..596cd72c7b8 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelStatus.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelStatus.java
@@ -24,6 +24,10 @@ import picocli.CommandLine;
                      description = "Get status of Camel integrations (use get --help to see sub commands)")
 public class CamelStatus extends CamelCommand {
 
+    @CommandLine.Option(names = { "--watch" },
+                        description = "Execute periodically and showing output fullscreen")
+    boolean watch;
+
     public CamelStatus(CamelJBangMain main) {
         super(main);
     }
@@ -31,7 +35,8 @@ public class CamelStatus extends CamelCommand {
     @Override
     public Integer call() throws Exception {
         // default to get the integrations
-        new CommandLine(new CamelContextStatus(getMain())).execute();
-        return 0;
+        CamelContextStatus cmd = new CamelContextStatus(getMain());
+        cmd.watch = watch;
+        return new CommandLine(cmd).execute();
     }
 }
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelTop.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelTop.java
index 9f0b3b8c1a0..5a3af05e8f3 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelTop.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelTop.java
@@ -24,6 +24,10 @@ import picocli.CommandLine;
                      description = "Top status of Camel integrations (use top --help to see sub commands)")
 public class CamelTop extends CamelCommand {
 
+    @CommandLine.Option(names = { "--watch" },
+                        description = "Execute periodically and showing output fullscreen")
+    boolean watch;
+
     public CamelTop(CamelJBangMain main) {
         super(main);
     }
@@ -31,7 +35,8 @@ public class CamelTop extends CamelCommand {
     @Override
     public Integer call() throws Exception {
         // default to top the integrations
-        new CommandLine(new CamelContextTop(getMain())).execute();
-        return 0;
+        CamelContextTop cmd = new CamelContextTop(getMain());
+        cmd.watch = watch;
+        return new CommandLine(cmd).execute();
     }
 }
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/Hawtio.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/Hawtio.java
index b5d925231fa..8d9e1dcd1ff 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/Hawtio.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/Hawtio.java
@@ -37,8 +37,8 @@ public class Hawtio extends CamelCommand {
     String name;
 
     @CommandLine.Option(names = { "--version" },
-                        description = "Version of the Hawtio web console", defaultValue = "2.16.2")
-    String version = "2.16.2";
+                        description = "Version of the Hawtio web console", defaultValue = "2.17.0")
+    String version = "2.17.0";
 
     // use port 8888 as 8080 is too commonly used
     @CommandLine.Option(names = { "--port" },
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListBlocked.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListBlocked.java
index 5cc8ac73359..800eba36ca3 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListBlocked.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListBlocked.java
@@ -34,7 +34,7 @@ import picocli.CommandLine.Command;
 
 @Command(name = "blocked",
          description = "Get blocked messages of Camel integrations")
-public class ListBlocked extends ProcessBaseCommand {
+public class ListBlocked extends ProcessWatchCommand {
 
     @CommandLine.Parameters(description = "Name or pid of running Camel integration", arity = "0..1")
     String name = "*";
@@ -48,7 +48,7 @@ public class ListBlocked extends ProcessBaseCommand {
     }
 
     @Override
-    public Integer call() throws Exception {
+    public Integer doCall() throws Exception {
         List<Row> rows = new ArrayList<>();
 
         List<Long> pids = findPids(name);
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListCircuitBreaker.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListCircuitBreaker.java
index d91051babaa..9d79ed9568e 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListCircuitBreaker.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListCircuitBreaker.java
@@ -34,7 +34,7 @@ import picocli.CommandLine.Command;
 
 @Command(name = "circuit-breaker",
          description = "Get status of Circuit Breaker EIPs")
-public class ListCircuitBreaker extends ProcessBaseCommand {
+public class ListCircuitBreaker extends ProcessWatchCommand {
 
     @CommandLine.Parameters(description = "Name or pid of running Camel integration", arity = "0..1")
     String name = "*";
@@ -48,7 +48,7 @@ public class ListCircuitBreaker extends ProcessBaseCommand {
     }
 
     @Override
-    public Integer call() throws Exception {
+    public Integer doCall() throws Exception {
         List<Row> rows = new ArrayList<>();
 
         List<Long> pids = findPids(name);
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelEndpointStatus.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListEndpoint.java
similarity index 98%
rename from dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelEndpointStatus.java
rename to dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListEndpoint.java
index 53d2c44192f..e3205346c86 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelEndpointStatus.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListEndpoint.java
@@ -34,7 +34,7 @@ import picocli.CommandLine;
 import picocli.CommandLine.Command;
 
 @Command(name = "endpoint", description = "Get usage of Camel endpoints")
-public class CamelEndpointStatus extends ProcessBaseCommand {
+public class ListEndpoint extends ProcessWatchCommand {
 
     @CommandLine.Parameters(description = "Name or pid of running Camel integration", arity = "0..1")
     String name = "*";
@@ -63,12 +63,12 @@ public class CamelEndpointStatus extends ProcessBaseCommand {
                         description = "List endpoint URI without query parameters (short)")
     boolean shortUri;
 
-    public CamelEndpointStatus(CamelJBangMain main) {
+    public ListEndpoint(CamelJBangMain main) {
         super(main);
     }
 
     @Override
-    public Integer call() throws Exception {
+    public Integer doCall() throws Exception {
         List<Row> rows = new ArrayList<>();
 
         // make it easier to filter
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListEvent.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListEvent.java
index 9f201aecc24..fca78be3c4a 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListEvent.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListEvent.java
@@ -34,7 +34,7 @@ import picocli.CommandLine.Command;
 
 @Command(name = "event",
          description = "Get latest events of Camel integrations")
-public class ListEvent extends ProcessBaseCommand {
+public class ListEvent extends ProcessWatchCommand {
 
     @CommandLine.Parameters(description = "Name or pid of running Camel integration", arity = "0..1")
     String name = "*";
@@ -52,7 +52,7 @@ public class ListEvent extends ProcessBaseCommand {
     }
 
     @Override
-    public Integer call() throws Exception {
+    public Integer doCall() throws Exception {
         List<Row> rows = new ArrayList<>();
 
         List<Long> pids = findPids(name);
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListHealth.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListHealth.java
index 5ba23909a2a..8d69917ba7b 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListHealth.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListHealth.java
@@ -40,7 +40,7 @@ import picocli.CommandLine;
 import picocli.CommandLine.Command;
 
 @Command(name = "health", description = "Get health check status of running Camel integrations")
-public class ListHealth extends ProcessBaseCommand {
+public class ListHealth extends ProcessWatchCommand {
 
     @CommandLine.Option(names = { "--sort" },
                         description = "Sort by pid, name or age", defaultValue = "pid")
@@ -75,7 +75,7 @@ public class ListHealth extends ProcessBaseCommand {
     }
 
     @Override
-    public Integer call() throws Exception {
+    public Integer doCall() throws Exception {
         final List<Row> rows = new ArrayList<>();
 
         // include stack-traces
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListInflight.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListInflight.java
index ce0ae54e0c5..941431dce9e 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListInflight.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListInflight.java
@@ -34,7 +34,7 @@ import picocli.CommandLine.Command;
 
 @Command(name = "inflight",
          description = "Get inflight messages of Camel integrations")
-public class ListInflight extends ProcessBaseCommand {
+public class ListInflight extends ProcessWatchCommand {
 
     @CommandLine.Parameters(description = "Name or pid of running Camel integration", arity = "0..1")
     String name = "*";
@@ -48,7 +48,7 @@ public class ListInflight extends ProcessBaseCommand {
     }
 
     @Override
-    public Integer call() throws Exception {
+    public Integer doCall() throws Exception {
         List<Row> rows = new ArrayList<>();
 
         List<Long> pids = findPids(name);
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListMetric.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListMetric.java
index b4252053865..b69b646b1d9 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListMetric.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListMetric.java
@@ -34,7 +34,7 @@ import picocli.CommandLine.Command;
 
 @Command(name = "metric",
          description = "Get metrics (micrometer) of running Camel integrations")
-public class ListMetric extends ProcessBaseCommand {
+public class ListMetric extends ProcessWatchCommand {
 
     @CommandLine.Parameters(description = "Name or pid of running Camel integration", arity = "0..1")
     String name = "*";
@@ -60,7 +60,7 @@ public class ListMetric extends ProcessBaseCommand {
     }
 
     @Override
-    public Integer call() throws Exception {
+    public Integer doCall() throws Exception {
         List<Row> rows = new ArrayList<>();
 
         List<Long> pids = findPids(name);
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListProcess.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListProcess.java
index 85a9475e3e8..8d67cfff03b 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListProcess.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListProcess.java
@@ -32,7 +32,7 @@ import picocli.CommandLine;
 import picocli.CommandLine.Command;
 
 @Command(name = "ps", description = "List running Camel integrations")
-public class ListProcess extends ProcessBaseCommand {
+public class ListProcess extends ProcessWatchCommand {
 
     @CommandLine.Option(names = { "--sort" },
                         description = "Sort by pid, name or age", defaultValue = "pid")
@@ -46,8 +46,7 @@ public class ListProcess extends ProcessBaseCommand {
         super(main);
     }
 
-    @Override
-    public Integer call() throws Exception {
+    protected Integer doCall() throws Exception {
         List<Row> rows = new ArrayList<>();
 
         List<Long> pids = findPids("*");
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListService.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListService.java
index 3a45113de8b..9b56a84ef15 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListService.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListService.java
@@ -34,7 +34,7 @@ import picocli.CommandLine.Command;
 
 @Command(name = "service",
          description = "Get services of Camel integrations")
-public class ListService extends ProcessBaseCommand {
+public class ListService extends ProcessWatchCommand {
 
     @CommandLine.Parameters(description = "Name or pid of running Camel integration", arity = "0..1")
     String name = "*";
@@ -48,7 +48,7 @@ public class ListService extends ProcessBaseCommand {
     }
 
     @Override
-    public Integer call() throws Exception {
+    public Integer doCall() throws Exception {
         List<Row> rows = new ArrayList<>();
 
         List<Long> pids = findPids(name);
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListVault.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListVault.java
index d6092254a00..8ce83a353cb 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListVault.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ListVault.java
@@ -34,7 +34,7 @@ import picocli.CommandLine.Command;
 
 @Command(name = "vault",
          description = "List secrets from security vaults used by running Camel integrations")
-public class ListVault extends ProcessBaseCommand {
+public class ListVault extends ProcessWatchCommand {
 
     @CommandLine.Option(names = { "--sort" },
                         description = "Sort by pid, name", defaultValue = "pid")
@@ -45,7 +45,7 @@ public class ListVault extends ProcessBaseCommand {
     }
 
     @Override
-    public Integer call() throws Exception {
+    public Integer doCall() throws Exception {
         List<Row> rows = new ArrayList<>();
 
         List<Long> pids = findPids("*");
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelStatus.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ProcessWatchCommand.java
similarity index 52%
copy from dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelStatus.java
copy to dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ProcessWatchCommand.java
index 3f3c44df414..cb8c6dbb560 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelStatus.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/ProcessWatchCommand.java
@@ -16,22 +16,46 @@
  */
 package org.apache.camel.dsl.jbang.core.commands.process;
 
-import org.apache.camel.dsl.jbang.core.commands.CamelCommand;
 import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import org.fusesource.jansi.Ansi;
+import org.fusesource.jansi.AnsiConsole;
 import picocli.CommandLine;
 
-@CommandLine.Command(name = "get",
-                     description = "Get status of Camel integrations (use get --help to see sub commands)")
-public class CamelStatus extends CamelCommand {
+/**
+ * Base class for commands that can run in watch mode.
+ */
+abstract class ProcessWatchCommand extends ProcessBaseCommand {
+
+    @CommandLine.Option(names = { "--watch" },
+                        description = "Execute periodically and showing output fullscreen")
+    boolean watch;
 
-    public CamelStatus(CamelJBangMain main) {
+    public ProcessWatchCommand(CamelJBangMain main) {
         super(main);
     }
 
     @Override
     public Integer call() throws Exception {
-        // default to get the integrations
-        new CommandLine(new CamelContextStatus(getMain())).execute();
-        return 0;
+        int exit;
+        if (watch) {
+            do {
+                clearScreen();
+                exit = doCall();
+                if (exit == 0) {
+                    // use 2-sec delay in watch mode
+                    Thread.sleep(2000);
+                }
+            } while (exit == 0);
+        } else {
+            exit = doCall();
+        }
+        return exit;
+    }
+
+    protected void clearScreen() {
+        AnsiConsole.out().print(Ansi.ansi().eraseScreen().cursor(1, 1));
     }
+
+    protected abstract Integer doCall() throws Exception;
+
 }
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/RuntimeUtil.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/RuntimeUtil.java
index edd832c98f8..837e698ef7e 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/RuntimeUtil.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/RuntimeUtil.java
@@ -32,8 +32,12 @@ public final class RuntimeUtil {
     private RuntimeUtil() {
     }
 
-    public static void configureLog(String level, boolean color, boolean json, boolean pipe, boolean export) {
+    public static void configureLog(
+            String level, boolean color, boolean json, boolean pipe, boolean export) {
         if (INIT_DONE.compareAndSet(false, true)) {
+            long pid = ProcessHandle.current().pid();
+            System.setProperty("pid", "" + pid);
+
             if (export) {
                 Configurator.initialize("CamelJBang", "log4j2-export.properties");
             } else if (pipe) {
@@ -99,4 +103,12 @@ public final class RuntimeUtil {
         return deps;
     }
 
+    public static String getPid() {
+        try {
+            return "" + ProcessHandle.current().pid();
+        } catch (Throwable e) {
+            return null;
+        }
+    }
+
 }
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/VersionHelper.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/VersionHelper.java
similarity index 95%
rename from dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/VersionHelper.java
rename to dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/VersionHelper.java
index 587a56b70d8..cc22c2985e5 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/VersionHelper.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/VersionHelper.java
@@ -14,11 +14,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.dsl.jbang.core.commands.catalog;
+package org.apache.camel.dsl.jbang.core.common;
 
 import org.apache.camel.util.StringHelper;
 
-final class VersionHelper {
+public final class VersionHelper {
 
     private VersionHelper() {
     }
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/XmlHelper.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/XmlHelper.java
index afc58f99cd9..452307af4cd 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/XmlHelper.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/XmlHelper.java
@@ -42,6 +42,11 @@ public final class XmlHelper {
             factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
         } catch (ParserConfigurationException e) {
         }
+        try {
+            // Disable the external-parameter-entities by default
+            factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
+        } catch (ParserConfigurationException e) {
+        }
         // setup the SecurityManager by default if it's apache xerces
         try {
             Class<?> smClass = ObjectHelper.loadClass("org.apache.xerces.util.SecurityManager");
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2-pipe.properties b/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2-background.properties
similarity index 76%
copy from dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2-pipe.properties
copy to dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2-background.properties
index f6ed178ad0d..5e700f81157 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2-pipe.properties
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2-background.properties
@@ -15,16 +15,17 @@
 ## limitations under the License.
 ## ---------------------------------------------------------------------------
 
+# file logger
 appender.file.type = File
 appender.file.name = file
-appender.file.fileName = ${sys:user.home}/.camel/camel-pipe.log
+appender.file.fileName = ${sys:user.home}/.camel/${sys:pid}.log
 appender.file.createOnDemand = true
 appender.file.append = false
-
 appender.file.layout.type = PatternLayout
-# logging style that is similar to spring boot (no color)
-appender.file.layout.pattern = %d{yyyy-MM-dd HH:mm:ss.SSS} %5p %pid --- [%15.15t] %-40.40c : %m%n
+# logging style that is similar to spring boot
+appender.file.layout.pattern = %style{%d{yyyy-MM-dd HH:mm:ss.SSS}}{Dim} %highlight{%5p} %style{%pid}{Magenta} %style{---}{Dim} %style{[%15.15t]}{Dim} %style{%-35.35c}{Cyan} : %m%n
 
+# log to file
+rootLogger = INFO,file
 rootLogger.level = INFO
-rootLogger.appenderRef.out.ref = file
 
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2-export.properties b/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2-export.properties
index c09e2c668a4..730ef1eb162 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2-export.properties
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2-export.properties
@@ -23,7 +23,7 @@ appender.file.append = false
 
 appender.file.layout.type = PatternLayout
 # logging style that is similar to spring boot (no color)
-appender.file.layout.pattern = %d{yyyy-MM-dd HH:mm:ss.SSS} %5p %pid --- [%15.15t] %-40.40c : %m%n
+appender.file.layout.pattern = %d{yyyy-MM-dd HH:mm:ss.SSS} %5p %pid --- [%15.15t] %-35.35c : %m%n
 
 rootLogger.level = INFO
 rootLogger.appenderRef.out.ref = file
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2-no-color.properties b/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2-no-color.properties
index 2bb0c0ddc93..6dcdec667d3 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2-no-color.properties
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2-no-color.properties
@@ -20,7 +20,7 @@ appender.stdout.name = out
 appender.stdout.layout.type = PatternLayout
 
 # logging style that is similar to spring boot (no color)
-appender.stdout.layout.pattern = %d{yyyy-MM-dd HH:mm:ss.SSS} %5p %pid --- [%15.15t] %-40.40c : %m%n
+appender.stdout.layout.pattern = %d{yyyy-MM-dd HH:mm:ss.SSS} %5p %pid --- [%15.15t] %-35.35c : %m%n
 
 rootLogger.level = INFO
 rootLogger.appenderRef.out.ref = out
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2-pipe.properties b/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2-pipe.properties
index f6ed178ad0d..1349f98ad8d 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2-pipe.properties
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2-pipe.properties
@@ -23,7 +23,7 @@ appender.file.append = false
 
 appender.file.layout.type = PatternLayout
 # logging style that is similar to spring boot (no color)
-appender.file.layout.pattern = %d{yyyy-MM-dd HH:mm:ss.SSS} %5p %pid --- [%15.15t] %-40.40c : %m%n
+appender.file.layout.pattern = %d{yyyy-MM-dd HH:mm:ss.SSS} %5p %pid --- [%15.15t] %-35.35c : %m%n
 
 rootLogger.level = INFO
 rootLogger.appenderRef.out.ref = file
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2.properties b/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2.properties
index bd77ce59db0..5561cfee4a4 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2.properties
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/log4j2.properties
@@ -15,13 +15,24 @@
 ## limitations under the License.
 ## ---------------------------------------------------------------------------
 
+# console logger
 appender.stdout.type = Console
 appender.stdout.name = out
 appender.stdout.layout.type = PatternLayout
+# logging style that is similar to spring boot
+appender.stdout.layout.pattern = %style{%d{yyyy-MM-dd HH:mm:ss.SSS}}{Dim} %highlight{%5p} %style{%pid}{Magenta} %style{---}{Dim} %style{[%15.15t]}{Dim} %style{%-35.35c}{Cyan} : %m%n
 
+# file logger
+appender.file.type = File
+appender.file.name = file
+appender.file.fileName = ${sys:user.home}/.camel/${sys:pid}.log
+appender.file.createOnDemand = true
+appender.file.append = false
+appender.file.layout.type = PatternLayout
 # logging style that is similar to spring boot
-appender.stdout.layout.pattern = %style{%d{yyyy-MM-dd HH:mm:ss.SSS}}{Dim} %highlight{%5p} %style{%pid}{Magenta} %style{---}{Dim} %style{[%15.15t]}{Dim} %style{%-40.40c}{Cyan} : %m%n
+appender.file.layout.pattern = %style{%d{yyyy-MM-dd HH:mm:ss.SSS}}{Dim} %highlight{%5p} %style{%pid}{Magenta} %style{---}{Dim} %style{[%15.15t]}{Dim} %style{%-35.35c}{Cyan} : %m%n
 
+# log to console and file
+rootLogger = INFO,out,file
 rootLogger.level = INFO
-rootLogger.appenderRef.out.ref = out
 
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelTop.java b/dsl/camel-jbang/camel-jbang-core/src/main/resources/templates/run-custom-camel-version.tmpl
similarity index 56%
copy from dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelTop.java
copy to dsl/camel-jbang/camel-jbang-core/src/main/resources/templates/run-custom-camel-version.tmpl
index 9f0b3b8c1a0..cd15762a79f 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/CamelTop.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/templates/run-custom-camel-version.tmpl
@@ -1,3 +1,5 @@
+///usr/bin/env jbang "$0" "$@" ; exit $?
+
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -6,7 +8,7 @@
  * (the "License"); you may not use this file except in compliance with
  * the License.  You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *    http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,24 +16,25 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.dsl.jbang.core.commands.process;
 
-import org.apache.camel.dsl.jbang.core.commands.CamelCommand;
+//JAVA {{ .JavaVersion }}+
+{{ .MavenRepositories }}
+//REPOS mavencentral,apache-snapshot=http://repository.apache.org/content/groups/snapshots/
+{{ .CamelDependencies }}
+{{ .CamelJBangDependencies }}
+//DEPS org.apache.camel.kamelets:camel-kamelets:${camel-kamelets.version:3.20.1.1}
+
+package main;
+
 import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
-import picocli.CommandLine;
 
-@CommandLine.Command(name = "top",
-                     description = "Top status of Camel integrations (use top --help to see sub commands)")
-public class CamelTop extends CamelCommand {
+/**
+ * Main to run CamelJBang
+ */
+public class CustomCamelJBang {
 
-    public CamelTop(CamelJBangMain main) {
-        super(main);
+    public static void main(String... args) {
+        CamelJBangMain.run(args);
     }
 
-    @Override
-    public Integer call() throws Exception {
-        // default to top the integrations
-        new CommandLine(new CamelContextTop(getMain())).execute();
-        return 0;
-    }
 }