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-website.git


The following commit(s) were added to refs/heads/main by this push:
     new 32b61f87 CAMEL-23788: Generate versioned offline documentation bundles 
(#1667)
32b61f87 is described below

commit 32b61f8795d98046e52f569d707e803a1b3d5cfe
Author: Claus Ibsen <[email protected]>
AuthorDate: Thu Jun 18 13:48:07 2026 +0200

    CAMEL-23788: Generate versioned offline documentation bundles (#1667)
    
    * CAMEL-23788: Generate versioned offline documentation bundles
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * CAMEL-23788: drop camel-spring-boot from offline bundle
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * CAMEL-23788: drop kamelets from offline bundle, keep pure core camel
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * CAMEL-23788: use connectors/components wording for AI clarity
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * CAMEL-23788: include Camel Catalog and YAML DSL schema in offline bundle
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * CAMEL-23788: document zip directory structure in llms.txt for AI agents
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * chore: update llms.txt with camel-a2a component link and description
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    ---------
    
    Co-authored-by: Claude Opus 4.6 <[email protected]>
---
 .github/workflows/offline-bundle.yml |  69 +++++++++++++++
 llms-txt-template.md                 |  26 +++++-
 scripts/generate-offline-bundle.js   | 158 +++++++++++++++++++++++++++++++++++
 3 files changed, 252 insertions(+), 1 deletion(-)

diff --git a/.github/workflows/offline-bundle.yml 
b/.github/workflows/offline-bundle.yml
new file mode 100644
index 00000000..c2c9206d
--- /dev/null
+++ b/.github/workflows/offline-bundle.yml
@@ -0,0 +1,69 @@
+#
+# 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.
+#
+
+name: Generate Offline Documentation Bundle
+
+on:
+  workflow_dispatch:
+    inputs:
+      camel_version:
+        description: 'Camel version to bundle (e.g. 4.18)'
+        required: true
+        type: string
+
+jobs:
+  generate-bundle:
+    runs-on: ubuntu-latest
+    permissions:
+      contents: write
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v5
+
+      - name: Install dependencies
+        run: yarn workspaces foreach --all install
+
+      - name: Build site
+        run: yarn build
+        env:
+          CAMEL_ENV: production
+          HUGO_OPTIONS: --buildFuture
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+      - name: Generate versioned bundle
+        run: node scripts/generate-offline-bundle.js ${{ inputs.camel_version 
}}
+
+      - name: Create or update GitHub Release
+        run: |
+          TAG="docs-${{ inputs.camel_version }}"
+          FILE="public/camel-docs-${{ inputs.camel_version }}.zip"
+          TITLE="Apache Camel ${{ inputs.camel_version }} — Offline 
Documentation"
+          NOTES="Offline documentation bundle for Apache Camel ${{ 
inputs.camel_version }}.
+
+          Contains 350+ connector/component docs (Markdown), the user manual, 
the Camel Catalog (JSON metadata for all connectors/components, data formats, 
languages, and EIPs), and the YAML DSL canonical JSON Schema.
+
+          Download and unzip locally for AI coding agents or environments with 
restricted internet access."
+
+          # delete existing release if present so we can recreate it
+          gh release delete "$TAG" --yes 2>/dev/null || true
+
+          gh release create "$TAG" "$FILE" \
+            --title "$TITLE" \
+            --notes "$NOTES" \
+            --latest=false
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/llms-txt-template.md b/llms-txt-template.md
index badf76d9..98dd3929 100644
--- a/llms-txt-template.md
+++ b/llms-txt-template.md
@@ -7,6 +7,30 @@ For example:
 - HTML: 
`https://camel.apache.org/components/next/languages/simple-language.html`
 - Markdown: 
`https://camel.apache.org/components/next/languages/simple-language.md`
 
+## Offline documentation bundles
+
+For agents or environments with no or restricted internet access, versioned 
offline documentation bundles are available as zip archives of all Markdown 
files:
+- [Camel 
4.18](https://github.com/apache/camel-website/releases/download/docs-4.18/camel-docs-4.18.zip)
+- [Camel 
4.14](https://github.com/apache/camel-website/releases/download/docs-4.14/camel-docs-4.14.zip)
+
+Download the zip matching your Camel version, unzip it locally, and read the 
files from there. Each bundle contains:
+
+```
+components/<version>/      — 350+ connector/component docs (Markdown)
+manual/                    — user manual (Markdown)
+catalog/
+  components/              — 350+ connector/component metadata (JSON)
+  dataformats/             — data format metadata (JSON)
+  languages/               — expression language metadata (JSON)
+  models/                  — EIP model metadata (JSON)
+  others/                  — other component metadata (JSON)
+  schema/
+    camelYamlDsl-canonical.json — YAML DSL JSON Schema
+llms.txt                   — this file
+```
+
+The `catalog/` JSON files contain machine-readable metadata for every 
connector/component, data format, language, and EIP — parameters, types, 
defaults, and descriptions. The YAML DSL schema is the definitive spec for 
validating and generating Camel YAML routes.
+
 ## Key facts
 
 - Apache Camel is a **library**, not a platform — it embeds in your existing 
Spring Boot or Quarkus application
@@ -57,7 +81,7 @@ For example:
 - [Camel MCP Server](https://camel.apache.org/manual/camel-jbang-mcp.md): 
Model Context Protocol server for AI coding assistants (Claude Code, GitHub 
Copilot, Cursor, Gemini CLI).
 - [Camel 
LangChain4j](https://camel.apache.org/components/next/langchain4j-chat-component.md):
 LLM integration via LangChain4j.
 - [Camel 
OpenAI](https://camel.apache.org/components/next/openai-component.md): Native 
OpenAI component.
-- A2A (Agent-to-Agent): Camel supports the A2A protocol for connecting AI 
agents to enterprise systems.
+- [Camel A2A](https://camel.apache.org/components/next/a2a-component.md): 
Agent-to-Agent (A2A) protocol component — expose Camel routes as A2A agents or 
call remote A2A agents. Supports HTTP+JSON and JSONRPC bindings, 
OAuth/OIDC/API-key auth, and SSE streaming.
 
 ## Tooling
 
diff --git a/scripts/generate-offline-bundle.js 
b/scripts/generate-offline-bundle.js
new file mode 100644
index 00000000..7de6cefe
--- /dev/null
+++ b/scripts/generate-offline-bundle.js
@@ -0,0 +1,158 @@
+const fs = require('fs');
+const path = require('path');
+const { execFileSync } = require('child_process');
+
+const PUBLIC_DIR = 'public';
+const CAMEL_REPO = 'apache/camel';
+const CATALOG_BASE = 
'catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog';
+const YAML_SCHEMA_PATH = 
'dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl-canonical.json';
+
+const CATALOG_DIRS = ['components', 'dataformats', 'languages', 'models', 
'others'];
+
+const VERSION_DIRS = [
+  'components'
+];
+
+const SHARED_DIRS = [
+  'manual'
+];
+
+function fetchCatalogAndSchema(version) {
+  const branch = `camel-${version}.x`;
+  const catalogDir = path.join(PUBLIC_DIR, 'catalog');
+
+  console.log(`\nFetching catalog and YAML DSL schema from 
${CAMEL_REPO}@${branch}...`);
+
+  // fetch YAML DSL canonical schema
+  const schemaDir = path.join(catalogDir, 'schema');
+  fs.mkdirSync(schemaDir, { recursive: true });
+  try {
+    const schema = execFileSync('gh', [
+      'api', `repos/${CAMEL_REPO}/contents/${YAML_SCHEMA_PATH}?ref=${branch}`,
+      '--jq', '.content'
+    ], { encoding: 'utf8' });
+    fs.writeFileSync(
+      path.join(schemaDir, 'camelYamlDsl-canonical.json'),
+      Buffer.from(schema.trim(), 'base64').toString('utf8')
+    );
+    console.log('  Fetched schema/camelYamlDsl-canonical.json');
+  } catch (error) {
+    console.warn(`  Could not fetch YAML DSL schema: ${error.message}`);
+  }
+
+  // fetch catalog JSON files for each category
+  for (const dir of CATALOG_DIRS) {
+    const targetDir = path.join(catalogDir, dir);
+    fs.mkdirSync(targetDir, { recursive: true });
+    try {
+      const files = execFileSync('gh', [
+        'api', 
`repos/${CAMEL_REPO}/contents/${CATALOG_BASE}/${dir}?ref=${branch}`,
+        '--jq', '.[].name'
+      ], { encoding: 'utf8' }).trim().split('\n').filter(f => 
f.endsWith('.json'));
+
+      console.log(`  Fetching catalog/${dir}/ (${files.length} files)...`);
+
+      for (const file of files) {
+        try {
+          const content = execFileSync('gh', [
+            'api', 
`repos/${CAMEL_REPO}/contents/${CATALOG_BASE}/${dir}/${file}?ref=${branch}`,
+            '--jq', '.content'
+          ], { encoding: 'utf8' });
+          fs.writeFileSync(
+            path.join(targetDir, file),
+            Buffer.from(content.trim(), 'base64').toString('utf8')
+          );
+        } catch {
+          // skip individual file failures silently
+        }
+      }
+    } catch (error) {
+      console.warn(`  Could not fetch catalog/${dir}: ${error.message}`);
+    }
+  }
+
+  return fs.existsSync(catalogDir);
+}
+
+function main() {
+  const version = process.argv[2];
+  if (!version) {
+    console.error('Usage: node scripts/generate-offline-bundle.js <version>');
+    console.error('Example: node scripts/generate-offline-bundle.js 4.18');
+    process.exit(1);
+  }
+
+  const versionDir = `${version}.x`;
+  const bundleName = `camel-docs-${version}.zip`;
+  const bundlePath = path.join(PUBLIC_DIR, bundleName);
+
+  if (!fs.existsSync(PUBLIC_DIR)) {
+    console.error(`Cannot generate ${bundleName}: '${PUBLIC_DIR}' directory 
not found`);
+    process.exit(1);
+  }
+
+  // collect paths to include (relative to public/)
+  const includePaths = [];
+
+  for (const dir of VERSION_DIRS) {
+    const fullPath = path.join(PUBLIC_DIR, dir, versionDir);
+    if (fs.existsSync(fullPath)) {
+      includePaths.push(`${dir}/${versionDir}/*`);
+      console.log(`  Including ${dir}/${versionDir}/`);
+    } else {
+      console.warn(`  Skipping ${dir}/${versionDir}/ (not found)`);
+    }
+  }
+
+  for (const dir of SHARED_DIRS) {
+    const fullPath = path.join(PUBLIC_DIR, dir);
+    if (fs.existsSync(fullPath)) {
+      includePaths.push(`${dir}/*`);
+      console.log(`  Including ${dir}/`);
+    }
+  }
+
+  if (includePaths.length === 0) {
+    console.error(`No documentation directories found for version ${version}`);
+    process.exit(1);
+  }
+
+  // always include llms.txt if present
+  if (fs.existsSync(path.join(PUBLIC_DIR, 'llms.txt'))) {
+    includePaths.push('llms.txt');
+  }
+
+  // fetch catalog and YAML DSL schema from the camel repo
+  if (fetchCatalogAndSchema(version)) {
+    includePaths.push('catalog/*');
+  }
+
+  // remove stale bundle
+  if (fs.existsSync(bundlePath)) {
+    fs.unlinkSync(bundlePath);
+  }
+
+  // build zip: include .md files from doc dirs, plus .json from catalog, plus 
llms.txt
+  const zipArgs = ['-r', '-q', bundleName, '.'];
+  for (const p of includePaths) {
+    if (p === 'llms.txt') {
+      zipArgs.push('-i', 'llms.txt');
+    } else if (p.startsWith('catalog/')) {
+      zipArgs.push('-i', `${p}.json`);
+    } else {
+      zipArgs.push('-i', `${p}.md`);
+    }
+  }
+
+  try {
+    execFileSync('zip', zipArgs, { cwd: PUBLIC_DIR, stdio: 'inherit' });
+
+    const sizeMb = (fs.statSync(bundlePath).size / (1024 * 1024)).toFixed(1);
+    console.log(`\nGenerated ${bundleName} (${sizeMb} MB)`);
+  } catch (error) {
+    console.error(`Failed to generate ${bundleName}:`, error.message);
+    process.exit(1);
+  }
+}
+
+main();

Reply via email to