This is an automated email from the ASF dual-hosted git repository. mgubaidullin pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel-karavan.git
commit 1dd91f2d2a949260507e750c2397eab504ded50f Author: Marat Gubaidullin <[email protected]> AuthorDate: Mon Aug 24 11:52:41 2026 -0400 Support Agentic Development --- .gitignore | 3 +- Dockerfile.claude | 34 +++++ claude_vscode.sh | 13 ++ claude_webapp.sh | 13 ++ karavan-vscode/AGENT.md | 328 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 390 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 34e57bdc..e7fd918c 100644 --- a/.gitignore +++ b/.gitignore @@ -83,4 +83,5 @@ docs/install/karavan-docker/data/* **/dependency-reduced-pom.xml .env -stats.html \ No newline at end of file +stats.html +.task_report.md \ No newline at end of file diff --git a/Dockerfile.claude b/Dockerfile.claude new file mode 100644 index 00000000..3f7631fd --- /dev/null +++ b/Dockerfile.claude @@ -0,0 +1,34 @@ +FROM registry.access.redhat.com/ubi9/openjdk-21-runtime:1.24 + +# The UBI runtime image defaults to a non-root user. +# We switch to root to install dependencies and give Claude full execution rights in the sandbox. +USER root + +# 1. Update existing packages +RUN microdnf update -y + +# 2. Install packages one by one to find the culprit +RUN microdnf install -y nodejs +RUN microdnf install -y npm +RUN microdnf install -y git +RUN microdnf install -y python3 +RUN microdnf install -y jq +RUN microdnf install -y gcc +RUN microdnf install -y tar +RUN microdnf install -y make + +# 3. Clean up +RUN microdnf clean all + +# Install Claude Code globally +RUN npm install -g @anthropic-ai/claude-code + +WORKDIR /karavan + +USER default + +# Set the entrypoint to the Claude CLI +ENTRYPOINT ["claude"] + +# Append the permission skip flag by default +CMD ["--dangerously-skip-permissions"] \ No newline at end of file diff --git a/claude_vscode.sh b/claude_vscode.sh new file mode 100755 index 00000000..f6315d4f --- /dev/null +++ b/claude_vscode.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +docker run -it --rm \ + --name claude-sandbox \ + -v "$(pwd)/docs:/karavan/docs" \ + -v "$(pwd)/karavan-vscode:/karavan/karavan-vscode" \ + -v "$(pwd)/.github/workflow/vscode.yml:/karavan/.github/workflow/vscode.yml" \ + -v "$(pwd)/.git:/karavan/.git:ro" \ + -v claude-config:/home/default \ + -e ANTHROPIC_API_KEY \ + claude-sandbox \ + --dangerously-skip-permissions \ + "Read /karavan/karavan-vscode/task.md. Execute the tasks described within, make the necessary code changes, and generate a concise summary report saved to /karavan/karavan-vscode/.task_report.md. Exit the process when you are completely finished." \ No newline at end of file diff --git a/claude_webapp.sh b/claude_webapp.sh new file mode 100755 index 00000000..b5ed0f50 --- /dev/null +++ b/claude_webapp.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +docker run -it --rm --network=karavan \ + --name claude-sandbox \ + -v "$(pwd)/docs:/karavan/docs" \ + -v "$(pwd)/karavan-app:/karavan/karavan-app" \ + -v "$(pwd)/karavan-generator:/karavan/karavan-generator" \ + -v "$(pwd)/.git:/karavan/.git:ro" \ + -v claude-config:/home/default \ + -e ANTHROPIC_API_KEY \ + claude-sandbox \ + --dangerously-skip-permissions \ + "Read /karavan/karavan-app/task.md. Execute the tasks described within, make the necessary code changes, and generate a concise summary report saved to /karavan/karavan-app/.task_report.md. Exit the process when you are completely finished." \ No newline at end of file diff --git a/karavan-vscode/AGENT.md b/karavan-vscode/AGENT.md new file mode 100644 index 00000000..7db70249 --- /dev/null +++ b/karavan-vscode/AGENT.md @@ -0,0 +1,328 @@ +# AGENT.md — Apache Camel Karavan VS Code Developer Agent + +Operating guide for an AI agent working on the **Karavan VS Code extension**. +Everything below was verified against the code in this checkout at extension version +**4.22.0**. Paths are relative to `karavan-vscode/` unless stated otherwise. + +--- + +## 1. What this project is + +Karavan is an *Integration Toolkit for Apache Camel*. The VS Code extension +(`karavan-vscode`, publisher `camel-karavan`, marketplace id `camel-karavan.karavan`) +embeds the Karavan visual designer as a **webview** and drives Camel JBang / Maven from +the VS Code UI. + +It reads and writes **Camel YAML**: plain routes (`*.camel.yaml`), Kamelets +(`*.kamelet.yaml`) and Integration CRDs (`kind: Integration`). + +### Layout + +``` +/karavan +├── docs/ ← user + developer docs (DEV.md, VSCODE_HOWTO.md, …) +└── karavan-vscode/ ← the extension (the only module checked out here) + ├── AGENT.md ← this file + ├── src/ ← extension host code (Node, webpack target "node") + ├── webview/ ← React UI bundled into dist/webview.js + │ ├── index.tsx App.tsx vscode.ts prerender.tsx + │ ├── karavan/ ← designer, topology, documentation, stores + │ └── karavan-core/ ← vendored copy of karavan-core (Camel model + YAML API) + ├── metadata/ ← components.json (7.3M), kamelets.yaml (1.9M), spiBeans.json + ├── snippets/ ← Java templates per runtime (Processor, AggregationStrategy) + ├── icons/ images/ + ├── webpack.config.js tsconfig.json package.json + └── dist/ ← build output (gitignored) +``` + +> Other monorepo modules (`karavan-app`, `karavan-core`, `karavan-designer`, +> `karavan-generator`, `karavan-devmode`, `release-utils`, `.github/**`) are *OUT OF SCOPE*. Do not read them; +> The repository root `/karavan` is not writable; +> write inside `karavan-vscode/` or `docs/`. + +--- + +## 2. Architecture + +### 2.1 Three bundles, one build + +`webpack.config.js` exports three configs, all built in one run: + +| Config | Entry | Target | Output | +|--------------|-------------------------|---------|--------| +| extension | `src/extension.ts` | node | `dist/extension.js` (commonjs2, `vscode` external) | +| webview | `webview/index.tsx` | web | `dist/webview.js` + `dist/main.css` | +| prerender | `webview/prerender.tsx` | node | `dist/prerender.js` (SSR helper; excluded from the VSIX by `.vscodeignore`) | + +`package.json` declares both `main` and `browser` as `./dist/extension.js`, so the +extension is also meant to run as a **web extension** (`vscode-test-web`, +`--extensionDevelopmentKind=web`). Keep `src/` free of Node-only APIs — file I/O already +goes through `workspace.fs`, not `node:fs`. + +### 2.2 Extension host (`src/`, ~1.9k LOC) + +| File | Responsibility | +|------|----------------| +| `extension.ts` | `activate()` — registers every command and tree view; `exportAndRunProject()`; `deactivate()` clears the `karavan:loaded` context key. | +| `designerView.ts` | Owns designer webview panels (`KARAVAN_PANELS: Map<relativePath, WebviewPanel>`), the message protocol, and data loading. | +| `topologyView.ts` | Single `topology` panel showing the route topology graph. | +| `helpView.ts` | "Help & Feedback" tree + the Knowledgebase webview. | +| `integrationView.ts` | `integrations` tree: scans `*.yaml`, keeps those `CamelDefinitionYaml.yamlIsIntegration()` accepts; children are the flows. | +| `openapiView.ts` | OpenAPI discovery (`*.json` / `*.yaml` with an `openapi` key) + the "Generate REST API" quick-pick flow. | +| `jbang.ts` | Builds Camel JBang command lines (`run`, `export`, `generate rest`). | +| `exec.ts` | `shelljs` exec + a `Map<id, Terminal>` of reusable terminals; `runWithRuntime()`, `camelDeploy()`. | +| `maven.ts` | Two command builders — **currently unreferenced**. | +| `utils.ts` | Everything else: file I/O via `workspace.fs`, kamelet/component/template/bean/java loading, `application.properties` handling, naming rules. | +| `webviewContent.ts` | The HTML shell for every panel (loads `dist/main.css` + `dist/webview.js`). | + +### 2.3 Webview (`webview/`) + +- `index.tsx` mounts `<ThemeProvider><App/></ThemeProvider>` into `#root`. +- `App.tsx` is a **class component** holding all state and is the sole message endpoint. + It renders one of three pages: `designer` (`KaravanDesigner`), `topology` + (`TopologyTab`) or `knowledgebase` (`DocumentationPage`). +- `webview/vscode.ts` exports the `acquireVsCodeApi()` handle (`undefined` outside VS + Code — the prerender build relies on that). +- State: **zustand** stores (`stores/*.ts`, `designer/DesignerStore.ts`, + `designer/CodeStore.ts`), created with `createWithEqualityFn` + `shallow`. +- Cross-component events: **rxjs** `Subject`s in `designer/utils/EventBus.ts` + (`DslPosition`, `Command`, `IntegrationUpdate`, alerts). +- Host callbacks are injected into the designer through the static + `designer/utils/InfrastructureAPI` class (`setOnSave`, `setOnSaveCustomCode`, + `setOnInternalConsumerClick`, …). `KaravanDesigner` wires these in its mount effect. +- UI kit: PatternFly 6 (`react-core`, `react-topology`, `react-table`), Monaco editor, + `elkjs` for topology layout. + +### 2.4 `webview/karavan-core` — generated, vendored, and drifting + +A **copy** of the upstream `karavan-core/src/core` module, reachable via the +`@karavan-core/*` tsconfig alias. +- `webview/karavan-core` is **machine-generated** by `karavan-generator` from the Camel catalog. Do not hand-edit. + +### 2.5 `metadata/` and `snippets/` + +`metadata/{components.json,kamelets.yaml,spiBeans.json}` are generated by +`karavan-generator` (`KaravanGenerator.main` clears and regenerates +`karavan-vscode/metadata`) and copied into `dist/metadata` by the prerender config's +`CopyPlugin`. Treat them as build artifacts: regenerate, never hand-edit. + +`snippets/<runtime>-<javaType>.java` are Java code templates; `utils.readTemplates()` +selects those whose filename starts with the active runtime and strips the prefix. + +--- + +## 3. Host ⇄ webview message protocol + +The single source of truth. Adding a feature almost always means touching **both** ends. + +**Webview → host** (`vscode.postMessage`, handled in `designerView.ts` / +`topologyView.ts` / `helpView.ts` `onDidReceiveMessage`): + +| command | payload | handler | +|---|---|---| +| `getData` | `reread?: boolean` | `sendData()` — loads kamelets, components, templates, java code, property placeholders, beans | +| `save` | `relativePath`, `code` | `utils.save()` | +| `saveCode` | `name`, `yamlFullPath`, `yamFileName`, `code` | writes `<name>.java` next to the YAML | +| `savePropertyPlaceholder` | `key`, `value` | appends to `application.properties` | +| `internalConsumerClick` | `uri`/`name`/`routeId`/`fileName` | resolves the peer file via `TopologyUtils`, runs `karavan.open` | +| `openFile` (topology only) | `fileName` | runs `karavan.open` | + +**Host → webview** (`panel.webview.postMessage`, handled in `App.onMessage`): +`kamelets`, `components`, `templates`, `javaCode`, `files`, `open` +(`{page, filename, relativePath, fullPath, yaml, tab, propertyPlaceholders, beans}`), +`activate` (`{tab}`), `deactivate`, `downloadImage`, `reread` (help view only). + +Notes that bite: + +- `App` only accepts `open` when `filename === '' && key === ''`. `activate` resets those + fields and re-requests data with `reread: true` — that is the reload path. +- The designer autosaves on a **2 s `setInterval`** (`saveScheduledChanges`), and only + while `state.active`. The interval is cleared for non-designer pages. +- Panels are keyed by **relative path** in `designerView.ts`, but `downloadImage()` looks + the panel up by **filename** — they only coincide for files at the workspace root. + +--- + +## 4. Commands, views and configuration + +Contributions live in `package.json`. Commands (all prefixed `karavan.` except the +refresher): `topology`, `create-yaml`, `create-kamelet`, `create-application`, `open`, +`open-file`, `run-project-jbang`, `run-project-runtime`, `jbang-export`, `deploy`, +`generate-rest`, `download-image`, `openKnowledgebase`, `reportIssue`, +`integrations.refresh`. + +View container `karavanView` contributes two views: `integrations` and `help`. + +> `extension.ts` also calls `window.registerTreeDataProvider('openapi', …)` and registers +> `openapi.refresh`, but **no `openapi` view is contributed** in `package.json`, so that +> tree is never rendered. `karavan.generate-rest` is still reachable from the explorer +> context menu. Fix by adding the view contribution — don't "clean up" the provider. + +Settings use two prefixes — keep the convention: + +- `camel.*` — `version`, `runtimes` (`camel-main` | `quarkus` | `spring-boot`), + `deployTarget` (`openshift` | `kubernetes` | `none`), `maxMessages`, `loggingLevel`, + `dev`, `messageTracing`. +- `Karavan.*` — `kameletsPath`, `defaultGroupId`, `applicationGitignore`, and the + templated command/properties arrays. + +The templated settings are resolved **by string concatenation**: + +``` +"Karavan." + runtime.replaceAll("-","") + capitalize(target) + "Deploy" // exec.camelDeploy +"Karavan." + runtime.replaceAll("-","") + "ApplicationProperties" // utils.createApplicationProperties +"Karavan." + runtime.replaceAll("-","") + capitalize(target) + "Properties" // utils.createApplicationProperties +``` + +**Adding a runtime or deploy target means adding every matching key** (e.g. +`Karavan.camelmainKubernetesDeploy`, `Karavan.camelmainKubernetesProperties`). A missing +key silently degrades to `''`. All 3 runtimes × {Openshift, Kubernetes} keys exist today; +the deliberate gap is target `none`, for which no `*NoneDeploy` / `*NoneProperties` keys +are defined. + +Placeholders substituted into generated `application.properties`: `$NAME`, `$GAV`, +`$RUNTIME`, `$TARGET` — the `if/else if` chain replaces **only the first match per +line**. `${NAMESPACE}` and `${DATE}` are resolved later as **terminal env vars** by +`exec.camelDeploy` (`DATE=Date.now()`, `NAMESPACE=oc project -q`). + +--- + +## 5. Runtime behaviour worth knowing + +- **Runtime resolution** (`utils.getRuntime`): `camel.jbang.runtime` from + `application.properties` wins; otherwise the `camel.runtimes` setting. +- **Export folder** (`utils.getExportFolder`): `camel.jbang.exportDir`, default prompt + value `.export`. `readCamelYamlFiles()` filters exported copies out of the file list. +- **JBang command shape** (`jbang.prepareCommand`): + `jbang "-Dcamel.jbang.version=<camel.version>" camel@apache/camel <cmd>`. +- **Run** = `run * [--max-messages=N] [--local-kamelet-dir=…] [--dev]`. + **Export** = `export --fresh --directory=<path> [--local-kamelet-dir=…]`. + **Runtime run** appends `&& mvn clean compile <quarkus:dev|spring-boot:run|camel:run> -f <path>`. +- Commands run in **named, reused terminals** (`jbang-run`, `runtime-run`, `deploy`); + `execTerminalCommand` disposes the previous terminal with the same id. +- `karavan.run-project-runtime` refuses to run when `application.properties` is empty + ("No runtime configured! Create application!"). +- Naming rules (`utils.nameFromTitle` / `fileNameFromName`): non-alphanumerics → `-`, + lowercased; kamelets get a `-<sink|source|action>` suffix and `.kamelet.yaml`, plain + integrations get `.camel.yaml`. +- Dead code today: `src/maven.ts` (both functions), `utils.deleteFile`, + `utils.toCliFilename`, `utils.setMinikubeEnvVariables`. + +--- + +## 6. Build, run, verify + +All commands run from `karavan-vscode/`. + +```bash +npm install # deps (Node 24 in CI) +npm run compile # webpack dev build of all three bundles (~15 s) +npm run package # production build +npm run watch # dev watch +npx vsce package # produce the .vsix +``` + +Debugging: `.vscode/launch.json` provides **Extension** (desktop extension host), +**Attach** (port 9229) and **Run Web Extension in VS Code**. Build tasks come from +`.vscode/tasks.json` (`npm: watch`). + +### Broken scripts — do not trust them as green/red signals + +| Script | Status | +|---|---| +| `npm run lint` / `lint:fix` | **fails immediately.** ESLint 9.33 requires flat config; the repo only has `.eslintrc.json`. Migrating to `eslint.config.js` is a real, unclaimed task. | +| `npm run test-compile` / `npx tsc --noEmit -p .` | **exits 2 with ~20 pre-existing errors** (baseline below). | +| `npm test` / `pretest` | **cannot run** — points at `out/test/runTest.js`; there is no `out/` and no test sources. The project has **zero automated tests**. | + +Pre-existing `tsc` baseline (not your regression — but don't add to it): + +- `webpack.config.js` — `TsconfigPathsPlugin` "not constructable". +- `karavan-core/api/TopologyUtils.ts` ×3, `useRouteDesignerHook.tsx` ×3, + `ProjectFunctionHook.tsx` ×4, `TopologyApi.tsx` ×3, `StringUtils.ts` ×5 — mostly + `string | undefined` under `strict`. +- `TopologyApi.tsx:472` — `TopologyUtils.findTopologyAsyncApiNodes` missing from the + vendored core (§2.4). +- `util/useFormUtil.tsx:19` — imports **`react-hook-form`, which is not in + `package.json`**. It only survives because ts-loader runs with `transpileOnly: true` + and nothing imports `useFormUtil`. Either add the dep or delete the file. + +**Because of `transpileOnly: true`, a successful webpack build proves nothing about +types.** Practical verification loop: + +1. `npm run compile` — must stay exit 0. +2. `npx tsc --noEmit -p . 2>&1 | grep -c "error TS"` — compare against the baseline. +3. Manual smoke test in the Extension Development Host (there is no test harness). + +CI (`git show HEAD:.github/workflows/vscode.yml`) only runs `npm update && npm install` +then `vsce package` on Node 24 — no lint, no tests, no typecheck. + +--- + +## 7. Conventions + +- **Apache License header on every new source file.** Copy the 16-line ASF block used + throughout `src/` and `webview/`; the license is Apache-2.0. +- TypeScript 5.9, `strict: true`, `target: es2022`, `jsx: "react"`. +- Import through the tsconfig path aliases, not relative climbs: `@karavan-core/*`, + `@app/*`, `@features/*`, `@models/*`, `@shared/*`, `@stores/*`, `@util/*`, `@/*`. +- Extension host: `import { X } from "vscode"` in `extension.ts`, `designerView.ts`, + `integrationView.ts`, `openapiView.ts`; `import * as vscode` in `topologyView.ts` and + `helpView.ts`. Match the file you are editing. +- File I/O in `src/` goes through `utils.ts` (`workspace.fs`), never `node:fs`. +- Register disposables with `context.subscriptions.push(...)` (a few registrations in + `activate()` skip this — follow the majority, not the omissions). +- Existing typos are part of the code's surface (`utils.parceYaml`, + `utils.getRalativePath`, `getFileWithIntegnalConsumer`, `saveCode(…, yamFileName, …)`). + Rename only as a deliberate, complete refactor. +- Indentation is inconsistent (4 spaces in most of `src/`, tabs in `integrationView.ts`, + `topologyView.ts`, `helpView.ts`, `openapiView.ts`). Match the file; don't reformat. + +--- + +## 8. Release / version bump + +Version lives in `package.json` and is normally driven by the monorepo script +`git show HEAD:change_version.sh`, which bumps every module, rewrites +`camel.jbang.version=…` in `karavan-vscode/README.md` and `docs/VSCODE_HOWTO.md`, and +patches `TAG:` in the workflows. `CHANGELOG.md` is maintained by hand. + +Current state to be aware of: `package.json` is **4.22.0** while `CHANGELOG.md`'s newest +entry and the `camel.version` default are **4.18.1** — the bump commit +(`0a2be04c bump version fo vscode to 4.22.0`) touched only the version. + +--- + +## 9. Playbooks + +**Add a command** +1. `contributes.commands` in `package.json` (+ `menus` entry, + `activationEvents` + `onCommand:` to match the existing style). +2. `commands.registerCommand` in `activate()`; push the disposable. +3. Implement in the matching `src/*.ts` module; reuse `utils`/`exec`/`jbang` helpers. +4. `npm run compile`, then smoke test in the Extension Development Host. + +**Add a designer ⇄ host round trip** +1. `vscode.postMessage({command: 'x', …})` in the webview. +2. New `case 'x'` in the panel's `onDidReceiveMessage` (`designerView.ts`). +3. If the host replies, add a `case` in `App.onMessage` plus a state field. +4. Remember `activate` → `getData {reread:true}` re-runs the whole load path. + +**Support a new runtime or deploy target** +1. No new runtimes should be added + +**Refresh Camel catalog / model** +1. Generated outside of this project + +--- + +## 10. Guardrails + +- Don't hand-edit `metadata/*`, `dist/*`, or the generated files in `webview/karavan-core`. +- Don't commit the monorepo deletions this pruned checkout reports. +- Don't claim "tests pass" — there are none. Don't claim "lint passes" — it can't run. +- A green `npm run compile` is a bundling result, not a type check (`transpileOnly`). +- The large metadata files make greps slow; scope searches with + `--include='*.ts' --include='*.tsx'` and exclude `node_modules`, `dist`, `metadata`. +- Webview panels set `enableScripts: true` with `localResourceRoots` limited to `dist`. + Keep it that way; don't widen the roots or inject remote script URLs into + `webviewContent.ts`.
