diff --git a/.claude/skills/add-rebase-rules/SKILL.md b/.claude/skills/add-rebase-rules/SKILL.md new file mode 100644 index 00000000000..d7b89d75275 --- /dev/null +++ b/.claude/skills/add-rebase-rules/SKILL.md @@ -0,0 +1,113 @@ +--- +name: add-rebase-rules +description: Generates .rebase add/override/replace rules from a commit that changes code/ files, updates rebase.sh conflict routing, and appends .rebase/CHANGELOG.md. Use when asked to add rebasing rules for a commit or PR. +argument-hint: [commit-sha] +disable-model-invocation: true +--- + +# Add Rebase Rules + +Create or update rebasing rules for Che-specific changes that touch VS Code subtree files under `code/`. + +Use this skill when the user gives a commit SHA (or PR/commit URL) and asks to add rebasing rules. + +## Required input + +- A commit SHA is expected in `$ARGUMENTS`. +- If `$ARGUMENTS` is empty, ask the user for a commit SHA before proceeding. + +## Scope and exclusions + +Only consider changed files under `code/`. + +Never create rebasing rules for: +- `code/extensions/che-*/**` +- any `**/package-lock.json` + +Important: +- A file can be under `code/` and still be Che-only (for example `code/src/.../che/...` newly created by Che). Do not create a rule for such files if they are not upstream VS Code files. +- Still create rules for the upstream file(s) that import/use those Che-only helpers. + +## Workflow + +1. Resolve the target commit and collect changed files + - If input is a URL, extract the SHA. + - Get changed files: + - `git show --name-only --pretty='' | sort -u` + - Filter to the rule candidate set: + - include: files starting with `code/` + - exclude: `code/extensions/che-*/**` + - exclude: `**/package-lock.json` + +2. Classify each candidate file + - `*/package.json` -> JSON merge rule (`.rebase/add/` and/or `.rebase/override/`) + - Other modified upstream files -> replace rule (`.rebase/replace/.json`) + - Newly added Che-only files with no upstream counterpart -> skip (no rule needed) + +3. Create or update JSON merge rules for `package.json` + - Preserve only minimal changed subtree (do not copy entire package.json). + - Use: + - `.rebase/add/` for new keys or additive nested values + - `.rebase/override/` when overriding existing values must be explicit + - It is valid to use both for one file. + - Keep file formatting consistent with existing `.rebase` JSON style (2-space indentation). + +4. Create or update replace rules for non-JSON files + - File path: `.rebase/replace/.json` + - Format: JSON array of objects with `from` and `by`. + - Add one rule per changed hunk, using stable and unique snippets. + - Prefer the smallest safe snippet that is unlikely to change accidentally. + - If replacement is multiline, encode using escaped newlines/tabs in JSON consistently with existing files. + - For multiline `from` snippets, start at the first non-whitespace token (avoid anchoring on leading indentation only). + - Prefer replacing the whole logical block (`if (...) { ... }`) rather than only an inner line fragment, so closing braces remain structurally correct. + +5. Update `rebase.sh` conflict routing + - Ensure each file that now has a new rebasing rule is routable in `resolve_conflicts`. + - For `package.json` files: + - add `elif` branch calling `apply_package_changes_by_path "$conflictingFile"` (or equivalent existing pattern). + - For non-JSON replace rules: + - use `apply_changes "$conflictingFile"` for line-based replacements. + - For multiline replacements, `rebase.sh` has **two** handlers — do not always default to one: + - `apply_changes_multi_line "$conflictingFile"` — higher-level wrapper that resets the file (`git checkout --theirs`), calls `apply_multi_line_replace`, then stages the result (`git add`). + - `apply_multi_line_replace "$conflictingFile"` — low-level function that performs the Perl multiline replacement directly, without git checkout/add. + - Before adding a routing branch, inspect the existing `resolve_conflicts` block in `rebase.sh` and look at how other files in the same area are routed. Match the handler already used for similar files. For example, if neighboring entries call `apply_multi_line_replace` directly, use that; if they use `apply_changes_multi_line`, use that instead. + - Do not add duplicate branches. + +6. Update `.rebase/CHANGELOG.md` + - Append a new entry in existing format: + - `#### @` + - commit/PR link (or commit SHA if no link is available) + - list only files for which rebasing rules were added/updated + - separator `---` + +7. Validate before finishing + - Determine the upstream ref from `rebase.sh` and use that exact ref for validation (do not hardcode a release branch in the skill output). + - Example source of truth in `rebase.sh`: `UPSTREAM_VERSION=$(git rev-parse upstream-code/release/1.108)` + - If the script later points to `upstream-code/main` or another release branch, use that new ref instead. + - `bash -n rebase.sh` + - JSON validation for changed `.rebase/**/*.json` files (`jq empty `) + - For each changed `.rebase/replace/**/*.json`, verify every `from` exists in the upstream file content before finishing. + - Example: `git show :` and compare with the `from` snippet. + - `path-without-code-prefix` means the same file path but without the leading `code/` (because `upstream-code` stores VS Code sources at repo root). + - Dry-run the generated rule using the same replacement path as `rebase.sh` (Perl-based multiline replace), not a language-native `.replace(...)`. + - Include at least one test case where `from`/`by` contains `$` (for example template literals like `${key}`) and confirm replacement still succeeds. + - Re-check exclusions: + - no rules for `code/extensions/che-*` + - no rules for `package-lock.json` + - Ensure every changed rule file is actually referenced by logic in `rebase.sh` when required. + +## Decision notes + +- Goal is to protect Che-specific behavior during upstream subtree rebases while keeping deltas in upstream files minimal. +- Prefer moving larger Che logic into Che-owned files and keeping upstream file edits small; then create replace rules only for the upstream file edits. +- When unsure between `add` vs `override` for JSON, follow existing `.rebase` conventions in neighboring files and keep the smallest rule payload that reproduces the required result. + +## Examples + +- Dependency override updates across many `code/**/package.json` files: + - Example commit: `04b7984047fec31dd6993bd299f6698750c63d08` + - Matching rule-update style: `eec9cd1e9e199ce9a0eb2f6e3bd1dad6fc258413` + +- Source-level VS Code file changes protected by replace rules: + - Example PR changes: `https://github.com/che-incubator/che-code/pull/617/changes` + - Matching rule commit: `https://github.com/che-incubator/che-code/pull/617/changes/e794c63f01d116b0b92d5ecd220247e13a5ba946` diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000000..a5065c84f86 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,135 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +**che-code** is Eclipse Che's fork of Microsoft's VS Code (Code-OSS) that runs in a browser, connecting to a remote HTTP(s) server on Kubernetes instead of desktop mode. The terminal is container-aware: it can open shells in any container of the running pod. + +Upstream VS Code is stored as a Git subtree in the `code/` directory. The repository is self-contained (no submodule setup needed). + +## Build & Development Commands + +### Development Mode +```bash +npm install # Install deps + download built-in extensions (runs in code/) +npm run watch # Compile and watch for changes +npm run server # Run VS Code server at localhost:8000 (dev mode) +``` + +### Production Build +```bash +npm run build # Build vscode-reh-web-linux-x64 (unminified) +npm run build:min # Build vscode-reh-web-linux-x64 (minified) +npm run rebuild-native-modules # Rebuild native Node modules +``` + +### Container Image Build (in order) +```bash +podman build -f build/dockerfiles/linux-musl.Dockerfile -t linux-musl . +podman build -f build/dockerfiles/linux-libc-ubi8.Dockerfile -t linux-libc-ubi8 . +podman build -f build/dockerfiles/linux-libc-ubi9.Dockerfile -t linux-libc-ubi9 . +podman build -f build/dockerfiles/assembly.Dockerfile -t che-code . +``` + +### Running the Container Locally +```bash +podman run --rm -it -p 3100:3100 -e CODE_HOST=0.0.0.0 quay.io/che-incubator/che-code:next +``` + +### Tests (inside `code/`) +```bash +cd code +npm run test-node # Mocha unit tests (Node.js) +npm run test-browser # Browser unit tests (Playwright) +npm run test-extension # Extension tests (vscode-test) +npm run smoketest # Full smoke test suite +``` + +### Linting (inside `code/`) +```bash +cd code +node build/eslint # ESLint +node build/stylelint # Stylelint +npm run hygiene # Full hygiene check (formatting, imports, layers) +npm run valid-layers-check # Architecture layer validation +``` + +### Launcher (`launcher/`) +```bash +cd launcher +npm run compile # TypeScript compile +npm run lint # ESLint +npm run format # Prettier check +npm run format:fix # Prettier auto-fix +npm run build # Full build (format + compile + lint + test) +``` +Launcher uses Jest for testing, TypeScript 5.6+, and ES2022 modules. + +### Che Extension License Check +```bash +npm --prefix code/extensions/che-api run license:generate +``` +Replace `che-api` with any Che extension name. Generates dependency reports in `.deps/`. + +## Architecture + +### Directory Structure + +- **`code/`** — VS Code upstream (git subtree) with Che modifications. This is where the bulk of the editor source lives (`code/src/vs/`, `code/extensions/`). +- **`launcher/`** — Standalone TypeScript project that configures and launches VS Code in Kubernetes. Handles workspace config, product.json generation, Open VSX registry integration, SSL certificates, and Kubernetes API interaction. +- **`build/dockerfiles/`** — Multi-stage Dockerfiles for three platform targets (musl/Alpine, libc-ubi8, libc-ubi9) plus an assembly Dockerfile that combines them. +- **`build/scripts/`** — Container entrypoint scripts (`entrypoint.sh`, `entrypoint-volume.sh`, `entrypoint-init-container.sh`). +- **`build/artifacts/`** — `artifacts.lock.yaml` locks built-in extension versions with SHA256 checksums. Regenerate with `./build/artifacts/generate.sh`. +- **`branding/`** — UI branding customization (icons, product.json overrides, CSS). Applied via `branding/branding.sh`. +- **`.rebase/`** — Patch management for upstream rebasing: + - `add/` — Files to add to upstream + - `override/` — JSON files to merge over upstream (via jq) + - `replace/` — Per-file JSON replacement rules keyed by file path (not full file swaps). Each entry is a JSON object with `from` and `by` strings applied to the specified file path. + +### Che-Specific Extensions (in `code/extensions/`) + +Nine extensions provide Kubernetes/Che integration: +- `che-api` — API for Che platform integration +- `che-activity-tracker` — User activity tracking +- `che-commands` — Custom command support +- `che-github-authentication` — GitHub OAuth flow +- `che-port` — Port exposure management for pods +- `che-remote` — Remote workspace status indicator +- `che-resource-monitor` — Resource usage monitoring +- `che-terminal` — Container-aware terminal (open shells in any pod container) +- `che-telemetry` — Telemetry collection + +### Key Entry Points + +- `code/src/server-main.ts` — VS Code remote server entry point +- `code/src/vs/` — Core VS Code modules (layered architecture enforced by `valid-layers-check`) +- `launcher/src/entrypoint.ts` — Launcher entry point for Kubernetes environments +- `launcher/src/vscode-launcher.ts` — VS Code process management + +### Upstream Rebase Workflow + +To rebase on upstream VS Code: +1. `git remote add upstream-code https://github.com/microsoft/vscode` (if not already added) +2. `git fetch upstream-code release/` — fetch the release branch that `rebase.sh` targets (check `UPSTREAM_VERSION` in `rebase.sh` for the current ref, e.g. `upstream-code/release/1.104`) +3. `./rebase.sh` — Pulls subtree, applies `.rebase/` patches, updates JSON overrides +4. Fix any conflicts +5. `./build/artifacts/generate.sh` to update `artifacts.lock.yaml` + +### Build System + +The `code/` directory uses Gulp as its build system. Key gulp tasks: +- `vscode-reh-web-linux-x64` / `vscode-reh-web-linux-x64-min` — Build the remote web host +- `watch-client` / `watch-extensions` — Watch mode (both run in parallel via `npm run watch`) +- `compile-build-with-mangling` — Production compilation with name mangling + +Node.js version must match what upstream VS Code requires (check `code/remote/.npmrc` for the `target` property). + +### Multi-Platform Container Strategy + +The final image is assembled from three platform-specific builds: +- **linux-musl** — Alpine Linux (musl libc) +- **linux-libc-ubi8** — Red Hat UBI 8 +- **linux-libc-ubi9** — Red Hat UBI 9 + +The `assembly.Dockerfile` combines all three into a single image that selects the right binary at runtime. \ No newline at end of file diff --git a/build/dockerfiles/dev.Dockerfile b/build/dockerfiles/dev.Dockerfile index 22ffd7d8f85..17a83c5a007 100644 --- a/build/dockerfiles/dev.Dockerfile +++ b/build/dockerfiles/dev.Dockerfile @@ -1,4 +1,4 @@ -# Copyright (c) 2022 Red Hat, Inc. +# Copyright (c) 2022-2026 Red Hat, Inc. # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ @@ -18,6 +18,29 @@ RUN dnf -y install libsecret libX11-devel libxkbcommon \ util-linux-user && \ dnf -y clean all --enablerepo='*' +# Pin gcloud CLI to a tested release from the official RHEL/CentOS repository. +# See https://cloud.google.com/sdk/docs/release-notes for recent versions. +ARG GCLOUD_CLI_VERSION=563.0.0 +RUN printf '%s\n' \ + '[google-cloud-cli]' \ + 'name=Google Cloud CLI' \ + 'baseurl=https://packages.cloud.google.com/yum/repos/cloud-sdk-el9-x86_64' \ + 'enabled=1' \ + 'gpgcheck=1' \ + 'repo_gpgcheck=0' \ + 'gpgkey=https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg' \ + > /etc/yum.repos.d/google-cloud-sdk.repo && \ + dnf makecache --repo=google-cloud-cli && \ + dnf list --showduplicates google-cloud-cli 2>/dev/null \ + | grep -q "${GCLOUD_CLI_VERSION}" || \ + { echo "ERROR: google-cloud-cli version ${GCLOUD_CLI_VERSION} not found in repo."; \ + echo "Available versions (most recent last):"; \ + dnf list --showduplicates google-cloud-cli 2>/dev/null | tail -10; \ + exit 1; } && \ + dnf -y install libxcrypt-compat google-cloud-cli-${GCLOUD_CLI_VERSION} && \ + dnf -y clean all --enablerepo='*' && \ + gcloud --version + COPY --chmod=664 /build/conf/dev/.p10k.zsh /home/user/.p10k.zsh # zsh support diff --git a/devfile.yaml b/devfile.yaml index 50278da3364..095d54902db 100644 --- a/devfile.yaml +++ b/devfile.yaml @@ -129,3 +129,31 @@ commands: git stash save --include-untracked git fetch upstream-code main ./rebase.sh + + - id: install-claude + exec: + label: Install Claude CLI + component: dev + env: + - name: DISABLE_AUTOUPDATER + value: "1" + commandLine: | + set -euo pipefail + # Bump version: https://github.com/anthropics/claude-code/releases + CLAUDE_VERSION="2.1.92" + GCS_BASE="https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases" + PLATFORM="linux-x64" + INSTALL_DIR="$HOME/.local/bin" + mkdir -p "$INSTALL_DIR" + echo "Installing Claude Code v${CLAUDE_VERSION} for ${PLATFORM}..." + MANIFEST=$(curl -fsSL "${GCS_BASE}/${CLAUDE_VERSION}/manifest.json") + EXPECTED_SHA=$(echo "$MANIFEST" | python3 -c "import json,sys; print(json.load(sys.stdin)['platforms']['${PLATFORM}']['checksum'])") + curl -fSL --progress-bar -o "${INSTALL_DIR}/claude" "${GCS_BASE}/${CLAUDE_VERSION}/${PLATFORM}/claude" + ACTUAL_SHA=$(sha256sum "${INSTALL_DIR}/claude" | cut -d' ' -f1) + if [ "$ACTUAL_SHA" != "$EXPECTED_SHA" ]; then + echo "SHA-256 mismatch! expected=${EXPECTED_SHA} actual=${ACTUAL_SHA}" >&2 + rm -f "${INSTALL_DIR}/claude" + exit 1 + fi + chmod +x "${INSTALL_DIR}/claude" + echo "Verified and installed Claude Code v${CLAUDE_VERSION} to ${INSTALL_DIR}/claude"