You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: .claude/skills/release-manager/SKILL.md
+24-6Lines changed: 24 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -97,9 +97,7 @@ git show origin/release/v<curr>:pnpm-workspace.yaml # vitest/oxl
97
97
### Structure
98
98
99
99
```markdown
100
-
Release vite-plus vX.Y.Z: <theme>.
101
-
102
-
<One or two sentences on the release theme. When a blog post accompanies the release, read it first (via its preview URL if not yet deployed), align the theme with it, and link the final URL here even if that URL is not live yet.>
100
+
<One or two sentences on the release theme. Do not repeat the PR title as an opener line; GitHub renders the title directly above the body, and step 8 would only strip it again. When a blog post accompanies the release, read it first (via its preview URL if not yet deployed), align the theme with it, and link the final URL here even if that URL is not live yet.>
103
101
104
102
### Breaking Changes
105
103
@@ -135,6 +133,9 @@ Merging this PR will trigger the release workflow.
135
133
-**Describe the net change between the two released versions, not intra-cycle churn.** When several PRs touch the same area within one release (one narrows a behavior, a later one broadens it back), the reader only sees the delta from `v<prev>` to `v<curr>`; describe that once, listing every PR number, and do not narrate a regression that was introduced and then fixed inside the cycle. Apply this to the intro/theme sentence too.
-`feat(docs)` goes in Docs when the user-facing surface is the docs site.
136
+
-**Docs means the published docs site, not contributor files.** A `docs` commit that changes an RFC, `AGENTS.md`, the repo map, or a skill under `.claude/` belongs in Chore: a vite-plus user never reads those. Docs should hold only entries a reader could go and look at on the site or in the README.
137
+
-**Describe behaviour, not resolution logic.** An entry states what a user now observes. Rules the implementation follows internally (target-selection signals, config precedence, detection order) belong in the RFC or the PR, not the changelog. If an entry needs a nested list to explain how a decision is reached, cut it down to the outcome.
138
+
-**A breaking change needs its migration path.** State what existing installs or projects do by default, then how to move to the new behaviour deliberately, then what that costs. Link the guide rather than restating it, and say plainly when doing nothing is a valid choice.
138
139
- Highlights: 3-5 changes a vite-plus user will notice (new capabilities, security, major fixes). Skip developer-tooling-only conveniences. Each highlight ends with `, by @<author>`, same as every other entry.
139
140
- Entry format: `Description ([#N](https://github.com/voidzero-dev/vite-plus/pull/N)), by @author`. Describe the user-visible behavior, not the implementation. Group supporting implementation PRs under the user-visible change they enable instead of giving them separate entries. Never include defensive edge cases or internal mechanics unless users need them to use or understand the feature; use concrete behavior instead of internal UI taxonomy that needs extra context.
140
141
-**Upstream dependency upgrade PRs** (`feat(deps): upgrade upstream dependencies`): consolidate all of them into one Features entry with net oldest-to-latest version changes (e.g. `vite 8.0.16 -> 8.1.2`), listing every PR number. Check the upgraded range for security fixes (search the upstream changelog for CVE/GHSA); if present, add a dedicated security entry quoting severity and linking the advisory. When oxfmt or oxlint changed version, add one clause telling users the new versions can flag code that passed before, so they should run `vp fmt` after upgrading if their CI runs `vp check`; in ecosystem testing this is reliably the largest single class of post-upgrade CI failures.
@@ -346,10 +347,27 @@ Merging the release PR is the release trigger. Before merging confirm: CI green,
346
347
5.`publish-docker`: multi-arch toolchain image to `ghcr.io/voidzero-dev/vite-plus`, after npm publish (the image installs vp from npm).
347
348
6.`discord-notify`: announces to Discord with a link to the release.
348
349
350
+
**A green `Release` job does not mean the packages are installable.**`pnpm publish` prints `✅ Published package <name>@X.Y.Z` as soon as the registry accepts the request, and the registry can then take tens of minutes to actually serve that version. This has shipped a broken release: `vite-plus@X.Y.Z` went live on `latest` with an exact dependency on `@voidzero-dev/vite-plus-core@X.Y.Z` that was invisible for about 35 minutes, so every `npm install vite-plus` failed with `ETARGET` and both `publish-docker` and `Deploy docs` failed on `ERR_PNPM_NO_MATCHING_VERSION`. The downstream job failures are the symptom, not the cause; do not re-run them until the registry has the package.
351
+
352
+
Check visibility directly, not through `npm view`, which caches:
python3 -c "import json,sys;d=json.load(sys.stdin);print('$pkg', d['dist-tags'].get('latest'), 'X.Y.Z' in d['versions'])"
358
+
done
359
+
```
360
+
361
+
Both must report `True` before you trust the release. A stale `modified` timestamp on the packument is the giveaway that nothing landed. If `vite-plus` is visible and `core` is not, the release is broken **right now** for every new install: tell the release manager immediately and offer to move the tag back (`npm dist-tag add vite-plus@<prev> latest`) while the publish is sorted out. Confirm the fix with a real install in a temp directory, not just a registry read:
1.**Polish the GitHub release notes** (ask first): the auto-created release body has only Published Packages and Installation. Build the polished notes from the final release PR body:
352
-
- Drop the `Release vite-plus vX.Y.Z: ...` opener line (the release title carries it) and the closing `---` / `Merging this PR ...` boilerplate.
370
+
- Drop the closing `---` / `Merging this PR ...` boilerplate.
353
371
- Keep every changelog section through **Full Changelog** unchanged.
354
372
- Append the generated Published Packages and Installation sections, and end Installation with a Docker usage block (keep the explanation to one short sentence):
355
373
@@ -432,7 +450,7 @@ Merging the release PR is the release trigger. Before merging confirm: CI green,
432
450
433
451
The release-notes URL stays in `<angle brackets>` to suppress the embed; a blog post link (if any) goes bare so it unfurls. Lead the header with the server custom emoji `:viteplus:` (before the bold title, since it is a custom emoji). Link contributors as `[@user](https://github.com/user)` because Discord does not auto-link a bare GitHub handle. Keep the whole message user-facing: exclude vite-plus's own tooling/CI work.
434
452
435
-
Never post to Discord yourself. Save the draft to a file, update that file after every requested revision, and post the approved contents as a comment on the release PR wrapped in a fenced ````markdown ` block, so the `@mentions`do not ping anyone on GitHub, the emoji shortcodes stay literal, and any team member can copy-paste it into Discord. After the release manager approves the Discord draft, proceed directly to step 9;do not waitfor another prompt or treat the skill update as optional.
453
+
Never post to Discord yourself. Save the draft to a file, update that file after every requested revision, and hand the approved contents over in chat. Do **not** post it as a comment on the release PR: that PR is a code-review artifact, and an announcement draft there is noise for reviewers and a second copy that can drift from the approved wording. After the release manager approves the Discord draft, proceed directly to step 9;do not waitfor another prompt or treat the skill update as optional.
436
454
437
455
## 9. Update this skill (post-release)
438
456
@@ -453,5 +471,5 @@ After the release ships and the Discord announcement draft is approved, review t
453
471
- [ ] Release PR merged;`release` environment approved by someone other than the merger; npm + GitHub release + Docker image all published
454
472
- [ ] GitHub release notes polished (release manager approved before applying), retitled, and validated; Installation ends with the Docker usage block
skip-platforms = [{ os = "linux", libc = "musl" }]
5
+
steps = [
6
+
{ argv = [
7
+
"vp",
8
+
"lint",
9
+
"src/uses-foo.ts",
10
+
], comment = "the local JS plugin imports its API from vite-plus/lint/plugins. It declares no @oxlint/plugins dependency. A reported diagnostic therefore proves the export resolved and loaded", continue-on-failure = true },
11
+
{ argv = [
12
+
"vp",
13
+
"lint",
14
+
"src/legacy-imports.ts",
15
+
], comment = "prefer-vite-plus-imports reports the three legacy authoring specifiers", continue-on-failure = true },
16
+
{ argv = [
17
+
"vp",
18
+
"lint",
19
+
"src/config-surface.ts",
20
+
], comment = "oxlint still owns defineConfig and OxlintOverride, so these are clean", continue-on-failure = true },
21
+
{ argv = [
22
+
"vp",
23
+
"lint",
24
+
"--fix",
25
+
"src/legacy-imports.ts",
26
+
], comment = "the autofix matches what vp migrate rewrites", continue-on-failure = true },
27
+
{ argv = [
28
+
"vpt",
29
+
"print-file",
30
+
"src/legacy-imports.ts",
31
+
], continue-on-failure = true },
32
+
{ argv = [
33
+
"vp",
34
+
"lint",
35
+
"src/legacy-imports.ts",
36
+
], comment = "confirm the rewritten file is clean", continue-on-failure = true },
the local JS plugin imports its API from vite-plus/lint/plugins. It declares no @oxlint/plugins dependency. A reported diagnostic therefore proves the export resolved and loaded
6
+
7
+
**Exit code:** 1
8
+
9
+
```
10
+
11
+
× local(no-foo): Do not name things "foo".
12
+
╭─[src/uses-foo.ts:1:14]
13
+
1 │ export const foo = 1;
14
+
· ───
15
+
2 │ export const bar = 2;
16
+
╰────
17
+
18
+
Found 0 warnings and 1 error.
19
+
Finished in <duration> on 1 file with <n> rules using <n> threads.
20
+
```
21
+
22
+
## `vp lint src/legacy-imports.ts`
23
+
24
+
prefer-vite-plus-imports reports the three legacy authoring specifiers
25
+
26
+
**Exit code:** 1
27
+
28
+
```
29
+
30
+
× vite-plus(prefer-vite-plus-imports): Use 'vite-plus/lint/plugins' instead of 'oxlint' in Vite+ projects.
31
+
╭─[src/legacy-imports.ts:1:28]
32
+
1 │ import { defineRule } from 'oxlint';
33
+
· ────────
34
+
2 │ import { definePlugin } from '@oxlint/plugins';
35
+
╰────
36
+
37
+
× vite-plus(prefer-vite-plus-imports): Use 'vite-plus/lint/plugins' instead of '@oxlint/plugins' in Vite+ projects.
38
+
╭─[src/legacy-imports.ts:2:30]
39
+
1 │ import { defineRule } from 'oxlint';
40
+
2 │ import { definePlugin } from '@oxlint/plugins';
41
+
· ─────────────────
42
+
3 │ import { RuleTester } from 'oxlint/plugins-dev';
43
+
╰────
44
+
45
+
× vite-plus(prefer-vite-plus-imports): Use 'vite-plus/lint/plugins-dev' instead of 'oxlint/plugins-dev' in Vite+ projects.
46
+
╭─[src/legacy-imports.ts:3:28]
47
+
2 │ import { definePlugin } from '@oxlint/plugins';
48
+
3 │ import { RuleTester } from 'oxlint/plugins-dev';
49
+
· ────────────────────
50
+
4 │
51
+
╰────
52
+
53
+
× vite-plus(prefer-vite-plus-imports): Use 'vite-plus/lint/plugins' instead of 'oxlint' in Vite+ projects.
0 commit comments