sequant 2.6.2 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +13 -1
- package/dist/bin/cli.d.ts +1 -1
- package/dist/bin/cli.js +11 -1
- package/dist/bin/preflight.d.ts +21 -0
- package/dist/bin/preflight.js +45 -0
- package/dist/marketplace/external_plugins/sequant/.claude-plugin/plugin.json +1 -1
- package/dist/marketplace/external_plugins/sequant/skills/_shared/references/force-push.md +34 -0
- package/dist/marketplace/external_plugins/sequant/skills/assess/SKILL.md +24 -7
- package/dist/marketplace/external_plugins/sequant/skills/exec/SKILL.md +29 -0
- package/dist/marketplace/external_plugins/sequant/skills/loop/SKILL.md +100 -2
- package/dist/marketplace/external_plugins/sequant/skills/qa/SKILL.md +24 -0
- package/dist/marketplace/external_plugins/sequant/skills/qa/references/anti-pattern-detection.md +285 -0
- package/dist/marketplace/external_plugins/sequant/skills/qa/references/call-site-review.md +202 -0
- package/dist/marketplace/external_plugins/sequant/skills/qa/references/quality-gates.md +287 -0
- package/dist/marketplace/external_plugins/sequant/skills/qa/references/test-quality-checklist.md +272 -0
- package/dist/marketplace/external_plugins/sequant/skills/qa/references/testing-requirements.md +40 -0
- package/dist/marketplace/external_plugins/sequant/skills/qa/scripts/quality-checks.sh +95 -11
- package/dist/marketplace/external_plugins/sequant/skills/references/shared/framework-gotchas.md +186 -0
- package/dist/marketplace/external_plugins/sequant/skills/release/SKILL.md +661 -0
- package/dist/marketplace/external_plugins/sequant/skills/test/references/browser-testing-patterns.md +423 -0
- package/dist/marketplace/external_plugins/sequant/skills/upstream/SKILL.md +419 -0
- package/dist/src/commands/sync.d.ts +1 -0
- package/dist/src/commands/sync.js +56 -1
- package/dist/src/commands/update.js +7 -0
- package/dist/src/lib/errors.d.ts +85 -0
- package/dist/src/lib/errors.js +111 -0
- package/dist/src/lib/version-check.d.ts +19 -0
- package/dist/src/lib/version-check.js +44 -0
- package/dist/src/lib/workflow/batch-executor.js +61 -6
- package/dist/src/lib/workflow/drivers/agent-driver.d.ts +17 -0
- package/dist/src/lib/workflow/drivers/claude-code.d.ts +22 -0
- package/dist/src/lib/workflow/drivers/claude-code.js +111 -7
- package/dist/src/lib/workflow/log-writer.d.ts +1 -1
- package/dist/src/lib/workflow/phase-executor.d.ts +18 -0
- package/dist/src/lib/workflow/phase-executor.js +76 -14
- package/dist/src/lib/workflow/run-log-schema.d.ts +3 -0
- package/dist/src/lib/workflow/run-log-schema.js +7 -0
- package/dist/src/lib/workflow/state-manager.d.ts +1 -0
- package/dist/src/lib/workflow/state-manager.js +6 -0
- package/dist/src/lib/workflow/state-schema.d.ts +3 -0
- package/dist/src/lib/workflow/state-schema.js +7 -0
- package/dist/src/lib/workflow/types.d.ts +17 -0
- package/dist/src/ui/tui/theme.d.ts +18 -4
- package/dist/src/ui/tui/theme.js +18 -4
- package/package.json +4 -3
- package/templates/skills/_shared/references/force-push.md +34 -0
- package/templates/skills/assess/SKILL.md +24 -7
- package/templates/skills/exec/SKILL.md +29 -0
- package/templates/skills/loop/SKILL.md +100 -2
- package/templates/skills/qa/SKILL.md +24 -0
- package/templates/skills/qa/references/anti-pattern-detection.md +285 -0
- package/templates/skills/qa/references/call-site-review.md +202 -0
- package/templates/skills/qa/references/quality-gates.md +287 -0
- package/templates/skills/qa/references/test-quality-checklist.md +272 -0
- package/templates/skills/qa/references/testing-requirements.md +40 -0
- package/templates/skills/qa/scripts/quality-checks.sh +95 -11
- package/templates/skills/references/shared/framework-gotchas.md +186 -0
- package/templates/skills/release/SKILL.md +661 -0
- package/templates/skills/test/references/browser-testing-patterns.md +423 -0
- package/templates/skills/upstream/SKILL.md +419 -0
|
@@ -0,0 +1,661 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: release
|
|
3
|
+
description: "Automates the full release workflow: version bump, git tag, GitHub release, and npm publish."
|
|
4
|
+
license: MIT
|
|
5
|
+
metadata:
|
|
6
|
+
author: sequant
|
|
7
|
+
version: "1.0"
|
|
8
|
+
allowed-tools:
|
|
9
|
+
- Read
|
|
10
|
+
- Bash(npm test:*)
|
|
11
|
+
- Bash(npm run build:*)
|
|
12
|
+
- Bash(npm version:*)
|
|
13
|
+
- Bash(npm pack:*)
|
|
14
|
+
- Bash(npm publish:*)
|
|
15
|
+
- Bash(npm whoami:*)
|
|
16
|
+
- Bash(npm view:*)
|
|
17
|
+
- Bash(npm audit:*)
|
|
18
|
+
- Bash(git status:*)
|
|
19
|
+
- Bash(git branch:*)
|
|
20
|
+
- Bash(git fetch:*)
|
|
21
|
+
- Bash(git log:*)
|
|
22
|
+
- Bash(git add:*)
|
|
23
|
+
- Bash(git commit:*)
|
|
24
|
+
- Bash(git tag:*)
|
|
25
|
+
- Bash(git push:*)
|
|
26
|
+
- Bash(gh auth status:*)
|
|
27
|
+
- Bash(gh release create:*)
|
|
28
|
+
- Bash(gh release view:*)
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
<!-- sequant:local-override -->
|
|
32
|
+
> **Local overrides (read this first).** Before following any instruction below, check whether `.claude/.local/skills/release/overrides.md` exists. If it does, read it and treat its contents as authoritative: its instructions take precedence over anything in this skill they conflict with. This is the supported way to tailor `/release` without forking it — `overrides.md` lives under `.claude/.local/`, which `sequant update` and `sync` never overwrite.
|
|
33
|
+
|
|
34
|
+
# Release Skill
|
|
35
|
+
|
|
36
|
+
Automates the full release workflow: version bump, git tag, GitHub release, and npm publish.
|
|
37
|
+
|
|
38
|
+
## Usage
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
/release [patch|minor|major] [--prerelease <tag>] [--dry-run]
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
- `/release` - Interactive, asks for version type
|
|
45
|
+
- `/release patch` - Patch release (1.3.1 → 1.3.2)
|
|
46
|
+
- `/release minor` - Minor release (1.3.1 → 1.4.0)
|
|
47
|
+
- `/release major` - Major release (1.3.1 → 2.0.0)
|
|
48
|
+
- `/release minor --prerelease beta` - Pre-release (1.3.1 → 1.4.0-beta.0)
|
|
49
|
+
- `/release --dry-run` - Preview without publishing
|
|
50
|
+
|
|
51
|
+
## Pre-flight Checks
|
|
52
|
+
|
|
53
|
+
Run ALL checks before proceeding. **STOP if any fails.**
|
|
54
|
+
|
|
55
|
+
### Git Checks
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
# 1. On main branch
|
|
59
|
+
[ "$(git branch --show-current)" = "main" ] || { echo "Not on main"; exit 1; }
|
|
60
|
+
|
|
61
|
+
# 2. Clean working tree
|
|
62
|
+
[ -z "$(git status --porcelain)" ] || { echo "Uncommitted changes"; exit 1; }
|
|
63
|
+
|
|
64
|
+
# 3. In sync with remote
|
|
65
|
+
git fetch origin
|
|
66
|
+
[ -z "$(git log HEAD..origin/main)" ] || { echo "Behind origin - pull first"; exit 1; }
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Quality Checks
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# 4. Tests pass
|
|
73
|
+
npm test
|
|
74
|
+
|
|
75
|
+
# 5. Build works
|
|
76
|
+
npm run build
|
|
77
|
+
|
|
78
|
+
# 6. No security vulnerabilities (high/critical)
|
|
79
|
+
npm audit --audit-level=high || echo "Warning: audit issues found"
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### npm Checks
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
# 7. Logged into npm
|
|
86
|
+
npm whoami || { echo "Not logged in - run: npm login"; exit 1; }
|
|
87
|
+
|
|
88
|
+
# 8. Version doesn't already exist
|
|
89
|
+
pkg_name=$(node -p "require('./package.json').name")
|
|
90
|
+
current=$(node -p "require('./package.json').version")
|
|
91
|
+
npm view "${pkg_name}@${current}" version 2>/dev/null && { echo "Version already published"; exit 1; }
|
|
92
|
+
|
|
93
|
+
# 9. Preview package contents
|
|
94
|
+
npm pack --dry-run 2>&1 | tail -20
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### GitHub Checks
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
# 10. Authenticated with GitHub
|
|
101
|
+
gh auth status || { echo "Not logged in - run: gh auth login"; exit 1; }
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Documentation Checks
|
|
105
|
+
|
|
106
|
+
> **Note:** Documentation freshness checks that compare against the version *being released* run **after** Step 4 (the version bump), not here in pre-flight:
|
|
107
|
+
> - `docs/internal/what-weve-built.md` title + ASCII version stamps → **Step 4.63**
|
|
108
|
+
> - `CHANGELOG.md` freshness (version entry present) → **Step 4.65**
|
|
109
|
+
> - `README.md` "What's new in <minor>" heading freshness → **Step 4.66**
|
|
110
|
+
>
|
|
111
|
+
> They must compare against the *new* version, which doesn't exist in `package.json` until Step 4 runs. Running them in pre-flight would compare against the *previous* release — which the docs already reflect — so the gate would never fire for the release in progress (root cause class of #684 / #687).
|
|
112
|
+
|
|
113
|
+
## Release Steps
|
|
114
|
+
|
|
115
|
+
### Step 1: Determine Version
|
|
116
|
+
|
|
117
|
+
If version type not provided as argument, ask the user:
|
|
118
|
+
|
|
119
|
+
| Type | When to Use | Example |
|
|
120
|
+
|------|-------------|---------|
|
|
121
|
+
| `patch` | Bug fixes, maintenance, no new features | 1.3.1 → 1.3.2 |
|
|
122
|
+
| `minor` | New features, backwards compatible | 1.3.1 → 1.4.0 |
|
|
123
|
+
| `major` | Breaking changes | 1.3.1 → 2.0.0 |
|
|
124
|
+
| `prerelease` | Alpha/beta/RC versions | 1.3.1 → 1.4.0-beta.0 |
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
current=$(node -p "require('./package.json').version")
|
|
128
|
+
echo "Current version: ${current}"
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Step 2: Generate Release Notes
|
|
132
|
+
|
|
133
|
+
Gather commits since last tag:
|
|
134
|
+
```bash
|
|
135
|
+
last_tag=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
|
|
136
|
+
if [ -n "$last_tag" ]; then
|
|
137
|
+
git log ${last_tag}..HEAD --oneline --no-merges
|
|
138
|
+
fi
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Categorize by conventional commit prefix:
|
|
142
|
+
- `feat:` → **Features**
|
|
143
|
+
- `fix:` → **Bug Fixes**
|
|
144
|
+
- `perf:` → **Performance**
|
|
145
|
+
- `docs:` → **Documentation**
|
|
146
|
+
- `refactor:` → **Refactoring**
|
|
147
|
+
- `chore:` → **Maintenance**
|
|
148
|
+
- `BREAKING CHANGE:` → **Breaking Changes** (for major releases)
|
|
149
|
+
|
|
150
|
+
**Release notes template:**
|
|
151
|
+
```markdown
|
|
152
|
+
## What's Changed
|
|
153
|
+
|
|
154
|
+
### Features
|
|
155
|
+
- Feature description (#PR)
|
|
156
|
+
|
|
157
|
+
### Bug Fixes
|
|
158
|
+
- Fix description (#PR)
|
|
159
|
+
|
|
160
|
+
### Breaking Changes
|
|
161
|
+
- Description of breaking change and migration path
|
|
162
|
+
|
|
163
|
+
**Full Changelog**: https://github.com/sequant-io/sequant/compare/v{old}...v{new}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**Show draft to user for approval before proceeding.**
|
|
167
|
+
|
|
168
|
+
### Step 3: Update CHANGELOG.md (if exists)
|
|
169
|
+
|
|
170
|
+
If `CHANGELOG.md` exists, use the **Edit tool** to:
|
|
171
|
+
|
|
172
|
+
1. Replace `## [Unreleased]` with `## [{new_version}] - {YYYY-MM-DD}`
|
|
173
|
+
2. Insert a fresh `## [Unreleased]` section above the newly stamped version:
|
|
174
|
+
|
|
175
|
+
```markdown
|
|
176
|
+
## [Unreleased]
|
|
177
|
+
|
|
178
|
+
## [1.4.0] - 2026-01-10
|
|
179
|
+
|
|
180
|
+
### Added
|
|
181
|
+
- New feature X
|
|
182
|
+
...
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
This ensures the next development cycle has an `[Unreleased]` section ready for contributors.
|
|
186
|
+
|
|
187
|
+
### Step 4: Bump Version
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
# For regular releases
|
|
191
|
+
npm version {patch|minor|major} --no-git-tag-version
|
|
192
|
+
|
|
193
|
+
# For pre-releases
|
|
194
|
+
npm version prerelease --preid=beta --no-git-tag-version
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Step 4.5: Sync Plugin Version
|
|
198
|
+
|
|
199
|
+
**IMPORTANT:** Keep plugin.json in sync with package.json.
|
|
200
|
+
|
|
201
|
+
Use the **Read tool** to read `.claude-plugin/plugin.json`, then use the **Edit tool** to update the version field:
|
|
202
|
+
|
|
203
|
+
```
|
|
204
|
+
Read(file_path=".claude-plugin/plugin.json")
|
|
205
|
+
|
|
206
|
+
Edit(file_path=".claude-plugin/plugin.json",
|
|
207
|
+
old_string="\"version\": \"<old_version>\"",
|
|
208
|
+
new_string="\"version\": \"<new_version>\"")
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
If `.claude-plugin/plugin.json` does not exist, skip this step.
|
|
212
|
+
|
|
213
|
+
**Why sync?** Sequant is distributed as both npm package and Claude Code plugin. Both must have matching versions to avoid user confusion and ensure compatibility.
|
|
214
|
+
|
|
215
|
+
### Step 4.6: Update what-weve-built.md
|
|
216
|
+
|
|
217
|
+
**IMPORTANT:** Keep `docs/internal/what-weve-built.md` version references in sync and document new features.
|
|
218
|
+
|
|
219
|
+
Get the new version, then use the Edit tool to update the file:
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
new_version=$(node -p "require('./package.json').version")
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Then use the **Edit tool** (not sed) to update `docs/internal/what-weve-built.md`:
|
|
226
|
+
|
|
227
|
+
```
|
|
228
|
+
# Update title version - use Edit tool with replace_all=true
|
|
229
|
+
Edit(file_path="docs/internal/what-weve-built.md",
|
|
230
|
+
old_string="Sequant v<old_version>",
|
|
231
|
+
new_string="Sequant v${new_version}",
|
|
232
|
+
replace_all=true)
|
|
233
|
+
|
|
234
|
+
# Update ASCII art version - use Edit tool with replace_all=true
|
|
235
|
+
Edit(file_path="docs/internal/what-weve-built.md",
|
|
236
|
+
old_string="SEQUANT v<old_version>",
|
|
237
|
+
new_string="SEQUANT v${new_version}",
|
|
238
|
+
replace_all=true)
|
|
239
|
+
|
|
240
|
+
# Update "Current Version" line - use Edit tool
|
|
241
|
+
Edit(file_path="docs/internal/what-weve-built.md",
|
|
242
|
+
old_string="**Current Version:** <old_version>",
|
|
243
|
+
new_string="**Current Version:** ${new_version}")
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
**Auto-generate feature bullets from CHANGELOG:**
|
|
247
|
+
|
|
248
|
+
Extract features from the `[Unreleased]` section of CHANGELOG.md:
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
# Extract [Unreleased] entries from CHANGELOG.md
|
|
252
|
+
if [ -f "CHANGELOG.md" ]; then
|
|
253
|
+
# Get content between [Unreleased] and next version header
|
|
254
|
+
unreleased_content=$(sed -n '/^## \[Unreleased\]/,/^## \[/p' CHANGELOG.md | head -n -1)
|
|
255
|
+
|
|
256
|
+
# Extract Added entries (these become what-weve-built features)
|
|
257
|
+
added_entries=$(echo "$unreleased_content" | sed -n '/^### Added/,/^### /p' | grep -E '^\s*-' | head -n -1 || true)
|
|
258
|
+
|
|
259
|
+
if [ -n "$added_entries" ]; then
|
|
260
|
+
echo "Features to add to what-weve-built.md:"
|
|
261
|
+
echo "$added_entries"
|
|
262
|
+
else
|
|
263
|
+
echo "No new features in [Unreleased] section"
|
|
264
|
+
fi
|
|
265
|
+
fi
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
**If CHANGELOG has features**, use the Edit tool to update `docs/internal/what-weve-built.md`:
|
|
269
|
+
|
|
270
|
+
1. **Update the "Recent Additions" section header:**
|
|
271
|
+
```
|
|
272
|
+
Edit(file_path="docs/internal/what-weve-built.md",
|
|
273
|
+
old_string="### Recent Additions (v<old_version>)",
|
|
274
|
+
new_string="### Recent Additions (v${new_version})")
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
2. **Add feature bullets under "Recent Additions":**
|
|
278
|
+
Transform CHANGELOG entries to what-weve-built format:
|
|
279
|
+
|
|
280
|
+
| CHANGELOG Format | what-weve-built Format |
|
|
281
|
+
|------------------|------------------------|
|
|
282
|
+
| `- Feature description (#123)` | `- **Feature Name** - Brief description` |
|
|
283
|
+
| `- Multi-line feature (#123)\n - Sub-detail` | `- **Feature Name** - Brief description` |
|
|
284
|
+
|
|
285
|
+
Example transformation:
|
|
286
|
+
```markdown
|
|
287
|
+
# From CHANGELOG:
|
|
288
|
+
- CHANGELOG update step in /exec skill (#320)
|
|
289
|
+
- Instructs /exec to add [Unreleased] entries during feature commits
|
|
290
|
+
|
|
291
|
+
# To what-weve-built:
|
|
292
|
+
- **CHANGELOG Automation** - Automatic CHANGELOG entry requirements in /exec and /qa
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
3. **Update counts in "At a Glance" table** if applicable:
|
|
296
|
+
- New skill added → increment skill count
|
|
297
|
+
- New command added → increment command count
|
|
298
|
+
- New MCP integration → increment integration count
|
|
299
|
+
|
|
300
|
+
**Fallback to commit-based detection:**
|
|
301
|
+
|
|
302
|
+
If CHANGELOG.md doesn't exist or has no `[Unreleased]` section, fall back to commit-based detection:
|
|
303
|
+
|
|
304
|
+
```bash
|
|
305
|
+
last_tag=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
|
|
306
|
+
if [ -n "$last_tag" ]; then
|
|
307
|
+
echo "New features since ${last_tag}:"
|
|
308
|
+
git log ${last_tag}..HEAD --oneline --no-merges | grep -E "^[a-f0-9]+ feat" || echo " (none)"
|
|
309
|
+
fi
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
**Ask the user to review what-weve-built.md before proceeding** if there are new features to document.
|
|
313
|
+
|
|
314
|
+
### Step 4.63: Verify what-weve-built.md Version Stamps
|
|
315
|
+
|
|
316
|
+
**IMPORTANT:** This runs **after** Step 4 (version bump) and Step 4.6 (which updates the stamps), so `package.json` already holds the *new* version. Running it earlier (in pre-flight) would compare against the previous release — which the file already reflects — so the gate would never fire for the version actually being released (root cause class of #684 / #687, the same ordering bug fixed for the README check in #685).
|
|
317
|
+
|
|
318
|
+
Warn-only (like the CHANGELOG freshness check): prompt the releaser if the title or ASCII-art version stamp omits/mismatches the version being released.
|
|
319
|
+
|
|
320
|
+
```bash
|
|
321
|
+
# Warn if docs/internal/what-weve-built.md version stamps don't match the version being released
|
|
322
|
+
if [ -f "docs/internal/what-weve-built.md" ]; then
|
|
323
|
+
new_version=$(node -p "require('./package.json').version")
|
|
324
|
+
|
|
325
|
+
# Check title version
|
|
326
|
+
title_version=$(grep -oE "Sequant v[0-9]+\.[0-9]+\.[0-9]+" docs/internal/what-weve-built.md | head -1 | grep -oE "[0-9]+\.[0-9]+\.[0-9]+" || true)
|
|
327
|
+
if [ "$title_version" != "$new_version" ]; then
|
|
328
|
+
echo "Warning: docs/internal/what-weve-built.md title shows v${title_version}, expected v${new_version}"
|
|
329
|
+
fi
|
|
330
|
+
|
|
331
|
+
# Check ASCII art version
|
|
332
|
+
ascii_version=$(grep -E "SEQUANT v[0-9]+\.[0-9]+\.[0-9]+" docs/internal/what-weve-built.md | grep -oE "[0-9]+\.[0-9]+\.[0-9]+" || true)
|
|
333
|
+
if [ "$ascii_version" != "$new_version" ]; then
|
|
334
|
+
echo "Warning: docs/internal/what-weve-built.md ASCII art shows v${ascii_version}, expected v${new_version}"
|
|
335
|
+
fi
|
|
336
|
+
fi
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### Step 4.65: Verify CHANGELOG Freshness
|
|
340
|
+
|
|
341
|
+
**IMPORTANT:** This runs **after** Step 4 (version bump) so `package.json` already holds the *new* version. Running it earlier (in pre-flight) would compare against the previous release, which the CHANGELOG already lists — so the gate would never fire for the version actually being released (root cause class of #684).
|
|
342
|
+
|
|
343
|
+
**Note (#701):** #694 moved the changelog wall out of `README.md` into `CHANGELOG.md` and removed the README "What's new" section, so this gate now checks `CHANGELOG.md` (the source of truth). Grepping `README.md` for a now-absent `# What's new` heading made the warn-only gate fire on every release.
|
|
344
|
+
|
|
345
|
+
Warn-only (like the what-weve-built checks): prompt the releaser to add a `CHANGELOG.md` entry if the new version is absent.
|
|
346
|
+
|
|
347
|
+
```bash
|
|
348
|
+
# Warn if CHANGELOG.md omits the version being released
|
|
349
|
+
if [ -f "CHANGELOG.md" ]; then
|
|
350
|
+
new_version=$(node -p "require('./package.json').version")
|
|
351
|
+
|
|
352
|
+
# Match the Keep-a-Changelog heading for this version, e.g. "## [2.4.0] - 2026-05-30"
|
|
353
|
+
if ! grep -qF "[${new_version}]" CHANGELOG.md; then
|
|
354
|
+
echo "Warning: CHANGELOG.md omits v${new_version} — add a \"## [${new_version}]\" entry before releasing"
|
|
355
|
+
fi
|
|
356
|
+
fi
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
### Step 4.66: Verify README "What's new" Freshness
|
|
360
|
+
|
|
361
|
+
**IMPORTANT:** This runs **after** Step 4 (version bump) so `package.json` already holds the *new* version. Running it earlier (in pre-flight) would compare against the previous release — which the README already reflects — so the gate would never fire for the version actually being released (root cause class of #684 / #687, the same ordering bug fixed for the README check in #685).
|
|
362
|
+
|
|
363
|
+
**Note (#702 / #707):** This gate owns the hand-written `### What's new in <major>.<minor>` positioning section that #702 re-added to `README.md` — distinct from the changelog wall that #694 moved to `CHANGELOG.md` (covered by Step 4.65). It keys on the **minor** line, not a full semver: "What's new in 2.6" is correct for the entire 2.6.x line, so a **patch** release (2.6.0 → 2.6.1) does NOT fire against a matching heading. During v2.6.0 the heading still read "What's new in 2.5" and shipped stale (fixed manually in 18c2d42); this gate flags that case.
|
|
364
|
+
|
|
365
|
+
Warn-only (like the CHANGELOG freshness check): prompt the releaser if the README's latest "What's new" heading lags the minor line being released. No README edit is auto-applied — the section's content and positioning are an editorial decision.
|
|
366
|
+
|
|
367
|
+
```bash
|
|
368
|
+
# Warn if README.md's latest "What's new" heading lags the minor line being released.
|
|
369
|
+
# Keys on the MINOR line (e.g. "2.6"), so a patch release against a matching heading stays silent.
|
|
370
|
+
if [ -f "README.md" ]; then
|
|
371
|
+
new_version=$(node -p "require('./package.json').version")
|
|
372
|
+
new_minor=$(echo "$new_version" | grep -oE '^[0-9]+\.[0-9]+')
|
|
373
|
+
|
|
374
|
+
# Anchor to a markdown heading (^#+) so a "What's new in X.Y" mention in prose can't be read as
|
|
375
|
+
# the section, and take the numerically-highest minor (sort -t. then tail -1) so the result is
|
|
376
|
+
# independent of heading order in the file rather than assuming newest-first.
|
|
377
|
+
readme_minor=$(grep -oE "^#+[[:space:]]+What's new in [0-9]+\.[0-9]+" README.md \
|
|
378
|
+
| grep -oE '[0-9]+\.[0-9]+' | sort -t. -k1,1n -k2,2n | tail -1 || true)
|
|
379
|
+
|
|
380
|
+
# The -n guard is load-bearing: if the section is ever removed again (as #694 did),
|
|
381
|
+
# this gate stays silent rather than firing on every release (the bug #701 fixed for the old gate).
|
|
382
|
+
if [ -n "$readme_minor" ] && [ "$readme_minor" != "$new_minor" ]; then
|
|
383
|
+
echo "Warning: README.md 'What's new' section is for $readme_minor, expected $new_minor — add/update the heading before releasing"
|
|
384
|
+
fi
|
|
385
|
+
fi
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
### Step 4.7: Regenerate Marketplace Artifact
|
|
389
|
+
|
|
390
|
+
**IMPORTANT:** The marketplace plugin artifact under `dist/marketplace/` is bundled into the published tgz via `files: ["dist", ...]` in package.json — even though `dist/` is gitignored. Regenerate it from current sources **before** packing/publishing so the bundled README always matches; otherwise a stale artifact ships (root cause of #684 — the v2.4.0 tgz carried a "Node.js 20+" README after the floor moved to 22.12).
|
|
391
|
+
|
|
392
|
+
This is an action step, so it lives in Release Steps (not the read-only pre-flight checks). It MUST run before Step 5 (`npm pack`) and Step 9 (`npm publish`).
|
|
393
|
+
|
|
394
|
+
```bash
|
|
395
|
+
# Regenerate the marketplace plugin artifact from current sources
|
|
396
|
+
npm run prepare:marketplace
|
|
397
|
+
|
|
398
|
+
# Freshness sanity check: generated README's Node.js floor should match package.json engines.
|
|
399
|
+
# Warn-only (regeneration above already fixes the artifact; this is a belt-and-suspenders signal).
|
|
400
|
+
gen_readme="dist/marketplace/external_plugins/sequant/README.md"
|
|
401
|
+
if [ -f "$gen_readme" ]; then
|
|
402
|
+
engines_floor=$(node -p "require('./package.json').engines.node.replace(/[^0-9.]/g,'')") # e.g. 22.12.0
|
|
403
|
+
readme_floor=$(grep -oE "Node\.js [0-9]+\.[0-9]+" "$gen_readme" | head -1 | grep -oE "[0-9]+\.[0-9]+" || true)
|
|
404
|
+
if [ -n "$readme_floor" ] && [ "${engines_floor%.*}" != "$readme_floor" ]; then
|
|
405
|
+
echo "Warning: generated marketplace README shows Node.js ${readme_floor}, package.json engines floor is ${engines_floor}"
|
|
406
|
+
fi
|
|
407
|
+
fi
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
### Step 5: Verify Package Size
|
|
411
|
+
|
|
412
|
+
```bash
|
|
413
|
+
# Check what will be published
|
|
414
|
+
npm pack --dry-run
|
|
415
|
+
|
|
416
|
+
# Verify size is reasonable (warn if > 500KB)
|
|
417
|
+
size=$(npm pack --dry-run 2>&1 | grep "total files" -A1 | tail -1 || true)
|
|
418
|
+
echo "Package size: ${size}"
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
### Step 6: Commit and Push
|
|
422
|
+
|
|
423
|
+
```bash
|
|
424
|
+
new_version=$(node -p "require('./package.json').version")
|
|
425
|
+
git add package.json package-lock.json CHANGELOG.md .claude-plugin/plugin.json .claude-plugin/marketplace.json docs/internal/what-weve-built.md
|
|
426
|
+
git commit -m "chore: release v${new_version}"
|
|
427
|
+
git push origin main
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
### Step 7: Create and Push Tag
|
|
431
|
+
|
|
432
|
+
```bash
|
|
433
|
+
git tag -a "v${new_version}" -m "Release v${new_version}"
|
|
434
|
+
git push origin "v${new_version}"
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
### Step 8: Create GitHub Release
|
|
438
|
+
|
|
439
|
+
```bash
|
|
440
|
+
# Regular release
|
|
441
|
+
gh release create "v${new_version}" \
|
|
442
|
+
--title "v${new_version} - {title}" \
|
|
443
|
+
--notes "{release_notes}"
|
|
444
|
+
|
|
445
|
+
# Pre-release (alpha/beta/rc)
|
|
446
|
+
gh release create "v${new_version}" \
|
|
447
|
+
--title "v${new_version}" \
|
|
448
|
+
--notes "{release_notes}" \
|
|
449
|
+
--prerelease
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
For the title, use a short summary:
|
|
453
|
+
- `v1.4.0 - New Feature Name`
|
|
454
|
+
- `v1.3.2 - Bug Fix Release`
|
|
455
|
+
- `v2.0.0 - Breaking Changes`
|
|
456
|
+
|
|
457
|
+
### Step 9: Publish to npm
|
|
458
|
+
|
|
459
|
+
Attempt to publish:
|
|
460
|
+
|
|
461
|
+
```bash
|
|
462
|
+
# Regular release
|
|
463
|
+
npm publish
|
|
464
|
+
|
|
465
|
+
# Pre-release with tag (prevents becoming "latest")
|
|
466
|
+
npm publish --tag beta
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
**If npm returns `EOTP` (2FA required):**
|
|
470
|
+
|
|
471
|
+
Non-interactive environments cannot handle the OTP prompt. Ask the user to publish manually:
|
|
472
|
+
|
|
473
|
+
```
|
|
474
|
+
npm publish --otp=<code>
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
Do NOT attempt to pass OTP codes programmatically or retry `npm publish` in a loop. Hand off to the user and continue with post-release verification once they confirm.
|
|
478
|
+
|
|
479
|
+
## Post-Release Verification
|
|
480
|
+
|
|
481
|
+
Verify both platforms show the new version:
|
|
482
|
+
|
|
483
|
+
```bash
|
|
484
|
+
# npm verification (may take 1-2 minutes to propagate)
|
|
485
|
+
sleep 5
|
|
486
|
+
npm view sequant version
|
|
487
|
+
npm view sequant dist-tags
|
|
488
|
+
|
|
489
|
+
# GitHub verification
|
|
490
|
+
gh release view "v${new_version}"
|
|
491
|
+
|
|
492
|
+
# Test install
|
|
493
|
+
npx sequant@${new_version} --version
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
## Output Summary
|
|
497
|
+
|
|
498
|
+
```
|
|
499
|
+
Release v{version} Complete
|
|
500
|
+
|
|
501
|
+
Version: {old} → {new}
|
|
502
|
+
Commit: {hash}
|
|
503
|
+
Tag: v{new}
|
|
504
|
+
|
|
505
|
+
GitHub: https://github.com/sequant-io/sequant/releases/tag/v{new}
|
|
506
|
+
npm: https://www.npmjs.com/package/sequant/v/{new}
|
|
507
|
+
Plugin: Version synced in .claude-plugin/plugin.json
|
|
508
|
+
Docs: Version synced in docs/internal/what-weve-built.md
|
|
509
|
+
|
|
510
|
+
Install (npm):
|
|
511
|
+
npm install sequant@{new}
|
|
512
|
+
npx sequant@{new}
|
|
513
|
+
|
|
514
|
+
Install (plugin):
|
|
515
|
+
/plugin marketplace update sequant-io/sequant
|
|
516
|
+
/plugin install sequant
|
|
517
|
+
|
|
518
|
+
Verification:
|
|
519
|
+
[x] npm view shows correct version
|
|
520
|
+
[x] GitHub release created
|
|
521
|
+
[x] Tag pushed
|
|
522
|
+
[x] plugin.json version synced
|
|
523
|
+
[x] what-weve-built.md version synced
|
|
524
|
+
[x] New features documented (if any)
|
|
525
|
+
|
|
526
|
+
Next steps:
|
|
527
|
+
- Announce release (if major/minor)
|
|
528
|
+
- Update dependent projects
|
|
529
|
+
- Monitor for issues
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
## Dry Run Mode
|
|
533
|
+
|
|
534
|
+
When `--dry-run` is specified:
|
|
535
|
+
|
|
536
|
+
1. Run all pre-flight checks
|
|
537
|
+
2. Show what version would be created
|
|
538
|
+
3. Show draft release notes
|
|
539
|
+
4. Show `npm pack --dry-run` output
|
|
540
|
+
5. **Do NOT** execute any publish commands
|
|
541
|
+
|
|
542
|
+
```
|
|
543
|
+
Dry Run Summary
|
|
544
|
+
|
|
545
|
+
Would release: 1.3.1 → 1.4.0
|
|
546
|
+
|
|
547
|
+
Package contents:
|
|
548
|
+
- 176 files
|
|
549
|
+
- 195.9 kB packed
|
|
550
|
+
|
|
551
|
+
Release notes:
|
|
552
|
+
[draft notes here]
|
|
553
|
+
|
|
554
|
+
To execute: /release minor
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
## Rollback Procedures
|
|
558
|
+
|
|
559
|
+
### Before npm publish
|
|
560
|
+
|
|
561
|
+
```bash
|
|
562
|
+
# Undo version bump (if not committed)
|
|
563
|
+
git checkout -- package.json package-lock.json
|
|
564
|
+
|
|
565
|
+
# Undo commit (if not pushed)
|
|
566
|
+
git reset --soft HEAD~1
|
|
567
|
+
|
|
568
|
+
# Delete local tag
|
|
569
|
+
git tag -d v{version}
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
### After git push, before npm publish
|
|
573
|
+
|
|
574
|
+
```bash
|
|
575
|
+
# Delete remote tag
|
|
576
|
+
git push origin :refs/tags/v{version}
|
|
577
|
+
|
|
578
|
+
# Delete GitHub release
|
|
579
|
+
gh release delete v{version} --yes
|
|
580
|
+
|
|
581
|
+
# Revert commit
|
|
582
|
+
git revert HEAD
|
|
583
|
+
git push origin main
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
### After npm publish
|
|
587
|
+
|
|
588
|
+
**Do NOT use `npm unpublish`** - it breaks dependent projects.
|
|
589
|
+
|
|
590
|
+
Instead:
|
|
591
|
+
1. Publish a patch fix: `npm version patch && npm publish`
|
|
592
|
+
2. Deprecate bad version: `npm deprecate sequant@{bad} "Use {good} instead"`
|
|
593
|
+
|
|
594
|
+
## Error Handling
|
|
595
|
+
|
|
596
|
+
| Error | Cause | Resolution |
|
|
597
|
+
|-------|-------|------------|
|
|
598
|
+
| "Not on main" | Wrong branch | `git checkout main` |
|
|
599
|
+
| "Uncommitted changes" | Dirty working tree | `git stash` or commit |
|
|
600
|
+
| "Behind origin" | Remote has new commits | `git pull origin main` |
|
|
601
|
+
| "Tests failed" | Failing tests | Fix tests first |
|
|
602
|
+
| "Version exists" | Already published | Choose different version |
|
|
603
|
+
| "Not logged in (npm)" | npm auth expired | `npm login` |
|
|
604
|
+
| "Not logged in (gh)" | GitHub auth expired | `gh auth login` |
|
|
605
|
+
| "OTP required" | npm 2FA enabled | Enter code when prompted |
|
|
606
|
+
| "Package too large" | Bloated package | Check `.npmignore` |
|
|
607
|
+
|
|
608
|
+
## Best Practices
|
|
609
|
+
|
|
610
|
+
### Versioning
|
|
611
|
+
- Follow [Semantic Versioning](https://semver.org/)
|
|
612
|
+
- Use pre-release tags for testing: `1.4.0-beta.1`
|
|
613
|
+
- Major version 0.x.x indicates unstable API
|
|
614
|
+
|
|
615
|
+
### Release Notes
|
|
616
|
+
- Write for users, not developers
|
|
617
|
+
- Highlight breaking changes prominently
|
|
618
|
+
- Include migration guides for major releases
|
|
619
|
+
- Link to relevant issues/PRs
|
|
620
|
+
|
|
621
|
+
### npm
|
|
622
|
+
- Keep package size small (< 500KB ideal)
|
|
623
|
+
- Use `files` in package.json or `.npmignore`
|
|
624
|
+
- Test with `npm pack` before publishing
|
|
625
|
+
- Use `--tag` for pre-releases to avoid becoming "latest"
|
|
626
|
+
|
|
627
|
+
### GitHub
|
|
628
|
+
- Use pre-release flag for beta/RC versions
|
|
629
|
+
- Attach relevant assets (if any)
|
|
630
|
+
- Use consistent title format
|
|
631
|
+
|
|
632
|
+
### Security
|
|
633
|
+
- Run `npm audit` before releasing
|
|
634
|
+
- Don't include sensitive files (check `npm pack --dry-run`)
|
|
635
|
+
- Verify `npm whoami` shows correct account
|
|
636
|
+
|
|
637
|
+
## Examples
|
|
638
|
+
|
|
639
|
+
### Standard Patch Release
|
|
640
|
+
```
|
|
641
|
+
/release patch
|
|
642
|
+
```
|
|
643
|
+
|
|
644
|
+
### Minor Release with Custom Notes
|
|
645
|
+
```
|
|
646
|
+
/release minor
|
|
647
|
+
# Review generated notes
|
|
648
|
+
# Edit if needed
|
|
649
|
+
# Approve to publish
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
### Beta Pre-release
|
|
653
|
+
```
|
|
654
|
+
/release minor --prerelease beta
|
|
655
|
+
```
|
|
656
|
+
Creates: `1.4.0-beta.0`
|
|
657
|
+
|
|
658
|
+
### Preview Without Publishing
|
|
659
|
+
```
|
|
660
|
+
/release minor --dry-run
|
|
661
|
+
```
|