Skip to content

Commit 1af6e82

Browse files
Merge branch 'master' into u/bvalverde/movePasteSourceToCorePackage
2 parents 74dd5dc + b4bfffa commit 1af6e82

84 files changed

Lines changed: 5122 additions & 421 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/skills/draft-pr/SKILL.md

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
---
2+
name: draft-pr
3+
description: Creates a pull request for the current branch, generating a clear title and a description that summarizes the changes and includes instructions on how to test them. Use when asked to open, draft, or create a PR.
4+
---
5+
6+
# Draft PR Skill
7+
8+
This skill creates a pull request for the current branch. It inspects the diff against `master`, generates a concise imperative title and a structured description (summary + how-to-test), and opens the PR with the `gh` CLI.
9+
10+
## Steps
11+
12+
### Step 1: Determine the current branch
13+
14+
```bash
15+
git branch --show-current
16+
```
17+
18+
If the current branch is `master` (or `release`), **stop** and tell the user to switch to a feature branch first — PRs should not be opened from `master`.
19+
20+
### Step 2: Inspect the changes
21+
22+
Gather the commits and the diff that this branch adds on top of `master`:
23+
24+
```bash
25+
git log master..HEAD --oneline
26+
git diff master...HEAD --stat
27+
git diff master...HEAD
28+
```
29+
30+
If there are **no commits/diff** versus `master`, stop and tell the user there is nothing to open a PR for.
31+
32+
Read the diff carefully so the title and description reflect what actually changed — not just the commit messages.
33+
34+
### Step 3: Make sure the branch is pushed
35+
36+
Check the upstream state:
37+
38+
```bash
39+
git status -sb
40+
```
41+
42+
If the branch has no upstream or has unpushed commits, push it:
43+
44+
```bash
45+
git push -u origin <branch_name>
46+
```
47+
48+
If there are **uncommitted changes**, stop and ask the user whether to commit them first — do not commit on their behalf without confirmation.
49+
50+
### Step 4: Check for an existing PR
51+
52+
```bash
53+
gh pr list --head <branch_name> --json number,title,url
54+
```
55+
56+
If a PR already exists, show its URL and ask the user whether to update it instead of creating a new one. Do not create a duplicate.
57+
58+
### Step 5: Write the title
59+
60+
Follow the repo's commit/PR conventions (see `AGENTS.md`):
61+
62+
- Concise, **imperative mood** ("Add", "Fix", "Remove", "Update").
63+
- Mention the surface area / feature when helpful (e.g. `[Table Improvements] ...`).
64+
- Reference a GitHub issue/PR number when relevant.
65+
66+
### Step 6: Write the description
67+
68+
Write the body to a temp file (avoids shell-escaping issues) using this template:
69+
70+
```markdown
71+
## Summary
72+
73+
<1-3 sentence explanation of WHAT changed and WHY. Reference the specific
74+
file(s)/function(s) and the behavior before vs. after when it clarifies intent.>
75+
76+
## How to test
77+
78+
1. <Exact command(s) to run the relevant tests, e.g.
79+
`yarn test:fast --testPathPattern=<regex>`>
80+
2. <Manual / integration steps when applicable: setup, action to trigger, and
81+
the expected result. Call out before-this-fix vs. after-this-fix behavior
82+
when it makes verification clearer.>
83+
```
84+
85+
Guidance for the **How to test** section:
86+
87+
- Always include the project test command: `yarn test:fast` (optionally scoped with `--testPathPattern=<regex>` or `--testNamePattern=<regex>`). Never suggest `yarn test` or `karma start`.
88+
- Prefer concrete, copy-pasteable steps over vague descriptions.
89+
- When the change is behavioral, describe how to observe the difference (e.g. "Before this fix: X. After this fix: Y.").
90+
91+
### Step 7: Create the PR
92+
93+
Use a heredoc to build the body file, then create the PR against `master`:
94+
95+
```bash
96+
cat > /tmp/draft_pr_body.md << 'EOF'
97+
<description from Step 6>
98+
EOF
99+
gh pr create --base master --head <branch_name> --title "<title>" --body-file /tmp/draft_pr_body.md
100+
```
101+
102+
If the user asked for a **draft** PR, add the `--draft` flag.
103+
104+
### Step 8: Show the PR link
105+
106+
Display the resulting PR URL to the user and a one-line recap of the title and how-to-test summary.
107+
108+
## Notes
109+
110+
- PRs target the `master` branch by default (per `AGENTS.md`). Only target another base if the user explicitly asks.
111+
- Keep the title and description grounded in the actual diff — do not invent changes or test steps that the code does not support.
112+
- If anything is ambiguous (e.g. which issue to reference, draft vs. ready), ask the user rather than guessing.

.claude/skills/hotfix/SKILL.md

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
---
2+
name: hotfix
3+
description: Proposes a scoped version bump for a roosterjs hotfix. Given one or more commits provided by the user, determines which packages had files changed by those commits, bumps the version only for the affected version groups, and creates a draft PR. Use when asked to do a hotfix, a scoped/targeted version bump, or to release only specific commits.
4+
---
5+
6+
# Hotfix Skill
7+
8+
This skill performs a **scoped** version bump for a roosterjs hotfix. Unlike the full `version-bump` skill (which bumps everything merged into `master` since the last release), this skill bumps the version **only for the packages whose files were changed by the specific commits the user provides**.
9+
10+
The user supplies the commits to hotfix. Each changed file is mapped to its package, each package to a version group (`main`, `legacyAdapter`, `react`), and **only the affected groups are bumped**.
11+
12+
## Inputs
13+
14+
The user must provide the **commits** to include in the hotfix. Accept any of:
15+
16+
- One or more commit hashes (e.g. `5142b51 e593ee8`)
17+
- A commit range (e.g. `abc123..def456`)
18+
- PR numbers (resolve to their merge/squash commit with `gh pr view <number> --json mergeCommit`)
19+
20+
If the user does **not** provide any commits, stop and ask which commits should be included in the hotfix before doing anything else.
21+
22+
## Version groups
23+
24+
The version groups live in `versions.json` and map to package sets defined in `tools/buildTools/common.js` (`buildConfig`). Use this mapping to translate changed files → group:
25+
26+
| Group | Packages |
27+
| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
28+
| `main` | roosterjs, roosterjs-content-model-types, roosterjs-content-model-dom, roosterjs-content-model-core, roosterjs-content-model-api, roosterjs-content-model-plugins, roosterjs-color-utils, roosterjs-content-model-markdown |
29+
| `legacyAdapter` | roosterjs-editor-adapter |
30+
| `react` | roosterjs-react |
31+
32+
Notes:
33+
34+
- A file path under `packages/<package-name>/` identifies the package; look up which group lists that package.
35+
- The legacy packages (`roosterjs-editor-*`, except `roosterjs-editor-adapter`) are **not** in `versions.json` and are not versioned by this skill. If a commit only touches legacy packages or non-package files (e.g. `tools/`, `demo/`, root configs), see Step 4.
36+
- Always re-read the group→package mapping from `tools/buildTools/common.js` in case packages were added or moved.
37+
38+
## Steps
39+
40+
### Step 1: Confirm the commits
41+
42+
Confirm the commits the user provided (see **Inputs**). If none were provided, stop and ask. Resolve PR numbers to commit hashes if needed. Verify each commit exists:
43+
44+
```bash
45+
git cat-file -t <commit>
46+
```
47+
48+
If any commit is invalid/unknown, stop and report it.
49+
50+
### Step 2: Check for uncommitted changes
51+
52+
Only **tracked** modifications (staged or unstaged edits to files git knows about) interfere with switching branches and cherry-picking. **Untracked** files (e.g. a new, not-yet-added skill folder or scratch files) do **not** interfere — do not block on them.
53+
54+
Check for blocking (tracked) changes only:
55+
56+
```bash
57+
git status --porcelain --untracked-files=no
58+
```
59+
60+
- If this produces output, **stop immediately** and ask the user to deal with their tracked uncommitted changes first.
61+
- If it is empty but `git status --porcelain` (with untracked) shows untracked files, mention them in one line and **continue** — they will be carried along untouched and excluded from the bump commit (which stages only `versions.json`). Note that `gh pr create` may print a harmless "uncommitted change" warning because of them.
62+
63+
### Step 3: Switch to release and pull latest
64+
65+
The hotfix branch is based on `release` (that is what ships).
66+
67+
```bash
68+
git checkout release
69+
git pull origin release
70+
```
71+
72+
If either command fails, stop and report the error.
73+
74+
**Then check whether each provided commit is already on `release`** — this is the common hotfix situation: the fix lives on `master` and must be cherry-picked onto `release`. Do **not** assume the commit is already there.
75+
76+
```bash
77+
git merge-base --is-ancestor <commit> release && echo "on release" || echo "NOT on release"
78+
```
79+
80+
- If a commit is **already on release**, it does not need cherry-picking (it will be released from `release` directly).
81+
- If a commit is **not on release**, it must be cherry-picked onto the hotfix branch in Step 5b. Note which commits need cherry-picking and confirm the plan with the user before proceeding (a single `AskUserQuestion` covering cherry-pick + bump level works well).
82+
83+
### Step 4: Determine the files changed by the provided commits
84+
85+
For each provided commit, list the files it changed. Combine across all commits (deduplicate):
86+
87+
```bash
88+
git show --name-only --pretty=format: <commit>
89+
```
90+
91+
For a range, use:
92+
93+
```bash
94+
git diff --name-only <from>..<to>
95+
```
96+
97+
Collect the full set of changed file paths.
98+
99+
**Map files to groups:**
100+
101+
1. For each changed path under `packages/<package-name>/...`, record `<package-name>`.
102+
2. Look up each package's group using the mapping in **Version groups** (re-confirm from `tools/buildTools/common.js`).
103+
3. The set of affected groups is the union across all changed files.
104+
105+
**Handle edge cases:**
106+
107+
- If **no package files** were changed (only `tools/`, `demo/`, root configs, docs, etc.), stop and tell the user: "The provided commits do not change any versioned package files, so no version bump is needed." List the changed files so they can confirm.
108+
- If commits only touch **legacy** packages (`roosterjs-editor-*` other than `roosterjs-editor-adapter`), tell the user those packages are not versioned via `versions.json` and ask how they want to proceed.
109+
110+
Show the user a summary before continuing:
111+
112+
```
113+
Affected packages and groups:
114+
- roosterjs-content-model-plugins → main
115+
- roosterjs-react → react
116+
Affected groups to bump: main, react
117+
```
118+
119+
### Step 5: Create a new branch based on release
120+
121+
Create a new branch from `release`. Use the naming convention `u/<username>/hotfix-<N>`, picking the next free N (check existing branches so you don't collide), or a name the user specifies:
122+
123+
```bash
124+
git branch --list 'u/<username>/hotfix-*' # see which N are taken
125+
git checkout -b <branch_name> release
126+
```
127+
128+
### Step 5b: Cherry-pick commits not on release
129+
130+
For each commit identified in Step 3 as **not on release** (in the order the user provided), cherry-pick it onto the new branch:
131+
132+
```bash
133+
git cherry-pick <commit>
134+
```
135+
136+
- If a cherry-pick conflicts, **stop**, show the conflicting files, and ask the user how to proceed (do not guess a resolution). Leave the repo clean if abandoning (`git cherry-pick --abort`).
137+
- Commits already on release are skipped here.
138+
139+
### Step 6: Determine the SemVer bump for each affected group
140+
141+
A hotfix is normally a **patch** bump (bug fixes, no public API changes). Determine the bump per affected group:
142+
143+
- **Patch** (0.0.x → 0.0.x+1): Bug fixes only, no public interface changes — the default for a hotfix.
144+
- **Minor** (0.x.0 → 0.x+1.0): New backward-compatible exports/APIs added.
145+
- **Major** (x.0.0 → x+1.0.0): Breaking changes to public interfaces.
146+
147+
To check whether more than a patch is warranted, inspect the commits' changes to each affected package's `lib/index.ts` barrel files and exported types/interfaces:
148+
149+
```bash
150+
git show <commit> -- 'packages/**/lib/index.ts'
151+
```
152+
153+
- New exports added → minor.
154+
- Changed/removed existing public signatures → major.
155+
- Implementation-only changes → patch.
156+
157+
**If a minor or major bump appears needed**, show the interface differences to the user and ask whether they want that bump or to keep it a patch. A hotfix is usually intended to stay a patch — confirm before doing anything larger.
158+
159+
Only bump the groups identified in Step 4. **Leave all other groups untouched.**
160+
161+
### Step 7: Update versions.json
162+
163+
Read the current versions from `versions.json` and apply the bump computed in Step 6 to **only** the affected groups. Do not change groups that were not affected.
164+
165+
### Step 8: Build and test
166+
167+
```bash
168+
yarn build
169+
yarn test:fast
170+
```
171+
172+
If **any errors** occur, show the full error output and **stop the flow**. Do not proceed with a broken build.
173+
174+
### Step 9: Commit the change
175+
176+
```bash
177+
git add versions.json
178+
git commit -m "Hotfix version bump <group>: <old_version> → <new_version>"
179+
```
180+
181+
List all changed groups/versions in the commit message.
182+
183+
### Step 10: Push the branch
184+
185+
```bash
186+
git push origin <branch_name>
187+
```
188+
189+
### Step 11: Create a draft PR
190+
191+
Create a draft PR targeting the `release` branch:
192+
193+
**Title:** `Hotfix version bump <group>: <old_version> → <new_version>` (list all affected groups)
194+
195+
**Description:** Include:
196+
197+
1. A table of old/new versions for the affected groups only:
198+
199+
```markdown
200+
| Group | Old Version | New Version |
201+
| ----- | ----------- | ----------- |
202+
| main | x.y.z | x.y.z+1 |
203+
| react | x.y.z | x.y.z+1 |
204+
```
205+
206+
2. The commits included in the hotfix and the packages they touched:
207+
208+
```markdown
209+
## Hotfix commits
210+
211+
- <short_hash> <commit_subject>
212+
213+
## Affected packages
214+
215+
- roosterjs-content-model-plugins → main
216+
- roosterjs-react → react
217+
```
218+
219+
Command:
220+
221+
```bash
222+
gh pr create --draft --base release --title "<title>" --body "<description>"
223+
```
224+
225+
### Step 12: Show the PR link
226+
227+
```
228+
✅ Hotfix version bump PR created successfully!
229+
PR: https://github.com/microsoft/roosterjs/pull/<number>
230+
Affected groups: <list>
231+
```
232+
233+
## Error Handling
234+
235+
- If no commits are provided, stop and ask the user which commits to hotfix.
236+
- If any provided commit is invalid, stop and report it.
237+
- If the commits change no versioned package files, stop — no bump needed.
238+
- If any git operation fails, show the error and stop.
239+
- If build/test fails, show errors and stop.
240+
- If a minor/major bump appears needed, confirm with the user before applying (hotfixes default to patch).
241+
- Only ever bump groups affected by the provided commits; never touch unaffected groups.
242+
- Always leave the repo in a clean state if stopping early.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { changeCapitalization } from 'roosterjs-content-model-api';
2+
import type { RibbonButton } from 'roosterjs-react';
3+
4+
const changeCapitalizationButtonKey = 'buttonNameChangeCapitalization';
5+
6+
const CAPITALIZATION_OPTIONS: Record<
7+
'sentence' | 'lowerCase' | 'upperCase' | 'capitalize',
8+
string
9+
> = {
10+
sentence: 'Sentence case',
11+
lowerCase: 'lowercase',
12+
upperCase: 'UPPERCASE',
13+
capitalize: 'Capitalize Each Word',
14+
};
15+
16+
/**
17+
* @internal
18+
* "Change capitalization" button on the format ribbon
19+
*/
20+
export const changeCapitalizationButton: RibbonButton<typeof changeCapitalizationButtonKey> = {
21+
key: changeCapitalizationButtonKey,
22+
unlocalizedText: 'Change capitalization',
23+
iconName: 'FontColorA',
24+
dropDownMenu: {
25+
items: CAPITALIZATION_OPTIONS,
26+
},
27+
onClick: (editor, key) => {
28+
changeCapitalization(editor, key as 'sentence' | 'lowerCase' | 'upperCase' | 'capitalize');
29+
},
30+
};

0 commit comments

Comments
 (0)