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

davsclaus pushed a commit to branch feature/CAMEL-24226-resource-dirs
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 40e3d76596ffd6e0e6677798fca552d67f0ac085
Author: Claus Ibsen <[email protected]>
AuthorDate: Tue Jul 21 16:06:36 2026 +0200

    CAMEL-24226: camel run/export - add --resource-dirs option to copy 
directories preserving structure
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
---
 .../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  |  48 +++++++
 .../dsl/jbang/core/common/CamelJBangConstants.java |   4 +
 .../dsl/jbang/core/commands/ResourceDirsTest.java  | 160 +++++++++++++++++++++
 .../core/commands/kubernetes/KubernetesExport.java |   2 +
 .../core/commands/kubernetes/KubernetesRun.java    |   6 +
 19 files changed, 345 insertions(+), 7 deletions(-)

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..036bebb78412 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,32 @@ 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 (!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..7eb3dd9fcffc
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ResourceDirsTest.java
@@ -0,0 +1,160 @@
+/*
+ * 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 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