diff --git a/.claude/skills/release-catalyst/SKILL.md b/.claude/skills/release-catalyst/SKILL.md index 3455cab52c..daabca03f4 100644 --- a/.claude/skills/release-catalyst/SKILL.md +++ b/.claude/skills/release-catalyst/SKILL.md @@ -54,7 +54,7 @@ Record the **version number** and **bump type** (patch/minor/major) for use in S ### 2a. Sync branches -Invoke the `/sync-makeswift` skill, with one addition: during the sync (after merge, before pushing), also add a changeset for `@bigcommerce/catalyst-makeswift`: +Invoke the `/sync-integration-branch` skill with target `integrations/makeswift`, with one addition: during the sync (after merge, before pushing), also add a changeset for `@bigcommerce/catalyst-makeswift`: **Determine bump type**: Match the bump type from Stage 1 (e.g., if core went `1.4.2` → `1.5.0`, that's a `minor`). diff --git a/.claude/skills/sync-integration-branch/SKILL.md b/.claude/skills/sync-integration-branch/SKILL.md new file mode 100644 index 0000000000..9235cc20c0 --- /dev/null +++ b/.claude/skills/sync-integration-branch/SKILL.md @@ -0,0 +1,133 @@ +--- +name: sync-integration-branch +description: > + Sync a Catalyst integration branch (`integrations/*`) with its upstream branch in the monorepo. + Use when the user says "/sync-integration-branch", "sync makeswift", "sync integrations/makeswift", + "sync b2b-makeswift", "sync integrations/b2b-makeswift", or asks to bring an `integrations/*` branch + up to date with its upstream. The target integration branch is passed as the argument. +--- + +# Sync an integration branch with its upstream + +Catalyst maintains a chain of integration branches, each layered on the one before it. `canary` is the root; every `integrations/*` branch mirrors an upstream branch and adds its own integration code on top. This skill syncs one **target** integration branch with its **upstream**, while defending the target's package identity, its release wiring, and its integration-specific code. + +The generic flow lives below. Everything branch-specific (upstream, package identity, integration surface, and any branch-only caveats) lives in a per-branch **reference file** that Phase 0 loads once the target is resolved. + +## Supported branches + +| Target branch | Reference | +|---|---| +| `integrations/makeswift` | `references/makeswift.md` | +| `integrations/b2b-makeswift` | `references/b2b-makeswift.md` | + +**Sync top-down.** When several branches need syncing, do the upstream first (`integrations/makeswift` before `integrations/b2b-makeswift`) so a branch never trails its upstream by more than one release. + +## Phase 0: Resolve the target branch and load its reference + +The skill argument is the target integration branch. Accept either the full ref (`integrations/b2b-makeswift`) or a shorthand (`b2b-makeswift`, `makeswift`). + +1. If **no argument** was given, list the Supported branches above and ask the user which one to sync. **Stop** and wait. +2. Normalize the argument to a full ref (prepend `integrations/` if a shorthand omitted it). +3. Validate the resolved branch is **both** in the Supported branches table **and** present on origin: + + ```bash + git fetch origin + git ls-remote --heads origin + ``` + + If the branch is not in the table, or `git ls-remote` prints nothing, report that it is not a valid integration branch, list the supported `integrations/*` targets, and ask the user to pick a valid one. **Stop.** +4. **Read the matching `references/.md`** for the resolved target and hold its values for the rest of the run: **upstream**, **package identity**, **sync branch**, **merge-base pair**, **integration surface**, and any **branch-specific notes**. The placeholders below (``, ``, ``, ``) are filled from that file. + +## Phase 1: Prepare and merge + +```bash +git checkout -B origin/ +git merge origin/ +``` + +If the merge completes cleanly, skip to changeset cleanup. Otherwise, resolve conflicts. + +### Conflict resolution rules + +Keep the target branch's identity, its release-wiring overrides, and its integration surface; take the upstream's structure for everything else. Never let an upstream value overwrite one of these — in particular, a package-name regression would republish over the upstream's package. + +- **`core/package.json` name/version** — the `name` field MUST stay ``. The `version` field MUST stay at the latest published `` version (check what's on `origin/`, not `origin/`). +- **`core/package.json` nested `catalyst.version`/`catalyst.ref`** — check these even when they don't show up as a textual conflict. They must mirror the top-level `name`/`version` on this branch (e.g. `"version": "1.9.0"` → `catalyst.ref: "@1.9.0"`), matching what the automated "Version Packages (``)" bump sets them to. Because this is a small, self-contained hunk, git often merges it cleanly by taking the upstream's raw value without flagging a conflict — check it by hand every time: + + ```bash + grep -A3 '"catalyst"' core/package.json + ``` + +- **`core/CHANGELOG.md`** — the latest release entry MUST match the latest published `` version. +- **`.changeset/config.json`** — keep `baseBranch` pointed at `` (never let the upstream's `baseBranch` win) and keep the branch's own `ignore` list. +- **`.github/workflows/prevent-invalid-changesets.yml` + `.github/scripts/prevent-invalid-changesets.js`** — keep them targeting `` and allowing only ``. Never let the upstream's target/package win. +- **`.github/workflows/changesets-release.yml`** — shared, ref-driven infrastructure (per-branch behavior is keyed on `github.ref_name`), so take the upstream's copy as-is; no per-branch edit is needed here. +- **`pnpm-lock.yaml`** — accept the upstream's version (`git checkout --theirs pnpm-lock.yaml`), then regenerate with `pnpm install --no-frozen-lockfile`. +- **Integration surface** — preserve the target's integration surface (from its reference file) wholesale. +- Apply any **branch-specific rules** called out in the loaded reference file. +- For all other conflicts, prefer the upstream's structure/patterns while preserving the integration surface above. + +After resolving all conflicts, stage everything and verify no unresolved conflicts remain: + +```bash +git add +git diff --name-only --diff-filter=U # should return empty +``` + +### Changeset cleanup + +Remove any `.changeset/*.md` files that do NOT target ``. Read each changeset file and delete any that reference other packages (`@bigcommerce/catalyst-core`, the upstream package, etc.). Amend the removals into the merge commit. (The `prevent-invalid-changesets` GitHub Action enforces this on the PR.) + +### Commit the merge + +```bash +git commit --no-edit +``` + +If changesets were removed after the initial commit, amend them in (`git commit --amend --no-edit`) rather than creating a separate commit. + +## Phase 2: Push and open PR + +```bash +git push origin +``` + +Open a PR into `` (never into the upstream or `canary`): + +- Title: `sync \`\` with \`\`` +- Body: summarize what came from the upstream, list conflict resolutions, and include this notice: + +> **Do not squash or rebase-and-merge this PR.** Use a true merge commit or rebase locally to preserve the merge base between `` and ``. + +**Stop here.** Tell the user the PR is ready for review and wait for them to confirm approval before continuing. + +## Phase 3: Rebase and push (after PR approval) + +```bash +git fetch origin +git checkout -B origin/ +git rebase +git push origin --force-with-lease +``` + +This closes the PR automatically. Confirm with the user that the push succeeded and the PR closed. + +## Phase 4: Cleanup + +Switch back to `canary` and delete the local branches that are no longer needed: + +```bash +git checkout canary +git pull +git branch -D +``` + +## One-time catch-up (large version gaps) + +When a target branch is many releases behind its upstream (e.g. reviving a stalled branch), do NOT merge `origin/` in one shot. Instead merge the upstream package's published version tags one at a time — **minor tags only** (e.g. `@bigcommerce/catalyst-makeswift@1.7.0` → `@1.8.0` → `@1.9.0`); skip the intervening patch releases, since each minor tag already contains them: + +```bash +git merge @ +``` + +Apply the same conflict rules at each step so a broken step is bisectable to a single minor. Once caught up, resume steady-state syncs that merge `origin/` directly. diff --git a/.claude/skills/sync-integration-branch/references/b2b-makeswift.md b/.claude/skills/sync-integration-branch/references/b2b-makeswift.md new file mode 100644 index 0000000000..7d5a3e7364 --- /dev/null +++ b/.claude/skills/sync-integration-branch/references/b2b-makeswift.md @@ -0,0 +1,28 @@ +# Reference: `integrations/b2b-makeswift` + +Load this when the sync target is `integrations/b2b-makeswift`. Fill the SKILL.md placeholders with: + +- **Upstream (merge from):** `integrations/makeswift` +- **Package identity:** `@bigcommerce/catalyst-b2b-makeswift` +- **Sync branch:** `sync-integrations-b2b-makeswift` +- **Merge-base pair:** `integrations/makeswift` ↔ `integrations/b2b-makeswift` +- **Upstream package (for one-time catch-up tags):** `@bigcommerce/catalyst-makeswift` + +## Integration surface (preserve wholesale) + +The B2B Edition + Buyer Portal surface layered over `integrations/makeswift`: + +- `core/b2b/*` +- `core/middlewares/with-b2b.ts` and the `withB2B` wiring in `core/middleware.ts` +- `core/next.config.ts` (B2B hooks) +- the `app/[locale]/**/layout.tsx` files (the `B2BLoader`) +- `core/auth/index.ts` + `core/auth/types.ts` (B2B token fields) +- the register `route.ts` +- the cart "add to quote" + PDP quote vibes components +- the B2B keys in `core/messages/en.json` + +## Branch-specific notes + +- b2b-makeswift builds on `integrations/makeswift`, so it syncs from there (**not** `canary` directly). Run this **after** syncing `integrations/makeswift`. +- **Never** let the upstream's `@bigcommerce/catalyst-makeswift` name win in `core/package.json`. Unlike a plain mispublish, regressing this name would republish over the **real, in-use Makeswift package**. +- **Currently in one-time catch-up.** b2b-makeswift trails makeswift by several minors. Follow the "One-time catch-up" section in SKILL.md: merge `@bigcommerce/catalyst-makeswift` **minor** tags one at a time (`@1.7.0` → `@1.8.0` → `@1.9.0`) until level, then resume steady-state syncs that merge `origin/integrations/makeswift` directly. diff --git a/.claude/skills/sync-integration-branch/references/makeswift.md b/.claude/skills/sync-integration-branch/references/makeswift.md new file mode 100644 index 0000000000..0d27eec8f3 --- /dev/null +++ b/.claude/skills/sync-integration-branch/references/makeswift.md @@ -0,0 +1,18 @@ +# Reference: `integrations/makeswift` + +Load this when the sync target is `integrations/makeswift`. Fill the SKILL.md placeholders with: + +- **Upstream (merge from):** `canary` +- **Package identity:** `@bigcommerce/catalyst-makeswift` +- **Sync branch:** `sync-integrations-makeswift` +- **Merge-base pair:** `canary` ↔ `integrations/makeswift` +- **Upstream package (for one-time catch-up tags):** `@bigcommerce/catalyst-core` + +## Integration surface (preserve wholesale) + +The Makeswift additions layered over `canary`: Makeswift components, builder/runtime registration, and Makeswift config (imports, components, config). Prefer canary's structure everywhere else. + +## Branch-specific notes + +- This is the **root** integration branch — it syncs directly from `canary`. Sync it before any branch that builds on it (e.g. `integrations/b2b-makeswift`). +- Steady state: this branch tracks `canary` closely, so syncs are usually small and the one-time catch-up flow does not apply. diff --git a/.claude/skills/sync-makeswift/SKILL.md b/.claude/skills/sync-makeswift/SKILL.md deleted file mode 100644 index 3ff9d91a13..0000000000 --- a/.claude/skills/sync-makeswift/SKILL.md +++ /dev/null @@ -1,89 +0,0 @@ ---- -name: sync-makeswift -description: > - Sync the `integrations/makeswift` branch with `canary` in the Catalyst monorepo. - Use when the user says "/sync-makeswift", "sync makeswift", "sync integrations/makeswift", - or asks to bring `integrations/makeswift` up to date with `canary`. ---- - -# Sync `integrations/makeswift` with `canary` - -Execute the following phases in order. Pause for user input where indicated. - -## Phase 1: Prepare and merge - -```bash -git fetch origin -git checkout -B sync-integrations-makeswift origin/integrations/makeswift -git merge origin/canary -``` - -If the merge completes cleanly, skip to changeset cleanup. Otherwise, resolve conflicts. - -### Conflict resolution rules - -- `core/package.json`: the `name` field MUST stay `@bigcommerce/catalyst-makeswift`. The `version` field MUST stay at the latest published `@bigcommerce/catalyst-makeswift` version (check what's on `origin/integrations/makeswift`, not `canary`). -- `core/CHANGELOG.md`: the latest release entry MUST match the latest published `@bigcommerce/catalyst-makeswift` version. -- `pnpm-lock.yaml`: accept canary's version (`git checkout --theirs pnpm-lock.yaml`), then regenerate with `pnpm install --no-frozen-lockfile`. -- For all other conflicts, prefer canary's structure/patterns while preserving makeswift-specific additions (imports, components, config). - -**Check `core/package.json`'s nested `catalyst.version`/`catalyst.ref` fields even when they don't show up as a textual conflict.** These must always mirror the top-level `name`/`version` on this branch (e.g. `"version": "1.9.0"` → `catalyst.ref: "@bigcommerce/catalyst-makeswift@1.9.0"`), matching what the automated "Version Packages (`integrations/makeswift`)" bump sets them to. Because this is a small, self-contained hunk, git often merges it cleanly by taking canary's raw value (`@bigcommerce/catalyst-core@`) without flagging a conflict — check it by hand every time: - -```bash -grep -A3 '"catalyst"' core/package.json -``` - -After resolving all conflicts, stage everything and verify no unresolved conflicts remain: - -```bash -git add -git diff --name-only --diff-filter=U # should return empty -``` - -### Changeset cleanup - -Remove any `.changeset/*.md` files that do NOT target `@bigcommerce/catalyst-makeswift`. Read each changeset file and delete any that reference `@bigcommerce/catalyst-core` or other packages. Amend the removals into the merge commit. - -### Commit the merge - -```bash -git commit --no-edit -``` - -If changesets were removed after the initial commit, amend them in (`git commit --amend --no-edit`) rather than creating a separate commit. - -## Phase 2: Push and open PR - -```bash -git push origin sync-integrations-makeswift -``` - -Open a PR into `integrations/makeswift` (not `canary`): - -- Title: `sync \`integrations/makeswift\` with \`canary\`` -- Body: summarize what came from canary, list conflict resolutions, and include this notice: - -> **Do not squash or rebase-and-merge this PR.** Use a true merge commit or rebase locally to preserve the merge base between `canary` and `integrations/makeswift`. - -**Stop here.** Tell the user the PR is ready for review and wait for them to confirm approval before continuing. - -## Phase 3: Rebase and push (after PR approval) - -```bash -git fetch origin -git checkout -B integrations/makeswift origin/integrations/makeswift -git rebase sync-integrations-makeswift -git push origin integrations/makeswift --force-with-lease -``` - -This closes the PR automatically. Confirm with the user that the push succeeded and the PR closed. - -## Phase 4: Cleanup - -Switch back to `canary` and delete the local branches that are no longer needed: - -```bash -git checkout canary -git pull -git branch -D sync-integrations-makeswift integrations/makeswift -```