@wipcomputer/wip-release 1.1.1 → 1.2.2
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 +10 -0
- package/README.md +6 -1
- package/REFERENCE.md +4 -0
- package/SKILL.md +10 -3
- package/core.mjs +74 -31
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
## 1.2.2 (2026-02-21)
|
|
8
|
+
|
|
9
|
+
Fix ClawHub display name and slug detection. Harden command injection fix.
|
|
10
|
+
|
|
11
|
+
## 1.2.0 (2026-02-21)
|
|
12
|
+
|
|
13
|
+
Add ClawHub publish as step 9 in release pipeline. Fix command injection by replacing execSync with execFileSync argument arrays. Declare required binaries and secrets in SKILL.md metadata.
|
|
14
|
+
|
|
5
15
|
## 1.1.1 (2026-02-21)
|
|
6
16
|
|
|
7
17
|
Fix npm bin entry: rename cli.mjs to cli.js
|
package/README.md
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
###### WIP Computer
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@wipcomputer/wip-release) [](https://github.com/wipcomputer/wip-release/blob/main/cli.js) [](https://clawhub.ai/parkertoddbrooks/wip-release) [](https://github.com/wipcomputer/wip-release/blob/main/SKILL.md) [](https://github.com/wipcomputer/wip-universal-installer/blob/main/SPEC.md)
|
|
4
|
+
|
|
5
|
+
# WIP.release
|
|
3
6
|
|
|
4
7
|
You ship a fix. Now you have to bump package.json, update CHANGELOG.md, sync the version in SKILL.md, commit, tag, push, publish to npm, publish to GitHub Packages, and create a GitHub release. Every time. Miss a step and versions drift.
|
|
5
8
|
|
|
@@ -24,6 +27,8 @@ Then ask me:
|
|
|
24
27
|
|
|
25
28
|
Your agent will read the repo, explain the tool, and walk you through integration interactively.
|
|
26
29
|
|
|
30
|
+
Also see **[wip-file-guard](https://github.com/wipcomputer/wip-file-guard)** ... the lock for the repo. Blocks AI agents from overwriting your critical files.
|
|
31
|
+
|
|
27
32
|
See [REFERENCE.md](REFERENCE.md) for full usage, pipeline steps, flags, auth, and module API.
|
|
28
33
|
|
|
29
34
|
---
|
package/REFERENCE.md
CHANGED
|
@@ -30,6 +30,7 @@ wip-release patch --no-publish # bump + tag only
|
|
|
30
30
|
✓ Published to npm
|
|
31
31
|
✓ Published to GitHub Packages
|
|
32
32
|
✓ GitHub release v1.0.1 created
|
|
33
|
+
✓ Published to ClawHub
|
|
33
34
|
|
|
34
35
|
Done. wip-grok v1.0.1 released.
|
|
35
36
|
```
|
|
@@ -44,6 +45,7 @@ wip-release patch --no-publish # bump + tag only
|
|
|
44
45
|
6. **npm publish** ... publishes to npmjs.com (auth via 1Password)
|
|
45
46
|
7. **GitHub Packages** ... publishes to npm.pkg.github.com
|
|
46
47
|
8. **GitHub release** ... creates release with changelog notes
|
|
48
|
+
9. **ClawHub publish** ... publishes skill to ClawHub (if SKILL.md exists)
|
|
47
49
|
|
|
48
50
|
## Flags
|
|
49
51
|
|
|
@@ -62,6 +64,7 @@ Requires:
|
|
|
62
64
|
- 1Password SA token at `~/.openclaw/secrets/op-sa-token`
|
|
63
65
|
- "npm Token" item in "Agent Secrets" vault
|
|
64
66
|
- `gh` CLI authenticated (for GitHub Packages and releases)
|
|
67
|
+
- `clawhub` CLI authenticated (for ClawHub skill publishing)
|
|
65
68
|
|
|
66
69
|
## As a Module
|
|
67
70
|
|
|
@@ -94,3 +97,4 @@ await release({
|
|
|
94
97
|
| `publishGitHubPackages(repoPath)` | Publish to npm.pkg.github.com |
|
|
95
98
|
| `createGitHubRelease(repoPath, newVersion, notes, currentVersion)` | Create GitHub release with rich notes |
|
|
96
99
|
| `buildReleaseNotes(repoPath, currentVersion, newVersion, notes)` | Generate detailed release notes |
|
|
100
|
+
| `publishClawHub(repoPath, newVersion, notes)` | Publish skill to ClawHub |
|
package/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
-
name:
|
|
3
|
-
version: 1.
|
|
2
|
+
name: WIP.release
|
|
3
|
+
version: 1.2.2
|
|
4
4
|
description: Local release tool. Bumps version, updates changelog + SKILL.md, publishes to npm + GitHub.
|
|
5
5
|
homepage: https://github.com/wipcomputer/wip-release
|
|
6
6
|
metadata:
|
|
@@ -13,6 +13,14 @@ metadata:
|
|
|
13
13
|
- github-release
|
|
14
14
|
dependencies: []
|
|
15
15
|
interface: CLI
|
|
16
|
+
requires:
|
|
17
|
+
binaries: [git, npm, gh, op, clawhub]
|
|
18
|
+
secrets:
|
|
19
|
+
- path: ~/.openclaw/secrets/op-sa-token
|
|
20
|
+
description: 1Password service account token
|
|
21
|
+
- vault: Agent Secrets
|
|
22
|
+
item: npm Token
|
|
23
|
+
description: npm publish token
|
|
16
24
|
openclaw:
|
|
17
25
|
emoji: "🚀"
|
|
18
26
|
install:
|
|
@@ -42,7 +50,6 @@ Local release pipeline. One command bumps version, updates all docs, publishes e
|
|
|
42
50
|
|
|
43
51
|
- Pre-release / alpha versions (not yet supported)
|
|
44
52
|
- Repos without a package.json
|
|
45
|
-
- Publishing to ClawHub (separate step)
|
|
46
53
|
|
|
47
54
|
## API Reference
|
|
48
55
|
|
package/core.mjs
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Zero dependencies.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { execSync } from 'node:child_process';
|
|
8
|
+
import { execSync, execFileSync } from 'node:child_process';
|
|
9
9
|
import { readFileSync, writeFileSync, existsSync } from 'node:fs';
|
|
10
10
|
import { join, basename } from 'node:path';
|
|
11
11
|
|
|
@@ -97,9 +97,15 @@ export function updateChangelog(repoPath, newVersion, notes) {
|
|
|
97
97
|
|
|
98
98
|
function gitCommitAndTag(repoPath, newVersion, notes) {
|
|
99
99
|
const msg = `v${newVersion}: ${notes || 'Release'}`;
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
100
|
+
// Stage known files (ignore missing ones)
|
|
101
|
+
for (const f of ['package.json', 'CHANGELOG.md', 'SKILL.md']) {
|
|
102
|
+
if (existsSync(join(repoPath, f))) {
|
|
103
|
+
execFileSync('git', ['add', f], { cwd: repoPath, stdio: 'pipe' });
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Use execFileSync to avoid shell injection via notes
|
|
107
|
+
execFileSync('git', ['commit', '-m', msg], { cwd: repoPath, stdio: 'pipe' });
|
|
108
|
+
execFileSync('git', ['tag', `v${newVersion}`], { cwd: repoPath, stdio: 'pipe' });
|
|
103
109
|
}
|
|
104
110
|
|
|
105
111
|
// ── Publish ─────────────────────────────────────────────────────────
|
|
@@ -109,10 +115,10 @@ function gitCommitAndTag(repoPath, newVersion, notes) {
|
|
|
109
115
|
*/
|
|
110
116
|
export function publishNpm(repoPath) {
|
|
111
117
|
const token = getNpmToken();
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
{
|
|
115
|
-
);
|
|
118
|
+
execFileSync('npm', [
|
|
119
|
+
'publish', '--access', 'public',
|
|
120
|
+
`--//registry.npmjs.org/:_authToken=${token}`
|
|
121
|
+
], { cwd: repoPath, stdio: 'inherit' });
|
|
116
122
|
}
|
|
117
123
|
|
|
118
124
|
/**
|
|
@@ -120,10 +126,11 @@ export function publishNpm(repoPath) {
|
|
|
120
126
|
*/
|
|
121
127
|
export function publishGitHubPackages(repoPath) {
|
|
122
128
|
const ghToken = execSync('gh auth token', { encoding: 'utf8' }).trim();
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
129
|
+
execFileSync('npm', [
|
|
130
|
+
'publish',
|
|
131
|
+
'--registry', 'https://npm.pkg.github.com',
|
|
132
|
+
`--//npm.pkg.github.com/:_authToken=${ghToken}`
|
|
133
|
+
], { cwd: repoPath, stdio: 'inherit' });
|
|
127
134
|
}
|
|
128
135
|
|
|
129
136
|
/**
|
|
@@ -145,17 +152,15 @@ export function buildReleaseNotes(repoPath, currentVersion, newVersion, notes) {
|
|
|
145
152
|
const prevTag = `v${currentVersion}`;
|
|
146
153
|
let commits = '';
|
|
147
154
|
try {
|
|
148
|
-
commits =
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
).trim();
|
|
155
|
+
commits = execFileSync('git', [
|
|
156
|
+
'log', `${prevTag}..HEAD`, '--pretty=format:- %s (%h)'
|
|
157
|
+
], { cwd: repoPath, encoding: 'utf8' }).trim();
|
|
152
158
|
} catch {
|
|
153
159
|
// No previous tag ... show all commits on branch
|
|
154
160
|
try {
|
|
155
|
-
commits =
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
).trim();
|
|
161
|
+
commits = execFileSync('git', [
|
|
162
|
+
'log', '--pretty=format:- %s (%h)', '-20'
|
|
163
|
+
], { cwd: repoPath, encoding: 'utf8' }).trim();
|
|
159
164
|
} catch {}
|
|
160
165
|
}
|
|
161
166
|
|
|
@@ -168,10 +173,9 @@ export function buildReleaseNotes(repoPath, currentVersion, newVersion, notes) {
|
|
|
168
173
|
// Files changed
|
|
169
174
|
let filesChanged = '';
|
|
170
175
|
try {
|
|
171
|
-
filesChanged =
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
).trim();
|
|
176
|
+
filesChanged = execFileSync('git', [
|
|
177
|
+
'diff', `${prevTag}..HEAD`, '--stat'
|
|
178
|
+
], { cwd: repoPath, encoding: 'utf8' }).trim();
|
|
175
179
|
} catch {}
|
|
176
180
|
|
|
177
181
|
if (filesChanged) {
|
|
@@ -216,15 +220,36 @@ export function createGitHubRelease(repoPath, newVersion, notes, currentVersion)
|
|
|
216
220
|
writeFileSync(tmpFile, body);
|
|
217
221
|
|
|
218
222
|
try {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
+
execFileSync('gh', [
|
|
224
|
+
'release', 'create', `v${newVersion}`,
|
|
225
|
+
'--title', `v${newVersion}`,
|
|
226
|
+
'--notes-file', '.release-notes-tmp.md',
|
|
227
|
+
'--repo', repoSlug
|
|
228
|
+
], { cwd: repoPath, stdio: 'inherit' });
|
|
223
229
|
} finally {
|
|
224
|
-
try {
|
|
230
|
+
try { execFileSync('rm', ['-f', tmpFile]); } catch {}
|
|
225
231
|
}
|
|
226
232
|
}
|
|
227
233
|
|
|
234
|
+
/**
|
|
235
|
+
* Publish skill to ClawHub.
|
|
236
|
+
*/
|
|
237
|
+
export function publishClawHub(repoPath, newVersion, notes) {
|
|
238
|
+
const skillPath = join(repoPath, 'SKILL.md');
|
|
239
|
+
if (!existsSync(skillPath)) return false;
|
|
240
|
+
|
|
241
|
+
const slug = detectSkillSlug(repoPath);
|
|
242
|
+
const changelog = notes || 'Release.';
|
|
243
|
+
|
|
244
|
+
execFileSync('clawhub', [
|
|
245
|
+
'publish', repoPath,
|
|
246
|
+
'--slug', slug,
|
|
247
|
+
'--version', newVersion,
|
|
248
|
+
'--changelog', changelog
|
|
249
|
+
], { cwd: repoPath, stdio: 'inherit' });
|
|
250
|
+
return true;
|
|
251
|
+
}
|
|
252
|
+
|
|
228
253
|
// ── Helpers ──────────────────────────────────────────────────────────
|
|
229
254
|
|
|
230
255
|
function getNpmToken() {
|
|
@@ -238,6 +263,12 @@ function getNpmToken() {
|
|
|
238
263
|
}
|
|
239
264
|
}
|
|
240
265
|
|
|
266
|
+
function detectSkillSlug(repoPath) {
|
|
267
|
+
// Slug must be lowercase and url-safe. Use directory name, not SKILL.md name
|
|
268
|
+
// (SKILL.md name can be display-formatted like "WIP.release").
|
|
269
|
+
return basename(repoPath).toLowerCase();
|
|
270
|
+
}
|
|
271
|
+
|
|
241
272
|
function detectRepoSlug(repoPath) {
|
|
242
273
|
try {
|
|
243
274
|
const url = execSync('git remote get-url origin', { cwd: repoPath, encoding: 'utf8' }).trim();
|
|
@@ -265,15 +296,16 @@ export async function release({ repoPath, level, notes, dryRun, noPublish }) {
|
|
|
265
296
|
console.log(` ${'─'.repeat(40)}`);
|
|
266
297
|
|
|
267
298
|
if (dryRun) {
|
|
299
|
+
const hasSkill = existsSync(join(repoPath, 'SKILL.md'));
|
|
268
300
|
console.log(` [dry run] Would bump package.json to ${newVersion}`);
|
|
269
|
-
|
|
270
|
-
if (existsSync(skillPath)) console.log(` [dry run] Would update SKILL.md version`);
|
|
301
|
+
if (hasSkill) console.log(` [dry run] Would update SKILL.md version`);
|
|
271
302
|
console.log(` [dry run] Would update CHANGELOG.md`);
|
|
272
303
|
console.log(` [dry run] Would commit and tag v${newVersion}`);
|
|
273
304
|
if (!noPublish) {
|
|
274
305
|
console.log(` [dry run] Would publish to npm (@wipcomputer scope)`);
|
|
275
306
|
console.log(` [dry run] Would publish to GitHub Packages`);
|
|
276
307
|
console.log(` [dry run] Would create GitHub release v${newVersion}`);
|
|
308
|
+
if (hasSkill) console.log(` [dry run] Would publish to ClawHub`);
|
|
277
309
|
}
|
|
278
310
|
console.log('');
|
|
279
311
|
console.log(` Dry run complete. No changes made.`);
|
|
@@ -330,6 +362,17 @@ export async function release({ repoPath, level, notes, dryRun, noPublish }) {
|
|
|
330
362
|
} catch (e) {
|
|
331
363
|
console.log(` ✗ GitHub release failed: ${e.message}`);
|
|
332
364
|
}
|
|
365
|
+
|
|
366
|
+
// 9. ClawHub skill publish
|
|
367
|
+
const skillPath = join(repoPath, 'SKILL.md');
|
|
368
|
+
if (existsSync(skillPath)) {
|
|
369
|
+
try {
|
|
370
|
+
publishClawHub(repoPath, newVersion, notes);
|
|
371
|
+
console.log(` ✓ Published to ClawHub`);
|
|
372
|
+
} catch (e) {
|
|
373
|
+
console.log(` ✗ ClawHub publish failed: ${e.message}`);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
333
376
|
}
|
|
334
377
|
|
|
335
378
|
console.log('');
|