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

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


The following commit(s) were added to refs/heads/main by this push:
     new eaf2f35752bb CAMEL-24226: camel run/export - add --resource-dirs option
eaf2f35752bb is described below

commit eaf2f35752bb9718bf644612e175541666bef7f5
Author: Claus Ibsen <[email protected]>
AuthorDate: Wed Jul 22 11:01:20 2026 +0200

    CAMEL-24226: camel run/export - add --resource-dirs option
    
    Add --resource-dirs option to camel run, camel export, and camel
    kubernetes run/export commands. Recursively copies specified directories
    into src/main/resources preserving the full directory structure. For
    paths with '..' uses only the last directory name as target. Rejects
    absolute paths and bare '..' for safety, limits to 1000 files per
    directory. Multiple directories supported via comma separation or
    repeated option.
    
    Closes #24986
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
---
 .../jbang/camel-jbang-configuration-metadata.json  |   1 +
 .../ROOT/pages/camel-jbang-configuration.adoc      |   3 +-
 .../modules/ROOT/pages/camel-jbang-projects.adoc   |  34 +++++
 .../modules/ROOT/pages/camel-jbang-running.adoc    |  30 ++++
 .../pages/jbang-commands/camel-jbang-debug.adoc    |   1 +
 .../camel-jbang-dependency-copy.adoc               |   1 +
 .../camel-jbang-dependency-list.adoc               |   1 +
 .../camel-jbang-dependency-update.adoc             |   1 +
 .../ROOT/pages/jbang-commands/camel-jbang-dev.adoc |   1 +
 .../pages/jbang-commands/camel-jbang-export.adoc   |   1 +
 .../ROOT/pages/jbang-commands/camel-jbang-run.adoc |   1 +
 .../pages/jbang-commands/camel-jbang-sbom.adoc     |   1 +
 .../META-INF/camel-jbang-commands-metadata.json    |  12 +-
 .../camel-jbang-configuration-metadata.json        |   1 +
 .../dsl/jbang/core/commands/ExportBaseCommand.java |  44 ++++++
 .../apache/camel/dsl/jbang/core/commands/Run.java  |  52 +++++++
 .../dsl/jbang/core/common/CamelJBangConstants.java |   4 +
 .../dsl/jbang/core/commands/ResourceDirsTest.java  | 167 +++++++++++++++++++++
 .../core/commands/kubernetes/KubernetesExport.java |   2 +
 .../core/commands/kubernetes/KubernetesRun.java    |   6 +
 20 files changed, 357 insertions(+), 7 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/jbang/camel-jbang-configuration-metadata.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/jbang/camel-jbang-configuration-metadata.json
index c28faba036ef..38820baacb31 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/jbang/camel-jbang-configuration-metadata.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/jbang/camel-jbang-configuration-metadata.json
@@ -45,6 +45,7 @@
     { "name": "camel.jbang.quarkusVersion", "required": false, "description": 
"version of Quarkus Platform BOM", "label": "quarkus", "type": "string", 
"javaType": "String", "secret": false },
     { "name": "camel.jbang.readmeFiles", "required": false, "description": 
"README files included with the integration (Use commas to separate multiple 
files)", "type": "string", "javaType": "String", "secret": false },
     { "name": "camel.jbang.repos", "required": false, "description": 
"Additional Maven repositories for download on-demand (Use commas to separate 
multiple repositories)", "label": "maven", "type": "string", "javaType": 
"String", "secret": false },
+    { "name": "camel.jbang.resourceDirs", "required": false, "description": 
"Additional resource directories to include recursively, preserving directory 
structure (Use commas to separate multiple directories)", "type": "string", 
"javaType": "String", "secret": false },
     { "name": "camel.jbang.runtime", "required": false, "description": "Which 
runtime to use (camel-main, spring-boot, quarkus)", "type": "enum", "javaType": 
"String", "secret": false, "enum": [ "camel-main", "spring-boot", "quarkus" ] },
     { "name": "camel.jbang.scriptFiles", "required": false, "description": 
"Additional shell script files to export to src\/main\/scripts directory", 
"type": "string", "javaType": "String", "secret": false },
     { "name": "camel.jbang.sourceDir", "required": false, "description": 
"Source directory for dynamically loading Camel file(s) to run. When using 
this, then files cannot be specified at the same time.", "label": "advanced", 
"type": "string", "javaType": "String", "secret": false },
diff --git a/docs/user-manual/modules/ROOT/pages/camel-jbang-configuration.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-jbang-configuration.adoc
index 4a38e58f513a..f37467779487 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-jbang-configuration.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-jbang-configuration.adoc
@@ -4,7 +4,7 @@ This page covers configuring the Camel CLI — available options, 
configuration
 
 // jbang options: START
 == Camel CLI configurations
-The camel.jbang supports 49 options, which are listed below.
+The camel.jbang supports 50 options, which are listed below.
 
 [width="100%",cols="2,5,^1,2",options="header"]
 |===
@@ -51,6 +51,7 @@ The camel.jbang supports 49 options, which are listed below.
 | *camel.jbang.quarkusVersion* | version of Quarkus Platform BOM |  | String
 | *camel.jbang.readmeFiles* | README files included with the integration (Use 
commas to separate multiple files) |  | String
 | *camel.jbang.repos* | Additional Maven repositories for download on-demand 
(Use commas to separate multiple repositories) |  | String
+| *camel.jbang.resourceDirs* | Additional resource directories to include 
recursively, preserving directory structure (Use commas to separate multiple 
directories) |  | String
 | *camel.jbang.runtime* | Which runtime to use (camel-main, spring-boot, 
quarkus) |  | String
 | *camel.jbang.scriptFiles* | Additional shell script files to export to 
src/main/scripts directory |  | String
 | *camel.jbang.sourceDir* | Source directory for dynamically loading Camel 
file(s) to run. When using this, then files cannot be specified at the same 
time. |  | String
diff --git a/docs/user-manual/modules/ROOT/pages/camel-jbang-projects.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-jbang-projects.adoc
index 26b621316a9b..05e53e7039e5 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-jbang-projects.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-jbang-projects.adoc
@@ -103,6 +103,40 @@ camel export --runtime=quarkus 
--gav=com.foo:acme:1.0-SNAPSHOT --dep=camel:manag
 camel export --runtime=quarkus --gav=com.foo:acme:1.0-SNAPSHOT 
--dep=camel:cli-connector
 ----
 
+=== Including resource directories
+
+To include entire directories of resource files (such as XSD schemas, WSDL 
files, etc.)
+in the exported project while preserving their directory structure, use 
`--resource-dirs`:
+
+[source,bash]
+----
+camel export --resource-dirs=soap
+----
+
+This recursively copies all files from the `soap/` directory into 
`src/main/resources/soap/`,
+preserving the directory structure. For example, `soap/schemas/common.xsd` 
becomes
+`src/main/resources/soap/schemas/common.xsd`.
+
+Multiple directories can be specified with commas:
+
+[source,bash]
+----
+camel export --resource-dirs=soap,wsdl
+----
+
+You can also reference directories outside the current project using relative 
paths.
+When using `..` paths, only the last directory name is used as the target:
+
+[source,bash]
+----
+camel export --resource-dirs=../shared/schemas
+----
+
+This copies the contents into `src/main/resources/schemas/`.
+
+NOTE: Absolute paths (e.g., `/some/path`) are not allowed.
+The directory is limited to at most 1000 files as a safety measure.
+
 === Troubleshooting exporting
 
 Use `--verbose` and `--logging` for more detail, or `--logging-level=DEBUG` 
for full output.
diff --git a/docs/user-manual/modules/ROOT/pages/camel-jbang-running.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-jbang-running.adoc
index a80d34ef1ac6..4d56d7565df9 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-jbang-running.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-jbang-running.adoc
@@ -152,6 +152,36 @@ Multiple dependencies can be separated by comma:
 camel run foo.java --dep=camel-saxon,com.foo:acme:1.0
 ----
 
+== Including resource directories
+
+To include entire directories of resource files (such as XSD schemas, WSDL 
files, etc.)
+on the classpath while preserving their directory structure, use 
`--resource-dirs`:
+
+[source,bash]
+----
+camel run route.yaml --resource-dirs=soap
+----
+
+This recursively adds all files from the `soap/` directory to the classpath,
+preserving the directory structure (e.g., `soap/schemas/common.xsd` is 
accessible as `classpath:soap/schemas/common.xsd`).
+
+Multiple directories can be specified with commas:
+
+[source,bash]
+----
+camel run route.yaml --resource-dirs=soap,wsdl
+----
+
+You can also reference directories outside the current project using relative 
paths:
+
+[source,bash]
+----
+camel run route.yaml --resource-dirs=../shared/schemas
+----
+
+NOTE: Absolute paths (e.g., `/some/path`) are not allowed.
+The directory is limited to at most 1000 files as a safety measure.
+
 == Using 3rd-party Maven repositories
 
 By default, Camel CLI downloads from the local Maven repository and Maven 
Central.
diff --git 
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-debug.adoc 
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-debug.adoc
index 2874c142b913..0f9265a5fec2 100644
--- a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-debug.adoc
+++ b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-debug.adoc
@@ -83,6 +83,7 @@ camel debug [options]
 | `--reload,--dev` | Enables dev mode (live reload when source files are 
updated and saved) |  | boolean
 | `--remote-attach` | Attaches debugger remotely to an existing running Camel 
integration. (Add camel-cli-debug JAR to the existing Camel application and run 
before attaching this debugger) |  | boolean
 | `--repo,--repos` | Additional maven repositories for download on-demand (Use 
commas to separate multiple repositories) |  | String
+| `--resource-dir,--resource-dirs` | Additional resource directories to 
include on the classpath (recursive, preserving structure) |  | List
 | `--runtime` | Runtime (camel-main, spring-boot, quarkus) | camel-main | 
RuntimeType
 | `--show-body` | Show message body in debug messages | true | boolean
 | `--show-exception` | Show exception and stacktrace for failed messages | 
true | boolean
diff --git 
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency-copy.adoc
 
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency-copy.adoc
index d8c90d2e84ef..2149196f292e 100644
--- 
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency-copy.adoc
+++ 
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency-copy.adoc
@@ -65,6 +65,7 @@ camel dependency copy [options]
 | `--quarkus-version` | version of Quarkus Platform BOM; the default value is 
looked up in Quarkus Extension Registry |  | String
 | `--quiet` | Will be quiet, only print when error occurs | false | boolean
 | `--repo,--repos` | Additional maven repositories for download on-demand (Use 
commas to separate multiple repositories) |  | String
+| `--resource-dir,--resource-dirs` | Additional resource directories to 
include in src/main/resources (recursive, preserving structure) |  | List
 | `--runtime` | Runtime (camel-main, spring-boot, quarkus) |  | RuntimeType
 | `--skip-plugins` | Skip plugins during export | false | boolean
 | `--spring-boot-version` | Spring Boot version | 
RuntimeType.SPRING_BOOT_VERSION | String
diff --git 
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency-list.adoc
 
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency-list.adoc
index 575369f1c32b..a87b96fed253 100644
--- 
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency-list.adoc
+++ 
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency-list.adoc
@@ -64,6 +64,7 @@ camel dependency list [options]
 | `--quarkus-version` | version of Quarkus Platform BOM; the default value is 
looked up in Quarkus Extension Registry |  | String
 | `--quiet` | Will be quiet, only print when error occurs | false | boolean
 | `--repo,--repos` | Additional maven repositories for download on-demand (Use 
commas to separate multiple repositories) |  | String
+| `--resource-dir,--resource-dirs` | Additional resource directories to 
include in src/main/resources (recursive, preserving structure) |  | List
 | `--runtime` | Runtime (camel-main, spring-boot, quarkus) |  | RuntimeType
 | `--skip-plugins` | Skip plugins during export | false | boolean
 | `--spring-boot-version` | Spring Boot version | 
RuntimeType.SPRING_BOOT_VERSION | String
diff --git 
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency-update.adoc
 
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency-update.adoc
index f5310726df1c..bc3ff5357e69 100644
--- 
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency-update.adoc
+++ 
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dependency-update.adoc
@@ -65,6 +65,7 @@ camel dependency update [options]
 | `--quarkus-version` | version of Quarkus Platform BOM; the default value is 
looked up in Quarkus Extension Registry |  | String
 | `--quiet` | Will be quiet, only print when error occurs | false | boolean
 | `--repo,--repos` | Additional maven repositories for download on-demand (Use 
commas to separate multiple repositories) |  | String
+| `--resource-dir,--resource-dirs` | Additional resource directories to 
include in src/main/resources (recursive, preserving structure) |  | List
 | `--runtime` | Runtime (camel-main, spring-boot, quarkus) |  | RuntimeType
 | `--scan-routes` | Sync dependencies from route definitions. Only manages 
org.apache.camel dependencies, preserving non-Camel dependencies. Removes 
unused Camel dependencies. |  | boolean
 | `--skip-plugins` | Skip plugins during export | false | boolean
diff --git 
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dev.adoc 
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dev.adoc
index 69218ec9f4a0..1b69782e934c 100644
--- a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dev.adoc
+++ b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-dev.adoc
@@ -76,6 +76,7 @@ camel dev [options]
 | `--quarkus-version` | version of Quarkus Platform BOM; the default value is 
looked up in Quarkus Extension Registry |  | String
 | `--reload,--dev` | Enables dev mode (live reload when source files are 
updated and saved) |  | boolean
 | `--repo,--repos` | Additional maven repositories for download on-demand (Use 
commas to separate multiple repositories) |  | String
+| `--resource-dir,--resource-dirs` | Additional resource directories to 
include on the classpath (recursive, preserving structure) |  | List
 | `--runtime` | Runtime (camel-main, spring-boot, quarkus) | camel-main | 
RuntimeType
 | `--skip-plugins` | Skip resolving plugin dependencies | false | boolean
 | `--source-dir` | Source directory for dynamically loading Camel file(s) to 
run. When using this, then files cannot be specified at the same time. |  | 
String
diff --git 
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-export.adoc 
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-export.adoc
index b78a1b2349f6..12278c201622 100644
--- a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-export.adoc
+++ b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-export.adoc
@@ -63,6 +63,7 @@ camel export [options]
 | `--quarkus-version` | version of Quarkus Platform BOM; the default value is 
looked up in Quarkus Extension Registry |  | String
 | `--quiet` | Will be quiet, only print when error occurs | false | boolean
 | `--repo,--repos` | Additional maven repositories for download on-demand (Use 
commas to separate multiple repositories) |  | String
+| `--resource-dir,--resource-dirs` | Additional resource directories to 
include in src/main/resources (recursive, preserving structure) |  | List
 | `--runtime` | Runtime (camel-main, spring-boot, quarkus) |  | RuntimeType
 | `--skip-plugins` | Skip plugins during export | false | boolean
 | `--spring-boot-version` | Spring Boot version | 
RuntimeType.SPRING_BOOT_VERSION | String
diff --git 
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-run.adoc 
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-run.adoc
index ef505512255b..93c8bcfc962b 100644
--- a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-run.adoc
+++ b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-run.adoc
@@ -76,6 +76,7 @@ camel run [options]
 | `--quarkus-version` | version of Quarkus Platform BOM; the default value is 
looked up in Quarkus Extension Registry |  | String
 | `--reload,--dev` | Enables dev mode (live reload when source files are 
updated and saved) |  | boolean
 | `--repo,--repos` | Additional maven repositories for download on-demand (Use 
commas to separate multiple repositories) |  | String
+| `--resource-dir,--resource-dirs` | Additional resource directories to 
include on the classpath (recursive, preserving structure) |  | List
 | `--runtime` | Runtime (camel-main, spring-boot, quarkus) | camel-main | 
RuntimeType
 | `--skip-plugins` | Skip resolving plugin dependencies | false | boolean
 | `--source-dir` | Source directory for dynamically loading Camel file(s) to 
run. When using this, then files cannot be specified at the same time. |  | 
String
diff --git 
a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-sbom.adoc 
b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-sbom.adoc
index 06036a020a35..d0540d8eabbd 100644
--- a/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-sbom.adoc
+++ b/docs/user-manual/modules/ROOT/pages/jbang-commands/camel-jbang-sbom.adoc
@@ -66,6 +66,7 @@ camel sbom [options]
 | `--quarkus-version` | version of Quarkus Platform BOM; the default value is 
looked up in Quarkus Extension Registry |  | String
 | `--quiet` | Will be quiet, only print when error occurs | false | boolean
 | `--repo,--repos` | Additional maven repositories for download on-demand (Use 
commas to separate multiple repositories) |  | String
+| `--resource-dir,--resource-dirs` | Additional resource directories to 
include in src/main/resources (recursive, preserving structure) |  | List
 | `--runtime` | Runtime (camel-main, spring-boot, quarkus) |  | RuntimeType
 | `--sbom-format` | The SBOM format, possible values are cyclonedx or spdx | 
CYCLONEDX_FORMAT | String
 | `--sbom-output-format` | The SBOM output format, possible values are json or 
xml | SBOM_JSON_FORMAT | String
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json
 
b/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json
index 7f66b663a036..85a31044c196 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-commands-metadata.json
@@ -6,15 +6,15 @@
     { "name": "cmd", "fullName": "cmd", "description": "Performs commands in 
the running Camel integrations, such as start\/stop route, or change logging 
levels.", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.action.CamelAction", "options": [ { 
"names": "-h,--help", "description": "Display the help and sub-commands", 
"javaType": "boolean", "type": "boolean" } ], "subcommands": [ { "name": 
"browse", "fullName": "cmd browse", "description": "Browse pending messages on 
endpoints [...]
     { "name": "completion", "fullName": "completion", "description": "Generate 
completion script for bash\/zsh", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.Complete", "options": [ { "names": 
"-h,--help", "description": "Display the help and sub-commands", "javaType": 
"boolean", "type": "boolean" } ] },
     { "name": "config", "fullName": "config", "description": "Get and set user 
configuration values", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.config.ConfigCommand", "options": [ { 
"names": "-h,--help", "description": "Display the help and sub-commands", 
"javaType": "boolean", "type": "boolean" } ], "subcommands": [ { "name": "get", 
"fullName": "config get", "description": "Display user configuration value", 
"sourceClass": "org.apache.camel.dsl.jbang.core.commands.config. [...]
-    { "name": "debug", "fullName": "debug", "description": "Debug local Camel 
integration", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Debug", 
"options": [ { "names": "--ago", "description": "Use ago instead of yyyy-MM-dd 
HH:mm:ss in timestamp.", "javaType": "boolean", "type": "boolean" }, { "names": 
"--background", "description": "Run in the background", "defaultValue": 
"false", "javaType": "boolean", "type": "boolean" }, { "names": 
"--background-wait", "description": "To  [...]
-    { "name": "dependency", "fullName": "dependency", "description": "Displays 
all Camel dependencies required to run", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.DependencyCommand", "options": [ { 
"names": "-h,--help", "description": "Display the help and sub-commands", 
"javaType": "boolean", "type": "boolean" } ], "subcommands": [ { "name": 
"copy", "fullName": "dependency copy", "description": "Copies all Camel 
dependencies required to run to a specific directory", "sourc [...]
-    { "name": "dev", "fullName": "dev", "description": "Run in dev mode with 
live reload", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Dev", 
"options": [ { "names": "--background", "description": "Run in the background", 
"defaultValue": "false", "javaType": "boolean", "type": "boolean" }, { "names": 
"--background-wait", "description": "To wait for run in background to startup 
successfully, before returning", "defaultValue": "true", "javaType": "boolean", 
"type": "boolean" }, [...]
+    { "name": "debug", "fullName": "debug", "description": "Debug local Camel 
integration", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Debug", 
"options": [ { "names": "--ago", "description": "Use ago instead of yyyy-MM-dd 
HH:mm:ss in timestamp.", "javaType": "boolean", "type": "boolean" }, { "names": 
"--background", "description": "Run in the background", "defaultValue": 
"false", "javaType": "boolean", "type": "boolean" }, { "names": 
"--background-wait", "description": "To  [...]
+    { "name": "dependency", "fullName": "dependency", "description": "Displays 
all Camel dependencies required to run", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.DependencyCommand", "options": [ { 
"names": "-h,--help", "description": "Display the help and sub-commands", 
"javaType": "boolean", "type": "boolean" } ], "subcommands": [ { "name": 
"copy", "fullName": "dependency copy", "description": "Copies all Camel 
dependencies required to run to a specific directory", "sourc [...]
+    { "name": "dev", "fullName": "dev", "description": "Run in dev mode with 
live reload", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Dev", 
"options": [ { "names": "--background", "description": "Run in the background", 
"defaultValue": "false", "javaType": "boolean", "type": "boolean" }, { "names": 
"--background-wait", "description": "To wait for run in background to startup 
successfully, before returning", "defaultValue": "true", "javaType": "boolean", 
"type": "boolean" }, [...]
     { "name": "dirty", "fullName": "dirty", "description": "Check if there are 
dirty files from previous Camel runs that did not terminate gracefully", 
"sourceClass": "org.apache.camel.dsl.jbang.core.commands.process.Dirty", 
"options": [ { "names": "--clean", "description": "Clean dirty files which are 
no longer in use", "defaultValue": "false", "javaType": "boolean", "type": 
"boolean" }, { "names": "-h,--help", "description": "Display the help and 
sub-commands", "javaType": "boolean", " [...]
     { "name": "doc", "fullName": "doc", "description": "Shows documentation 
for kamelet, component, and other Camel resources", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.catalog.CatalogDoc", "options": [ { 
"names": "--camel-version", "description": "To use a different Camel version 
than the default version", "javaType": "java.lang.String", "type": "string" }, 
{ "names": "--download", "description": "Whether to allow automatic downloading 
JAR dependencies (over the internet [...]
     { "name": "doctor", "fullName": "doctor", "description": "Checks the 
environment and reports potential issues", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.Doctor", "options": [ { "names": 
"-h,--help", "description": "Display the help and sub-commands", "javaType": 
"boolean", "type": "boolean" } ] },
     { "name": "eval", "fullName": "eval", "description": "Evaluate Camel 
expressions and scripts", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.EvalCommand", "options": [ { "names": 
"-h,--help", "description": "Display the help and sub-commands", "javaType": 
"boolean", "type": "boolean" } ], "subcommands": [ { "name": "expression", 
"fullName": "eval expression", "description": "Evaluates Camel expression", 
"sourceClass": "org.apache.camel.dsl.jbang.core.commands.action.EvalEx [...]
     { "name": "explain", "fullName": "explain", "description": "Explain what a 
Camel route does using AI\/LLM", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.Explain", "options": [ { "names": 
"--api-key", "description": "API key for authentication. Also reads 
ANTHROPIC_API_KEY, OPENAI_API_KEY, or LLM_API_KEY env vars", "javaType": 
"java.lang.String", "type": "string" }, { "names": "--api-type", "description": 
"API type: 'ollama', 'openai' (OpenAI-compatible), or 'anthropic' (A [...]
-    { "name": "export", "fullName": "export", "description": "Export to other 
runtimes (Camel Main, Spring Boot, or Quarkus)", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.Export", "options": [ { "names": 
"--build-property", "description": "Maven build properties, ex. 
--build-property=prop1=foo", "javaType": "java.util.List", "type": "array" }, { 
"names": "--camel-spring-boot-version", "description": "Camel version to use 
with Spring Boot", "javaType": "java.lang.String", "ty [...]
+    { "name": "export", "fullName": "export", "description": "Export to other 
runtimes (Camel Main, Spring Boot, or Quarkus)", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.Export", "options": [ { "names": 
"--build-property", "description": "Maven build properties, ex. 
--build-property=prop1=foo", "javaType": "java.util.List", "type": "array" }, { 
"names": "--camel-spring-boot-version", "description": "Camel version to use 
with Spring Boot", "javaType": "java.lang.String", "ty [...]
     { "name": "get", "fullName": "get", "description": "Get status of Camel 
integrations", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.process.CamelStatus", "options": [ { 
"names": "--watch", "description": "Execute periodically and showing output 
fullscreen", "javaType": "boolean", "type": "boolean" }, { "names": 
"-h,--help", "description": "Display the help and sub-commands", "javaType": 
"boolean", "type": "boolean" } ], "subcommands": [ { "name": "activity", 
"fullName": " [...]
     { "name": "harden", "fullName": "harden", "description": "Suggest security 
hardening for Camel routes using AI\/LLM", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.Harden", "options": [ { "names": 
"--api-key", "description": "API key for authentication. Also reads 
OPENAI_API_KEY or LLM_API_KEY env vars", "javaType": "java.lang.String", 
"type": "string" }, { "names": "--api-type", "description": "API type: 'ollama' 
or 'openai' (OpenAI-compatible)", "defaultValue": "ollama", [...]
     { "name": "hawtio", "fullName": "hawtio", "description": "Launch Hawtio 
web console", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.process.Hawtio", "options": [ { 
"names": "--host", "description": "Hostname to bind the Hawtio web console to", 
"defaultValue": "127.0.0.1", "javaType": "java.lang.String", "type": "string" 
}, { "names": "--openUrl", "description": "To automatic open Hawtio web console 
in the web browser", "defaultValue": "true", "javaType": "boolean", "type": 
[...]
@@ -26,8 +26,8 @@
     { "name": "plugin", "fullName": "plugin", "description": "Manage plugins 
that add sub-commands to this CLI", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.plugin.PluginCommand", "options": [ { 
"names": "-h,--help", "description": "Display the help and sub-commands", 
"javaType": "boolean", "type": "boolean" } ], "subcommands": [ { "name": "add", 
"fullName": "plugin add", "description": "Add new plugin", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.plugin.PluginA [...]
     { "name": "ps", "fullName": "ps", "description": "List running Camel 
integrations", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.process.ListProcess", "options": [ { 
"names": "--json", "description": "Output in JSON Format", "javaType": 
"boolean", "type": "boolean" }, { "names": "--pid", "description": "List only 
pid in the output", "javaType": "boolean", "type": "boolean" }, { "names": 
"--remote", "description": "Break down counters into remote\/total pairs", 
"javaType": [...]
     { "name": "restart", "fullName": "restart", "description": "Restarts 
running Camel integrations (stop + re-launch)", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.process.RestartProcess", "options": [ 
{ "names": "-h,--help", "description": "Display the help and sub-commands", 
"javaType": "boolean", "type": "boolean" } ] },
-    { "name": "run", "fullName": "run", "description": "Run as local Camel 
integration", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Run", 
"options": [ { "names": "--background", "description": "Run in the background", 
"defaultValue": "false", "javaType": "boolean", "type": "boolean" }, { "names": 
"--background-wait", "description": "To wait for run in background to startup 
successfully, before returning", "defaultValue": "true", "javaType": "boolean", 
"type": "boolean" }, { [...]
-    { "name": "sbom", "fullName": "sbom", "description": "Generate a CycloneDX 
or SPDX SBOM for a specific project", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.SBOMGenerator", "options": [ { 
"names": "--build-property", "description": "Maven build properties, ex. 
--build-property=prop1=foo", "javaType": "java.util.List", "type": "array" }, { 
"names": "--camel-spring-boot-version", "description": "Camel version to use 
with Spring Boot", "javaType": "java.lang.String", "type" [...]
+    { "name": "run", "fullName": "run", "description": "Run as local Camel 
integration", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Run", 
"options": [ { "names": "--background", "description": "Run in the background", 
"defaultValue": "false", "javaType": "boolean", "type": "boolean" }, { "names": 
"--background-wait", "description": "To wait for run in background to startup 
successfully, before returning", "defaultValue": "true", "javaType": "boolean", 
"type": "boolean" }, { [...]
+    { "name": "sbom", "fullName": "sbom", "description": "Generate a CycloneDX 
or SPDX SBOM for a specific project", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.SBOMGenerator", "options": [ { 
"names": "--build-property", "description": "Maven build properties, ex. 
--build-property=prop1=foo", "javaType": "java.util.List", "type": "array" }, { 
"names": "--camel-spring-boot-version", "description": "Camel version to use 
with Spring Boot", "javaType": "java.lang.String", "type" [...]
     { "name": "script", "fullName": "script", "description": "Run Camel 
integration as shell script for terminal scripting", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.Script", "options": [ { "names": 
"--logging", "description": "Can be used to turn on logging (logs to file in 
<user home>\/.camel directory)", "defaultValue": "false", "javaType": 
"boolean", "type": "boolean" }, { "names": "--logging-level", "description": 
"Logging level (ERROR, WARN, INFO, DEBUG, TRACE)", "d [...]
     { "name": "shell", "fullName": "shell", "description": "Interactive Camel 
CLI shell.", "sourceClass": "org.apache.camel.dsl.jbang.core.commands.Shell", 
"options": [ { "names": "-h,--help", "description": "Display the help and 
sub-commands", "javaType": "boolean", "type": "boolean" } ] },
     { "name": "stop", "fullName": "stop", "description": "Shuts down running 
Camel integrations", "sourceClass": 
"org.apache.camel.dsl.jbang.core.commands.process.StopProcess", "options": [ { 
"names": "--kill", "description": "To force killing the process (SIGKILL)", 
"javaType": "boolean", "type": "boolean" }, { "names": "-h,--help", 
"description": "Display the help and sub-commands", "javaType": "boolean", 
"type": "boolean" } ] },
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-configuration-metadata.json
 
b/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-configuration-metadata.json
index c28faba036ef..38820baacb31 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-configuration-metadata.json
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/generated/resources/META-INF/camel-jbang-configuration-metadata.json
@@ -45,6 +45,7 @@
     { "name": "camel.jbang.quarkusVersion", "required": false, "description": 
"version of Quarkus Platform BOM", "label": "quarkus", "type": "string", 
"javaType": "String", "secret": false },
     { "name": "camel.jbang.readmeFiles", "required": false, "description": 
"README files included with the integration (Use commas to separate multiple 
files)", "type": "string", "javaType": "String", "secret": false },
     { "name": "camel.jbang.repos", "required": false, "description": 
"Additional Maven repositories for download on-demand (Use commas to separate 
multiple repositories)", "label": "maven", "type": "string", "javaType": 
"String", "secret": false },
+    { "name": "camel.jbang.resourceDirs", "required": false, "description": 
"Additional resource directories to include recursively, preserving directory 
structure (Use commas to separate multiple directories)", "type": "string", 
"javaType": "String", "secret": false },
     { "name": "camel.jbang.runtime", "required": false, "description": "Which 
runtime to use (camel-main, spring-boot, quarkus)", "type": "enum", "javaType": 
"String", "secret": false, "enum": [ "camel-main", "spring-boot", "quarkus" ] },
     { "name": "camel.jbang.scriptFiles", "required": false, "description": 
"Additional shell script files to export to src\/main\/scripts directory", 
"type": "string", "javaType": "String", "secret": false },
     { "name": "camel.jbang.sourceDir", "required": false, "description": 
"Source directory for dynamically loading Camel file(s) to run. When using 
this, then files cannot be specified at the same time.", "label": "advanced", 
"type": "string", "javaType": "String", "secret": false },
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 664a2c603a27..dc2304e28fcc 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
@@ -248,6 +248,11 @@ public abstract class ExportBaseCommand extends 
CamelCommand {
                         description = "Whether to automatic package scan JARs 
for custom Spring or Quarkus beans making them available for Camel CLI")
     protected boolean packageScanJars;
 
+    @CommandLine.Option(names = { "--resource-dir", "--resource-dirs" },
+                        description = "Additional resource directories to 
include in src/main/resources (recursive, preserving structure)",
+                        split = ",")
+    protected List<String> resourceDirs = new ArrayList<>();
+
     @CommandLine.Option(names = { "--build-property" },
                         description = "Maven build properties, ex. 
--build-property=prop1=foo")
     protected List<String> buildProperties = new ArrayList<>();
@@ -574,6 +579,7 @@ public abstract class ExportBaseCommand extends 
CamelCommand {
         run.kameletsVersion = kameletsVersion;
         run.javaVersion = javaVersion;
         run.localKameletDir = localKameletDir;
+        run.resourceDirs = resourceDirs;
         run.ignoreLoadingError = ignoreLoadingError;
         run.lazyBean = lazyBean;
         run.property = applicationProperties;
@@ -896,6 +902,10 @@ public abstract class ExportBaseCommand extends 
CamelCommand {
                     } else if (web) {
                         targetDir = 
srcResourcesDir.resolve("META-INF/resources");
                     } else {
+                        // skip files that belong to a resource dir (they are 
copied with structure preserved later)
+                        if (isUnderResourceDir(f)) {
+                            continue;
+                        }
                         targetDir = srcResourcesDir;
                     }
                     Files.createDirectories(targetDir);
@@ -980,6 +990,8 @@ public abstract class ExportBaseCommand extends 
CamelCommand {
             }
         }
 
+        copyResourceDirs(srcResourcesDir);
+
         if (!skipPlugins) {
             Set<PluginExporter> exporters = 
PluginHelper.getActivePlugins(getMain(), mavenResolver.repos()).values()
                     .stream()
@@ -995,6 +1007,38 @@ public abstract class ExportBaseCommand extends 
CamelCommand {
         }
     }
 
+    private void copyResourceDirs(Path srcResourcesDir) throws Exception {
+        if (resourceDirs == null || resourceDirs.isEmpty()) {
+            return;
+        }
+        for (String dir : resourceDirs) {
+            Path dirPath = Run.validateResourceDir(dir);
+            // use the last component as the target directory name
+            // so ../shared/schemas -> src/main/resources/schemas/
+            Path baseName = dirPath.getFileName();
+            for (Path source : Run.walkResourceDir(dirPath)) {
+                Path relativePath = dirPath.relativize(source);
+                Path target = 
srcResourcesDir.resolve(baseName).resolve(relativePath);
+                Files.createDirectories(target.getParent());
+                Files.copy(source, target, 
StandardCopyOption.REPLACE_EXISTING);
+            }
+        }
+    }
+
+    private boolean isUnderResourceDir(String file) {
+        if (resourceDirs == null || resourceDirs.isEmpty()) {
+            return false;
+        }
+        Path filePath = Paths.get(file).normalize();
+        for (String dir : resourceDirs) {
+            Path dirPath = Paths.get(dir).normalize();
+            if (filePath.startsWith(dirPath)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     protected void adjustJavaSourceFileLine(String line, OutputStream fos) 
throws Exception {
         // noop
     }
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 e0e261bfb7f5..dc4a6a06d73b 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
@@ -180,6 +180,11 @@ public class Run extends CamelCommand {
             description = "Source directory for dynamically loading Camel 
file(s) to run. When using this, then files cannot be specified at the same 
time.")
     String sourceDir;
 
+    @Option(names = { "--resource-dir", "--resource-dirs" },
+            description = "Additional resource directories to include on the 
classpath (recursive, preserving structure)",
+            split = ",")
+    List<String> resourceDirs = new ArrayList<>();
+
     @Option(names = { "--background" }, defaultValue = "false", description = 
"Run in the background")
     public boolean background;
 
@@ -971,6 +976,16 @@ public class Run extends CamelCommand {
             }
         }
 
+        // walk resource directories and add files to classpath preserving 
directory structure
+        if (resourceDirs != null) {
+            for (String dir : resourceDirs) {
+                Path dirPath = validateResourceDir(dir);
+                for (Path f : walkResourceDir(dirPath)) {
+                    sjClasspathFiles.add(f.toString());
+                }
+            }
+        }
+
         for (String file : files) {
             if (file.startsWith("clipboard") && 
!(Files.exists(Paths.get(file)))) {
                 file = loadFromClipboard(file);
@@ -1130,6 +1145,13 @@ public class Run extends CamelCommand {
         } else {
             writeSetting(main, profileProperties, JKUBE_FILES, () -> null);
         }
+        if (resourceDirs != null && !resourceDirs.isEmpty()) {
+            String dirs = String.join(",", resourceDirs);
+            main.addInitialProperty(RESOURCE_DIRS, dirs);
+            writeSettings(RESOURCE_DIRS, dirs);
+        } else {
+            writeSetting(main, profileProperties, RESOURCE_DIRS, () -> null);
+        }
 
         if (sjKamelets.length() > 0) {
             String loc = 
main.getInitialProperties().getProperty("camel.component.kamelet.location");
@@ -2669,6 +2691,36 @@ public class Run extends CamelCommand {
         return on.toLowerCase(Locale.ROOT).startsWith("readme");
     }
 
+    static final int MAX_RESOURCE_DIR_FILES = 1000;
+
+    static Path validateResourceDir(String dir) {
+        Path path = Paths.get(dir).normalize();
+        if (path.isAbsolute()) {
+            throw new IllegalArgumentException("--resource-dirs only accepts 
relative paths: " + dir);
+        }
+        if (path.getFileName() != null && 
path.getFileName().toString().equals("..")) {
+            throw new IllegalArgumentException(
+                    "--resource-dirs path must end with a named directory, not 
'..': " + dir);
+        }
+        if (!Files.isDirectory(path)) {
+            throw new IllegalArgumentException("--resource-dirs path is not a 
directory: " + dir);
+        }
+        return path;
+    }
+
+    static List<Path> walkResourceDir(Path dirPath) throws IOException {
+        try (Stream<Path> walk = Files.walk(dirPath)) {
+            List<Path> files = walk.filter(Files::isRegularFile).toList();
+            if (files.size() > MAX_RESOURCE_DIR_FILES) {
+                throw new IllegalArgumentException(
+                        "--resource-dirs directory contains " + files.size()
+                                                   + " files which exceeds the 
limit of " + MAX_RESOURCE_DIR_FILES + ": "
+                                                   + dirPath);
+            }
+            return files;
+        }
+    }
+
     private void writeSettings(String key, String value) {
         try {
             // use java.util.Properties to ensure the value is escaped 
correctly
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/CamelJBangConstants.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/CamelJBangConstants.java
index 403761e5997f..526867409907 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/CamelJBangConstants.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/CamelJBangConstants.java
@@ -60,6 +60,10 @@ public final class CamelJBangConstants {
               javaType = "String", label = "kubernetes")
     public static final String JKUBE_FILES = "camel.jbang.jkubeFiles";
 
+    @Metadata(description = "Additional resource directories to include 
recursively, preserving directory structure (Use commas to separate multiple 
directories)",
+              javaType = "String")
+    public static final String RESOURCE_DIRS = "camel.jbang.resourceDirs";
+
     @Metadata(description = "Which runtime to use (camel-main, spring-boot, 
quarkus)",
               javaType = "String", enums = "camel-main,spring-boot,quarkus")
     public static final String RUNTIME = "camel.jbang.runtime";
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ResourceDirsTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ResourceDirsTest.java
new file mode 100644
index 000000000000..3de78f3fec1c
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ResourceDirsTest.java
@@ -0,0 +1,167 @@
+/*
+ * 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.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+class ResourceDirsTest {
+
+    @Test
+    void validateShouldRejectAbsolutePath() {
+        assertThatThrownBy(() -> 
Run.validateResourceDir("/some/absolute/path"))
+                .isInstanceOf(IllegalArgumentException.class)
+                .hasMessageContaining("only accepts relative paths");
+    }
+
+    @Test
+    void validateShouldRejectNonDirectory(@TempDir Path tempDir) throws 
Exception {
+        // create a regular file inside tempDir, then use a relative path to it
+        Path file = tempDir.resolve("notadir.txt");
+        Files.writeString(file, "hello");
+
+        // use relative path from cwd to the file
+        Path relative = Path.of("").toAbsolutePath().relativize(file);
+        assertThatThrownBy(() -> Run.validateResourceDir(relative.toString()))
+                .isInstanceOf(IllegalArgumentException.class)
+                .hasMessageContaining("not a directory");
+    }
+
+    @Test
+    void validateShouldAcceptRelativeDir(@TempDir Path tempDir) throws 
Exception {
+        Path dir = tempDir.resolve("soap");
+        Files.createDirectories(dir);
+
+        // use relative path from cwd to the dir
+        Path relative = Path.of("").toAbsolutePath().relativize(dir);
+        Path result = Run.validateResourceDir(relative.toString());
+        assertThat(result).isNotNull();
+    }
+
+    @Test
+    void validateShouldAcceptDotDotPaths(@TempDir Path tempDir) throws 
Exception {
+        // create project/child and shared dirs, use ../shared from child's 
perspective
+        Path project = tempDir.resolve("project/child");
+        Path shared = tempDir.resolve("shared");
+        Files.createDirectories(project);
+        Files.createDirectories(shared);
+
+        // use relative path from cwd — this will contain .. segments
+        Path relative = Path.of("").toAbsolutePath().relativize(shared);
+        Path result = Run.validateResourceDir(relative.toString());
+        assertThat(result).isNotNull();
+    }
+
+    @Test
+    void walkShouldFindFilesRecursively(@TempDir Path tempDir) throws 
Exception {
+        Path dir = tempDir.resolve("soap");
+        Path subDir = tempDir.resolve("soap/schemas");
+        Files.createDirectories(subDir);
+        Files.writeString(dir.resolve("file.xsd"), "<xsd/>");
+        Files.writeString(subDir.resolve("common.xsd"), "<xsd/>");
+
+        List<Path> files = Run.walkResourceDir(dir);
+        assertThat(files).hasSize(2);
+        
assertThat(files).extracting(Path::getFileName).extracting(Path::toString)
+                .containsExactlyInAnyOrder("file.xsd", "common.xsd");
+    }
+
+    @Test
+    void walkShouldEnforceMaxFileLimit(@TempDir Path tempDir) throws Exception 
{
+        Path dir = tempDir.resolve("big");
+        Files.createDirectories(dir);
+
+        for (int i = 0; i < Run.MAX_RESOURCE_DIR_FILES + 1; i++) {
+            Files.writeString(dir.resolve("file" + i + ".txt"), "content");
+        }
+
+        assertThatThrownBy(() -> Run.walkResourceDir(dir))
+                .isInstanceOf(IllegalArgumentException.class)
+                .hasMessageContaining("exceeds the limit");
+    }
+
+    @Test
+    void parentPathShouldMapToLastComponent(@TempDir Path tempDir) throws 
Exception {
+        // simulate ../shared/schemas structure where only the last dir name 
is used as target
+        Path shared = tempDir.resolve("shared/schemas");
+        Files.createDirectories(shared);
+        Files.writeString(shared.resolve("common.xsd"), "<xsd/>");
+
+        Path dirPath = shared;
+        Path baseName = dirPath.getFileName();
+        assertThat(baseName.toString()).isEqualTo("schemas");
+
+        // verify target path uses only the last component
+        Path srcResources = tempDir.resolve("export/src/main/resources");
+        Files.createDirectories(srcResources);
+
+        for (Path source : Run.walkResourceDir(dirPath)) {
+            Path relativePath = dirPath.relativize(source);
+            Path target = srcResources.resolve(baseName).resolve(relativePath);
+            Files.createDirectories(target.getParent());
+            Files.copy(source, target);
+        }
+
+        // ../shared/schemas/common.xsd -> 
src/main/resources/schemas/common.xsd
+        assertThat(srcResources.resolve("schemas/common.xsd")).exists();
+    }
+
+    @Test
+    void validateShouldRejectBareDotDot(@TempDir Path tempDir) {
+        assertThatThrownBy(() -> Run.validateResourceDir(".."))
+                .isInstanceOf(IllegalArgumentException.class)
+                .hasMessageContaining("must end with a named directory");
+    }
+
+    @Test
+    void nestedParentPathShouldMapToLastComponent() {
+        // ../../mydata/foo -> last component is "foo"
+        Path path = Path.of("../../mydata/foo").normalize();
+        assertThat(path.getFileName().toString()).isEqualTo("foo");
+    }
+
+    @Test
+    void deepSubdirectoryShouldPreserveStructure(@TempDir Path tempDir) throws 
Exception {
+        // create a deep structure: soap/types/common/base.xsd
+        Path dir = tempDir.resolve("soap");
+        Path deep = tempDir.resolve("soap/types/common");
+        Files.createDirectories(deep);
+        Files.writeString(dir.resolve("service.wsdl"), "<wsdl/>");
+        Files.writeString(deep.resolve("base.xsd"), "<xsd/>");
+
+        Path baseName = dir.getFileName();
+        Path srcResources = tempDir.resolve("export/src/main/resources");
+        Files.createDirectories(srcResources);
+
+        for (Path source : Run.walkResourceDir(dir)) {
+            Path relativePath = dir.relativize(source);
+            Path target = srcResources.resolve(baseName).resolve(relativePath);
+            Files.createDirectories(target.getParent());
+            Files.copy(source, target);
+        }
+
+        assertThat(srcResources.resolve("soap/service.wsdl")).exists();
+        
assertThat(srcResources.resolve("soap/types/common/base.xsd")).exists();
+    }
+}
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesExport.java
 
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesExport.java
index 8baf5bc56aa1..57243c453ba6 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesExport.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesExport.java
@@ -185,6 +185,7 @@ public class KubernetesExport extends Export {
         logging = configurer.logging;
         loggingLevel = configurer.loggingLevel;
         verbose = configurer.verbose;
+        resourceDirs = configurer.resourceDirs;
         observe = true; // always include observability-services for kubernetes
     }
 
@@ -662,6 +663,7 @@ public class KubernetesExport extends Export {
             String loggingLevel,
             boolean verbose,
             boolean skipPlugins,
+            List<String> resourceDirs,
             String camelQuarkusGroupId,
             String camelQuarkusArtifactId,
             String camelQuarkusVersion) implements QuarkusPlatformMixinSpec, 
MavenResolverMixinSpec {
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesRun.java
 
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesRun.java
index 80b0ab78749b..d4aad60ce30c 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesRun.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/main/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesRun.java
@@ -207,6 +207,11 @@ public class KubernetesRun extends KubernetesBaseCommand {
     @CommandLine.Option(names = { "--exclude" }, description = "Exclude files 
by name or pattern")
     List<String> excludes = new ArrayList<>();
 
+    @CommandLine.Option(names = { "--resource-dir", "--resource-dirs" },
+                        description = "Additional resource directories to 
include in src/main/resources (recursive, preserving structure)",
+                        split = ",")
+    List<String> resourceDirs = new ArrayList<>();
+
     @CommandLine.Option(names = { "--package-scan-jars" }, defaultValue = 
"false",
                         description = "Whether to automatic package scan JARs 
for custom Spring or Quarkus beans making them available for Camel CLI")
     boolean packageScanJars;
@@ -482,6 +487,7 @@ public class KubernetesRun extends KubernetesBaseCommand {
                 "info",
                 verbose,
                 skipPlugins,
+                resourceDirs,
                 quarkusPlatformBoms.quarkusCamelBom().getGroupId(),
                 quarkusPlatformBoms.quarkusCamelBom().getArtifactId(),
                 quarkusPlatformBoms.quarkusCamelBom().getVersion());

Reply via email to