| 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
-
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
-
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)
-
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).
- Choosing add vs override for dependency version pins (e.g. CVE fixes):
- If the dependency already exists in the upstream
package.json (in dependencies, devDependencies, etc.) and we need a different version → use .rebase/override/ with the correct section. This is an override of an existing upstream value.
- If the fix uses npm
overrides (the npm feature that pins transitive dependency versions) and the override key does not exist in upstream's overrides section → use .rebase/add/. This is additive content absent from upstream.
- Prefer the JSON merge mechanism (add or override) over
.rebase/replace/ for package.json changes. However, .rebase/replace/ is acceptable when the change cannot be expressed by JSON merge alone — for example, replacing one dependency with a different package (e.g. swapping gulp-untar for gulp-decompress — see .rebase/replace/code/package.json.json) or inserting a new entry at a specific position among existing keys.
- Place each entry in the file where the dependency actually lives in upstream. For example, if
@vitest/coverage-v8 is a devDependency of code/extensions/copilot/package.json, its override rule belongs in .rebase/override/code/extensions/copilot/package.json, not in a sibling package.
-
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.
- Ensure
from appears exactly once in the upstream file. Both sed and perl handlers replace all occurrences — if from matches multiple places, all will be replaced, which is almost always wrong. Extend the snippet with more surrounding context to make it unique.
- Prefer the smallest safe snippet that is unlikely to change accidentally, but large enough to be unique in the file.
- 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.
- Encode special characters correctly for the handler used in
rebase.sh. See the encoding tables below.
Sed encoding (apply_changes)
Values go through: JSON parse → jq -r → escape_litteral → sed.
| Character in target | from encoding | by encoding |
|---|
| Newline | \\\n | \\\n |
| Tab | \\\t | \\\t |
& | literal | \\& |
* | \\* | literal |
$, [, ] | literal (escape_litteral handles) | literal |
" | \\\" | \\\" |
Common pitfall — & in sed by values: In sed replacement strings, & means "the entire matched text". Writing && in a by value produces the matched from text repeated twice instead of a literal &&. Always escape as \\&\\&. This applies to any & in by, not just &&.
Perl encoding (apply_changes_multi_line / apply_multi_line_replace)
Values go through: JSON parse → jq -r → env var → perl \Q\E (from) / literal (by).
| Character in target | from encoding | by encoding |
|---|
| Newline | \n | \n |
| Tab | \t | \t |
| Any special char | literal | literal |
Prefer multiline (perl) for new rules — simpler encoding, handles all cases, no & pitfall.
-
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.
-
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
---
-
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).
- Verify each
from appears exactly once in the upstream file. If it matches multiple times, the rule will silently replace all of them. Extend the from snippet with more context until it is unique.
- 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.
-
Verify completeness — no uncovered Che-specific changes
- For each file that was updated or created in
.rebase/replace/, simulate the full rule application:
- Start with the upstream file at
CURRENT_UPSTREAM_VERSION.
- Apply all rule entries from the JSON (not just the newly added ones) plus any custom inline replacements from
rebase.sh.
- Diff the result against the che-code working tree file.
- If the diff is empty → all Che changes are covered. Good.
- If there is a remaining diff → there are Che-specific changes in the working tree that are not covered by any rule. These changes would be silently lost during rebase.
- If the uncovered changes are from the same commit being processed, add additional rule entries for them.
- If the uncovered changes are pre-existing (from earlier commits), report them to the user as a warning: "Pre-existing Che-specific changes at lines X-Y have no rebase rule and would be lost during rebase."
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