@wipcomputer/wip-release 1.9.14 → 1.9.15
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/SKILL.md +19 -1
- package/cli.js +2 -1
- package/core.mjs +26 -6
- package/package.json +1 -1
package/SKILL.md
CHANGED
|
@@ -78,10 +78,28 @@ wip-release checks that product docs (dev update, roadmap, readme-first) were up
|
|
|
78
78
|
- **--skip-product-check**: bypasses the gate
|
|
79
79
|
|
|
80
80
|
Checks:
|
|
81
|
-
1. `ai/dev-updates/` has a file
|
|
81
|
+
1. `ai/dev-updates/` has a file modified since the last release tag
|
|
82
82
|
2. `ai/product/plans-prds/roadmap.md` was modified since last release
|
|
83
83
|
3. `ai/product/readme-first-product.md` was modified since last release
|
|
84
84
|
|
|
85
|
+
### Skill Publish to Website
|
|
86
|
+
|
|
87
|
+
After publishing, wip-release auto-copies SKILL.md to your website as plain text. Any AI can fetch the URL and get clean install instructions.
|
|
88
|
+
|
|
89
|
+
**Setup:** Set the `WIP_WEBSITE_REPO` environment variable to your website repo path. That's it.
|
|
90
|
+
|
|
91
|
+
**How it works:**
|
|
92
|
+
1. If SKILL.md exists and `WIP_WEBSITE_REPO` is set, copies SKILL.md to `{website}/wip.computer/install/{name}.txt`
|
|
93
|
+
2. Runs `deploy.sh` in the website repo to push live
|
|
94
|
+
3. Non-blocking: if deploy fails, the release still succeeds
|
|
95
|
+
|
|
96
|
+
**Name resolution (first match wins):**
|
|
97
|
+
1. `.publish-skill.json` in repo root: `{ "name": "my-tool" }`
|
|
98
|
+
2. `package.json` name (with `@scope/` prefix stripped)
|
|
99
|
+
3. Directory name (with `-private` suffix stripped)
|
|
100
|
+
|
|
101
|
+
No config file needed. Every repo with a SKILL.md auto-publishes on release.
|
|
102
|
+
|
|
85
103
|
### Module
|
|
86
104
|
|
|
87
105
|
```javascript
|
package/cli.js
CHANGED
|
@@ -23,7 +23,8 @@ const skipStaleCheck = args.includes('--skip-stale-check');
|
|
|
23
23
|
const skipWorktreeCheck = args.includes('--skip-worktree-check');
|
|
24
24
|
const notesFilePath = flag('notes-file');
|
|
25
25
|
let notes = flag('notes');
|
|
26
|
-
|
|
26
|
+
// Bug fix #121: use strict check, not truthiness. --notes="" is empty, not absent.
|
|
27
|
+
let notesSource = (notes !== null && notes !== undefined && notes !== '') ? 'flag' : 'none';
|
|
27
28
|
|
|
28
29
|
// Release notes priority (highest wins):
|
|
29
30
|
// 1. --notes-file=path Explicit file path (always wins)
|
package/core.mjs
CHANGED
|
@@ -90,19 +90,27 @@ export function syncSkillVersion(repoPath, newVersion) {
|
|
|
90
90
|
export function updateChangelog(repoPath, newVersion, notes) {
|
|
91
91
|
const changelogPath = join(repoPath, 'CHANGELOG.md');
|
|
92
92
|
const date = new Date().toISOString().split('T')[0];
|
|
93
|
-
|
|
93
|
+
|
|
94
|
+
// Bug fix #121: never silently default to "Release." when notes are empty.
|
|
95
|
+
// If notes are empty at this point, warn loudly.
|
|
96
|
+
if (!notes || !notes.trim()) {
|
|
97
|
+
console.warn(` ! WARNING: No release notes provided for v${newVersion}. CHANGELOG entry will be minimal.`);
|
|
98
|
+
notes = 'No release notes provided.';
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const entry = `## ${newVersion} (${date})\n\n${notes}\n`;
|
|
94
102
|
|
|
95
103
|
if (!existsSync(changelogPath)) {
|
|
96
|
-
writeFileSync(changelogPath, `# Changelog\n\n${entry}
|
|
104
|
+
writeFileSync(changelogPath, `# Changelog\n\n${entry}`);
|
|
97
105
|
return;
|
|
98
106
|
}
|
|
99
107
|
|
|
100
108
|
let content = readFileSync(changelogPath, 'utf8');
|
|
101
|
-
// Insert after the # Changelog header
|
|
102
|
-
const headerMatch = content.match(/^# Changelog\s*\n
|
|
109
|
+
// Insert after the # Changelog header (single newline, no accumulation)
|
|
110
|
+
const headerMatch = content.match(/^# Changelog\s*\n+/);
|
|
103
111
|
if (headerMatch) {
|
|
104
112
|
const insertPoint = headerMatch[0].length;
|
|
105
|
-
content = content.slice(0, insertPoint) +
|
|
113
|
+
content = content.slice(0, insertPoint) + entry + '\n' + content.slice(insertPoint);
|
|
106
114
|
} else {
|
|
107
115
|
content = `# Changelog\n\n${entry}\n${content}`;
|
|
108
116
|
}
|
|
@@ -395,7 +403,7 @@ export function buildReleaseNotes(repoPath, currentVersion, newVersion, notes) {
|
|
|
395
403
|
}
|
|
396
404
|
|
|
397
405
|
// Install section
|
|
398
|
-
lines.push('### Install
|
|
406
|
+
lines.push('### Install');
|
|
399
407
|
lines.push('```bash');
|
|
400
408
|
lines.push(`npm install -g ${pkg.name}@${newVersion}`);
|
|
401
409
|
lines.push('```');
|
|
@@ -438,6 +446,18 @@ export function createGitHubRelease(repoPath, newVersion, notes, currentVersion)
|
|
|
438
446
|
'--notes-file', '.release-notes-tmp.md',
|
|
439
447
|
'--repo', repoSlug
|
|
440
448
|
], { cwd: repoPath, stdio: 'inherit' });
|
|
449
|
+
|
|
450
|
+
// Bug fix #121: verify the release was actually created
|
|
451
|
+
try {
|
|
452
|
+
const verify = execFileSync('gh', [
|
|
453
|
+
'release', 'view', `v${newVersion}`,
|
|
454
|
+
'--repo', repoSlug, '--json', 'body', '--jq', '.body | length'
|
|
455
|
+
], { cwd: repoPath, encoding: 'utf8' }).trim();
|
|
456
|
+
const bodyLen = parseInt(verify, 10);
|
|
457
|
+
if (bodyLen < 50) {
|
|
458
|
+
console.warn(` ! GitHub release body is only ${bodyLen} chars. Notes may be truncated.`);
|
|
459
|
+
}
|
|
460
|
+
} catch {}
|
|
441
461
|
} finally {
|
|
442
462
|
try { execFileSync('rm', ['-f', tmpFile]); } catch {}
|
|
443
463
|
}
|
package/package.json
CHANGED