Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 113 additions & 0 deletions .claude/skills/add-rebase-rules/SKILL.md
Original file line number Diff line number Diff line change
@@ -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='' <sha> | 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/<path>.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/<path>` for new keys or additive nested values
- `.rebase/override/<path>` 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/<original-path>.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:
- `#### @<author>`
- 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 <file>`)
- For each changed `.rebase/replace/**/*.json`, verify every `from` exists in the upstream file content before finishing.
- Example: `git show <upstream-ref>:<path-without-code-prefix>` 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`
135 changes: 135 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -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/<version>` — 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.
25 changes: 24 additions & 1 deletion build/dockerfiles/dev.Dockerfile
Original file line number Diff line number Diff line change
@@ -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/
Expand All @@ -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
Expand Down
28 changes: 28 additions & 0 deletions devfile.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Loading