@wipcomputer/wip-ai-devops-toolbox 1.9.28 → 1.9.30
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/CHANGELOG.md +70 -0
- package/SKILL.md +1 -1
- package/package.json +1 -1
- package/tools/deploy-public/package.json +1 -1
- package/tools/post-merge-rename/package.json +1 -1
- package/tools/wip-branch-guard/package.json +1 -1
- package/tools/wip-file-guard/package.json +1 -1
- package/tools/wip-license-guard/package.json +1 -1
- package/tools/wip-license-hook/package.json +1 -1
- package/tools/wip-readme-format/package.json +1 -1
- package/tools/wip-release/cli.js +6 -6
- package/tools/wip-release/core.mjs +54 -10
- package/tools/wip-release/package.json +1 -1
- package/tools/wip-repo-init/package.json +1 -1
- package/tools/wip-repo-permissions-hook/package.json +1 -1
- package/tools/wip-repos/package.json +1 -1
- package/tools/wip-universal-installer/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -31,6 +31,76 @@
|
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
|
|
34
|
+
|
|
35
|
+
## 1.9.30 (2026-03-15)
|
|
36
|
+
|
|
37
|
+
# Release notes must be a file on disk
|
|
38
|
+
|
|
39
|
+
**Date:** 2026-03-15
|
|
40
|
+
|
|
41
|
+
## What changed
|
|
42
|
+
|
|
43
|
+
wip-release no longer accepts the `--notes` flag. Release notes MUST come from a file on disk:
|
|
44
|
+
|
|
45
|
+
1. `RELEASE-NOTES-v{version}.md` in repo root (auto-detected)
|
|
46
|
+
2. `ai/dev-updates/YYYY-MM-DD--description.md` (auto-detected)
|
|
47
|
+
3. `--notes-file=path` (explicit file path)
|
|
48
|
+
|
|
49
|
+
If no file exists, the release is blocked. The gate scaffolds a template (`RELEASE-NOTES-v{version}.md`) so the agent has something to fill in.
|
|
50
|
+
|
|
51
|
+
## Why
|
|
52
|
+
|
|
53
|
+
The `--notes` flag was the root cause of every bad release note. Agents passed one-liners like `--notes="fix bug"` and the gate let them through. Even after we added length checks and changelog detection, agents found ways around it. The flag was an escape hatch that undermined the entire system.
|
|
54
|
+
|
|
55
|
+
The file-on-disk requirement solves three problems:
|
|
56
|
+
1. **Reviewability.** The file is on the branch. It shows up in the PR diff. Parker can read and approve the release notes before merge.
|
|
57
|
+
2. **Quality.** Writing a file forces the agent to think about what changed and why. A flag encourages one-liners.
|
|
58
|
+
3. **History.** The file is committed to git. The release notes are part of the repo history, not a transient CLI argument.
|
|
59
|
+
|
|
60
|
+
## What agents need to do
|
|
61
|
+
|
|
62
|
+
Before running `wip-release`:
|
|
63
|
+
1. Write `RELEASE-NOTES-v{version}.md` or `ai/dev-updates/YYYY-MM-DD--description.md`
|
|
64
|
+
2. Commit it on the branch
|
|
65
|
+
3. The file shows up in the PR for review
|
|
66
|
+
4. After merge to main, `wip-release` auto-detects it
|
|
67
|
+
|
|
68
|
+
If the agent forgets, `wip-release` blocks and scaffolds a template.
|
|
69
|
+
|
|
70
|
+
## 1.9.29 (2026-03-15)
|
|
71
|
+
|
|
72
|
+
# Release notes must be a file on disk
|
|
73
|
+
|
|
74
|
+
**Date:** 2026-03-15
|
|
75
|
+
|
|
76
|
+
## What changed
|
|
77
|
+
|
|
78
|
+
wip-release no longer accepts the `--notes` flag. Release notes MUST come from a file on disk:
|
|
79
|
+
|
|
80
|
+
1. `RELEASE-NOTES-v{version}.md` in repo root (auto-detected)
|
|
81
|
+
2. `ai/dev-updates/YYYY-MM-DD--description.md` (auto-detected)
|
|
82
|
+
3. `--notes-file=path` (explicit file path)
|
|
83
|
+
|
|
84
|
+
If no file exists, the release is blocked. The gate scaffolds a template (`RELEASE-NOTES-v{version}.md`) so the agent has something to fill in.
|
|
85
|
+
|
|
86
|
+
## Why
|
|
87
|
+
|
|
88
|
+
The `--notes` flag was the root cause of every bad release note. Agents passed one-liners like `--notes="fix bug"` and the gate let them through. Even after we added length checks and changelog detection, agents found ways around it. The flag was an escape hatch that undermined the entire system.
|
|
89
|
+
|
|
90
|
+
The file-on-disk requirement solves three problems:
|
|
91
|
+
1. **Reviewability.** The file is on the branch. It shows up in the PR diff. Parker can read and approve the release notes before merge.
|
|
92
|
+
2. **Quality.** Writing a file forces the agent to think about what changed and why. A flag encourages one-liners.
|
|
93
|
+
3. **History.** The file is committed to git. The release notes are part of the repo history, not a transient CLI argument.
|
|
94
|
+
|
|
95
|
+
## What agents need to do
|
|
96
|
+
|
|
97
|
+
Before running `wip-release`:
|
|
98
|
+
1. Write `RELEASE-NOTES-v{version}.md` or `ai/dev-updates/YYYY-MM-DD--description.md`
|
|
99
|
+
2. Commit it on the branch
|
|
100
|
+
3. The file shows up in the PR for review
|
|
101
|
+
4. After merge to main, `wip-release` auto-detects it
|
|
102
|
+
|
|
103
|
+
If the agent forgets, `wip-release` blocks and scaffolds a template.
|
|
34
104
|
|
|
35
105
|
## 1.9.28 (2026-03-15)
|
|
36
106
|
|
package/SKILL.md
CHANGED
|
@@ -5,7 +5,7 @@ license: MIT
|
|
|
5
5
|
interface: [cli, module, mcp, skill, hook, plugin]
|
|
6
6
|
metadata:
|
|
7
7
|
display-name: "WIP AI DevOps Toolbox"
|
|
8
|
-
version: "1.9.
|
|
8
|
+
version: "1.9.30"
|
|
9
9
|
homepage: "https://github.com/wipcomputer/wip-ai-devops-toolbox"
|
|
10
10
|
author: "Parker Todd Brooks"
|
|
11
11
|
category: dev-tools
|
package/package.json
CHANGED
package/tools/wip-release/cli.js
CHANGED
|
@@ -119,12 +119,12 @@ Flags:
|
|
|
119
119
|
--skip-stale-check Skip stale remote branch check
|
|
120
120
|
--skip-worktree-check Skip worktree guard (allow release from worktree)
|
|
121
121
|
|
|
122
|
-
Release notes (
|
|
123
|
-
1. --notes-file=path Explicit file path
|
|
124
|
-
2. RELEASE-NOTES-v{ver}.md In repo root (
|
|
125
|
-
3. ai/dev-updates/YYYY-MM-DD* Today's dev update (
|
|
126
|
-
|
|
127
|
-
|
|
122
|
+
Release notes (REQUIRED, must be a file on disk):
|
|
123
|
+
1. --notes-file=path Explicit file path
|
|
124
|
+
2. RELEASE-NOTES-v{ver}.md In repo root (auto-detected)
|
|
125
|
+
3. ai/dev-updates/YYYY-MM-DD* Today's dev update (auto-detected)
|
|
126
|
+
The --notes flag is NOT accepted. Write a file. Commit it on your branch.
|
|
127
|
+
The file shows up in the PR diff so it can be reviewed before merge.
|
|
128
128
|
|
|
129
129
|
Skill publish to website:
|
|
130
130
|
Add .publish-skill.json to repo root: { "name": "my-tool" }
|
|
@@ -227,28 +227,38 @@ function checkReleaseNotes(notes, notesSource, level) {
|
|
|
227
227
|
const issues = [];
|
|
228
228
|
|
|
229
229
|
if (!notes) {
|
|
230
|
-
issues.push('No release notes
|
|
230
|
+
issues.push('No release notes found. A file is REQUIRED.');
|
|
231
|
+
issues.push('Write RELEASE-NOTES-v{version}.md or ai/dev-updates/YYYY-MM-DD--description.md');
|
|
232
|
+
issues.push('Commit it on your branch so it is reviewable in the PR.');
|
|
231
233
|
return { ok: false, issues, block: true };
|
|
232
234
|
}
|
|
233
235
|
|
|
234
|
-
//
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
issues.push('
|
|
236
|
+
// HARD RULE: release notes must come from a file on disk.
|
|
237
|
+
// --notes flag is NOT accepted. Write a file. Commit it. Review it.
|
|
238
|
+
if (notesSource === 'flag') {
|
|
239
|
+
issues.push('Release notes must come from a file, not the --notes flag.');
|
|
240
|
+
issues.push('Write RELEASE-NOTES-v{version}.md or ai/dev-updates/YYYY-MM-DD--description.md');
|
|
241
|
+
issues.push('Commit it on your branch so it is reviewable in the PR before merge.');
|
|
242
|
+
return { ok: false, issues, block: true };
|
|
238
243
|
}
|
|
239
244
|
|
|
240
|
-
//
|
|
241
|
-
if (
|
|
242
|
-
issues.push('
|
|
243
|
-
issues.push('Write RELEASE-NOTES-v{version}.md (dashes not dots) and commit it.');
|
|
245
|
+
// Notes too short.
|
|
246
|
+
if (notes.length < 50) {
|
|
247
|
+
issues.push('Release notes are too short (under 50 chars). Explain what changed and why.');
|
|
244
248
|
}
|
|
245
249
|
|
|
246
|
-
// Check for changelog-style one-liners
|
|
250
|
+
// Check for changelog-style one-liners
|
|
247
251
|
const looksLikeChangelog = /^(fix|add|update|remove|bump|chore|refactor|docs?)[\s:]/i.test(notes);
|
|
248
252
|
if (looksLikeChangelog && notes.length < 100) {
|
|
249
253
|
issues.push('Notes look like a changelog entry, not a narrative. Explain the impact.');
|
|
250
254
|
}
|
|
251
255
|
|
|
256
|
+
// Release notes should reference at least one issue
|
|
257
|
+
const hasIssueRef = /#\d+/.test(notes);
|
|
258
|
+
if (!hasIssueRef) {
|
|
259
|
+
issues.push('No issue reference found (#XX). Every release should close or reference an issue.');
|
|
260
|
+
}
|
|
261
|
+
|
|
252
262
|
return { ok: issues.length === 0, issues, block: issues.length > 0 };
|
|
253
263
|
}
|
|
254
264
|
|
|
@@ -264,6 +274,19 @@ export function scaffoldReleaseNotes(repoPath, version) {
|
|
|
264
274
|
const pkg = JSON.parse(readFileSync(join(repoPath, 'package.json'), 'utf8'));
|
|
265
275
|
const name = pkg.name?.replace(/^@[^/]+\//, '') || basename(repoPath);
|
|
266
276
|
|
|
277
|
+
// Auto-detect issue references from commits since last tag
|
|
278
|
+
let issueRefs = '';
|
|
279
|
+
try {
|
|
280
|
+
const lastTag = execFileSync('git', ['describe', '--tags', '--abbrev=0'],
|
|
281
|
+
{ cwd: repoPath, encoding: 'utf8' }).trim();
|
|
282
|
+
const log = execFileSync('git', ['log', `${lastTag}..HEAD`, '--oneline'],
|
|
283
|
+
{ cwd: repoPath, encoding: 'utf8' });
|
|
284
|
+
const issues = [...new Set(log.match(/#\d+/g) || [])];
|
|
285
|
+
if (issues.length > 0) {
|
|
286
|
+
issueRefs = issues.map(i => `- ${i}`).join('\n');
|
|
287
|
+
}
|
|
288
|
+
} catch {}
|
|
289
|
+
|
|
267
290
|
const template = `# Release Notes: ${name} v${version}
|
|
268
291
|
|
|
269
292
|
**One-line summary of what this release does**
|
|
@@ -279,6 +302,10 @@ Describe the changes. Not a commit list. Explain:
|
|
|
279
302
|
|
|
280
303
|
What problem does this solve? What was broken or missing?
|
|
281
304
|
|
|
305
|
+
## Issues closed
|
|
306
|
+
|
|
307
|
+
${issueRefs || '- #XX (replace with actual issue numbers)'}
|
|
308
|
+
|
|
282
309
|
## How to verify
|
|
283
310
|
|
|
284
311
|
\`\`\`bash
|
|
@@ -495,6 +522,23 @@ export function createGitHubRelease(repoPath, newVersion, notes, currentVersion)
|
|
|
495
522
|
console.warn(` ! GitHub release body is only ${bodyLen} chars. Notes may be truncated.`);
|
|
496
523
|
}
|
|
497
524
|
} catch {}
|
|
525
|
+
|
|
526
|
+
// Auto-close referenced issues
|
|
527
|
+
const issueNums = [...new Set((body.match(/#(\d+)/g) || []).map(m => m.slice(1)))];
|
|
528
|
+
for (const num of issueNums) {
|
|
529
|
+
try {
|
|
530
|
+
// Only close if issue exists and is open on the public repo
|
|
531
|
+
const publicSlug = repoSlug.replace(/-private$/, '');
|
|
532
|
+
execFileSync('gh', [
|
|
533
|
+
'issue', 'close', num,
|
|
534
|
+
'--repo', publicSlug,
|
|
535
|
+
'--comment', `Closed by v${newVersion}. See release notes.`
|
|
536
|
+
], { cwd: repoPath, stdio: 'pipe' });
|
|
537
|
+
console.log(` ✓ Closed #${num} on ${publicSlug}`);
|
|
538
|
+
} catch {
|
|
539
|
+
// Issue doesn't exist on public repo or already closed. Fine.
|
|
540
|
+
}
|
|
541
|
+
}
|
|
498
542
|
} finally {
|
|
499
543
|
try { execFileSync('rm', ['-f', tmpFile]); } catch {}
|
|
500
544
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wipcomputer/universal-installer",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.30",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "The Universal Interface specification for agent-native software. Teaches your AI how to build repos with every interface: CLI, Module, MCP Server, OpenClaw Plugin, Skill, Claude Code Hook.",
|
|
6
6
|
"main": "detect.mjs",
|