@wipcomputer/wip-ai-devops-toolbox 1.9.20

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.
Files changed (146) hide show
  1. package/.license-guard.json +7 -0
  2. package/.publish-skill.json +4 -0
  3. package/CHANGELOG.md +1120 -0
  4. package/CLA.md +19 -0
  5. package/DEV-GUIDE-GENERAL-PUBLIC.md +882 -0
  6. package/LICENSE +52 -0
  7. package/README.md +238 -0
  8. package/SKILL.md +728 -0
  9. package/TECHNICAL.md +282 -0
  10. package/UNIVERSAL-INTERFACE.md +180 -0
  11. package/_trash/RELEASE-NOTES-v1-8-0.md +29 -0
  12. package/_trash/RELEASE-NOTES-v1-8-1.md +7 -0
  13. package/_trash/RELEASE-NOTES-v1-8-2.md +7 -0
  14. package/_trash/RELEASE-NOTES-v1-9-0.md +37 -0
  15. package/_trash/RELEASE-NOTES-v1-9-1.md +38 -0
  16. package/_trash/RELEASE-NOTES-v1-9-10.md +40 -0
  17. package/_trash/RELEASE-NOTES-v1-9-2.md +40 -0
  18. package/_trash/RELEASE-NOTES-v1-9-6.md +72 -0
  19. package/_trash/RELEASE-NOTES-v1-9-7.md +23 -0
  20. package/_trash/RELEASE-NOTES-v1-9-9.md +75 -0
  21. package/_trash/guide 2/DEV-GUIDE.md +487 -0
  22. package/_trash/guide 2/scripts/deploy-public.sh +152 -0
  23. package/package.json +27 -0
  24. package/scripts/SKILL-deploy-public.md +61 -0
  25. package/scripts/SKILL-post-merge-rename.md +47 -0
  26. package/scripts/deploy-public.sh +264 -0
  27. package/scripts/post-merge-rename.sh +205 -0
  28. package/scripts/publish-skill.sh +134 -0
  29. package/tools/deploy-public/LICENSE +52 -0
  30. package/tools/deploy-public/README.md +31 -0
  31. package/tools/deploy-public/SKILL.md +71 -0
  32. package/tools/deploy-public/deploy-public.sh +264 -0
  33. package/tools/deploy-public/package.json +9 -0
  34. package/tools/ldm-jobs/LICENSE +52 -0
  35. package/tools/ldm-jobs/README.md +46 -0
  36. package/tools/ldm-jobs/backup.sh +16 -0
  37. package/tools/ldm-jobs/branch-protect.sh +39 -0
  38. package/tools/ldm-jobs/crystal-capture.sh +19 -0
  39. package/tools/ldm-jobs/setup-shell.sh +27 -0
  40. package/tools/ldm-jobs/visibility-audit.sh +27 -0
  41. package/tools/post-merge-rename/LICENSE +52 -0
  42. package/tools/post-merge-rename/README.md +29 -0
  43. package/tools/post-merge-rename/SKILL.md +57 -0
  44. package/tools/post-merge-rename/package.json +9 -0
  45. package/tools/post-merge-rename/post-merge-rename.sh +122 -0
  46. package/tools/wip-branch-guard/INSTALL.md +41 -0
  47. package/tools/wip-branch-guard/guard.mjs +259 -0
  48. package/tools/wip-branch-guard/package.json +11 -0
  49. package/tools/wip-file-guard/CHANGELOG.md +6 -0
  50. package/tools/wip-file-guard/LICENSE +52 -0
  51. package/tools/wip-file-guard/README.md +113 -0
  52. package/tools/wip-file-guard/REFERENCE.md +86 -0
  53. package/tools/wip-file-guard/SKILL.md +105 -0
  54. package/tools/wip-file-guard/guard.mjs +128 -0
  55. package/tools/wip-file-guard/openclaw.plugin.json +8 -0
  56. package/tools/wip-file-guard/package.json +27 -0
  57. package/tools/wip-file-guard/test.sh +119 -0
  58. package/tools/wip-license-guard/LICENSE +52 -0
  59. package/tools/wip-license-guard/README.md +32 -0
  60. package/tools/wip-license-guard/SKILL.md +65 -0
  61. package/tools/wip-license-guard/cli.mjs +464 -0
  62. package/tools/wip-license-guard/core.mjs +310 -0
  63. package/tools/wip-license-guard/hook.mjs +146 -0
  64. package/tools/wip-license-guard/package.json +15 -0
  65. package/tools/wip-license-hook/CHANGELOG.md +17 -0
  66. package/tools/wip-license-hook/LICENSE +52 -0
  67. package/tools/wip-license-hook/README.md +200 -0
  68. package/tools/wip-license-hook/SKILL.md +111 -0
  69. package/tools/wip-license-hook/dist/cli/index.d.ts +15 -0
  70. package/tools/wip-license-hook/dist/cli/index.js +170 -0
  71. package/tools/wip-license-hook/dist/cli/index.js.map +1 -0
  72. package/tools/wip-license-hook/dist/core/detector.d.ts +12 -0
  73. package/tools/wip-license-hook/dist/core/detector.js +104 -0
  74. package/tools/wip-license-hook/dist/core/detector.js.map +1 -0
  75. package/tools/wip-license-hook/dist/core/index.d.ts +4 -0
  76. package/tools/wip-license-hook/dist/core/index.js +5 -0
  77. package/tools/wip-license-hook/dist/core/index.js.map +1 -0
  78. package/tools/wip-license-hook/dist/core/ledger.d.ts +49 -0
  79. package/tools/wip-license-hook/dist/core/ledger.js +72 -0
  80. package/tools/wip-license-hook/dist/core/ledger.js.map +1 -0
  81. package/tools/wip-license-hook/dist/core/reporter.d.ts +14 -0
  82. package/tools/wip-license-hook/dist/core/reporter.js +227 -0
  83. package/tools/wip-license-hook/dist/core/reporter.js.map +1 -0
  84. package/tools/wip-license-hook/dist/core/scanner.d.ts +39 -0
  85. package/tools/wip-license-hook/dist/core/scanner.js +325 -0
  86. package/tools/wip-license-hook/dist/core/scanner.js.map +1 -0
  87. package/tools/wip-license-hook/hooks/pre-pull.sh +55 -0
  88. package/tools/wip-license-hook/hooks/pre-push.sh +51 -0
  89. package/tools/wip-license-hook/mcp-server.mjs +119 -0
  90. package/tools/wip-license-hook/package-lock.json +54 -0
  91. package/tools/wip-license-hook/package.json +43 -0
  92. package/tools/wip-license-hook/src/cli/index.ts +189 -0
  93. package/tools/wip-license-hook/src/core/detector.ts +130 -0
  94. package/tools/wip-license-hook/src/core/index.ts +4 -0
  95. package/tools/wip-license-hook/src/core/ledger.ts +116 -0
  96. package/tools/wip-license-hook/src/core/reporter.ts +255 -0
  97. package/tools/wip-license-hook/src/core/scanner.ts +367 -0
  98. package/tools/wip-license-hook/tsconfig.json +16 -0
  99. package/tools/wip-readme-format/README.md +49 -0
  100. package/tools/wip-readme-format/SKILL.md +84 -0
  101. package/tools/wip-readme-format/format.mjs +570 -0
  102. package/tools/wip-readme-format/package.json +15 -0
  103. package/tools/wip-release/CHANGELOG.md +42 -0
  104. package/tools/wip-release/LICENSE +52 -0
  105. package/tools/wip-release/README.md +45 -0
  106. package/tools/wip-release/REFERENCE.md +100 -0
  107. package/tools/wip-release/SKILL.md +139 -0
  108. package/tools/wip-release/cli.js +161 -0
  109. package/tools/wip-release/core.mjs +1174 -0
  110. package/tools/wip-release/mcp-server.mjs +109 -0
  111. package/tools/wip-release/package.json +36 -0
  112. package/tools/wip-repo-init/README.md +38 -0
  113. package/tools/wip-repo-init/SKILL.md +77 -0
  114. package/tools/wip-repo-init/init.mjs +142 -0
  115. package/tools/wip-repo-init/package.json +11 -0
  116. package/tools/wip-repo-permissions-hook/LICENSE +52 -0
  117. package/tools/wip-repo-permissions-hook/README.md +86 -0
  118. package/tools/wip-repo-permissions-hook/SKILL.md +73 -0
  119. package/tools/wip-repo-permissions-hook/cli.js +83 -0
  120. package/tools/wip-repo-permissions-hook/core.mjs +122 -0
  121. package/tools/wip-repo-permissions-hook/guard.mjs +64 -0
  122. package/tools/wip-repo-permissions-hook/mcp-server.mjs +92 -0
  123. package/tools/wip-repo-permissions-hook/openclaw.plugin.json +8 -0
  124. package/tools/wip-repo-permissions-hook/package.json +31 -0
  125. package/tools/wip-repos/LICENSE +52 -0
  126. package/tools/wip-repos/README.md +77 -0
  127. package/tools/wip-repos/SKILL.md +80 -0
  128. package/tools/wip-repos/cli.mjs +176 -0
  129. package/tools/wip-repos/core.mjs +290 -0
  130. package/tools/wip-repos/mcp-server.mjs +157 -0
  131. package/tools/wip-repos/package.json +34 -0
  132. package/tools/wip-universal-installer/CHANGELOG.md +57 -0
  133. package/tools/wip-universal-installer/LICENSE +52 -0
  134. package/tools/wip-universal-installer/README.md +81 -0
  135. package/tools/wip-universal-installer/REFERENCE.md +122 -0
  136. package/tools/wip-universal-installer/SKILL.md +87 -0
  137. package/tools/wip-universal-installer/SPEC.md +180 -0
  138. package/tools/wip-universal-installer/detect.mjs +130 -0
  139. package/tools/wip-universal-installer/examples/minimal/README.md +20 -0
  140. package/tools/wip-universal-installer/examples/minimal/SKILL.md +28 -0
  141. package/tools/wip-universal-installer/examples/minimal/cli.mjs +4 -0
  142. package/tools/wip-universal-installer/examples/minimal/core.mjs +8 -0
  143. package/tools/wip-universal-installer/examples/minimal/mcp-server.mjs +27 -0
  144. package/tools/wip-universal-installer/examples/minimal/package.json +12 -0
  145. package/tools/wip-universal-installer/install.js +930 -0
  146. package/tools/wip-universal-installer/package.json +36 -0
@@ -0,0 +1,45 @@
1
+ ###### WIP Computer
2
+
3
+ [![npm](https://img.shields.io/npm/v/@wipcomputer/wip-release)](https://www.npmjs.com/package/@wipcomputer/wip-release) [![CLI / TUI](https://img.shields.io/badge/interface-CLI_/_TUI-black)](https://github.com/wipcomputer/wip-release/blob/main/cli.js) [![OpenClaw Skill](https://img.shields.io/badge/interface-OpenClaw_Skill-black)](https://clawhub.ai/parkertoddbrooks/wip-release) [![Claude Code Skill](https://img.shields.io/badge/interface-Claude_Code_Skill-black)](https://github.com/wipcomputer/wip-release/blob/main/SKILL.md) [![Universal Interface Spec](https://img.shields.io/badge/Universal_Interface_Spec-black?style=flat&color=black)](https://github.com/wipcomputer/wip-universal-installer/blob/main/SPEC.md)
4
+
5
+ # WIP.release
6
+
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.
8
+
9
+ `wip-release` does all of it in one command. It also checks that product docs (dev update, roadmap, readme-first) are up to date before publishing. Patches get a warning. Minor and major releases are blocked until docs are updated.
10
+
11
+ ## Install
12
+
13
+ Open your AI coding tool and say:
14
+
15
+ ```
16
+ Read the REFERENCE.md and SKILL.md at github.com/wipcomputer/wip-release.
17
+ Then explain to me:
18
+ 1. What is this tool?
19
+ 2. What does it do?
20
+ 3. What would it change or fix in our current release process?
21
+
22
+ Then ask me:
23
+ - Do you have more questions?
24
+ - Do you want to integrate it into our system?
25
+ - Do you want to clone it (use as-is) or fork it (so you can contribute back if you find bugs)?
26
+ ```
27
+
28
+ Your agent will read the repo, explain the tool, and walk you through integration interactively.
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
+
32
+ See [REFERENCE.md](REFERENCE.md) for full usage, pipeline steps, flags, auth, and module API.
33
+
34
+ ---
35
+
36
+ ## License
37
+
38
+ ```
39
+ CLI, MCP server, skills MIT (use anywhere, no restrictions)
40
+ Hosted or cloud service use AGPL (network service distribution)
41
+ ```
42
+
43
+ AGPL for personal use is free.
44
+
45
+ Built by Parker Todd Brooks, Lēsa (OpenClaw, Claude Opus 4.6), Claude Code (Claude Opus 4.6).
@@ -0,0 +1,100 @@
1
+ ###### WIP Computer
2
+ # wip-release ... Reference
3
+
4
+ Detailed usage, pipeline steps, flags, auth, and module API.
5
+
6
+ ## Usage
7
+
8
+ Run from inside any repo:
9
+
10
+ ```bash
11
+ wip-release patch # 1.0.0 -> 1.0.1
12
+ wip-release minor # 1.0.0 -> 1.1.0
13
+ wip-release major # 1.0.0 -> 2.0.0
14
+
15
+ wip-release patch --notes="fix auth config" # with changelog note
16
+ wip-release minor --dry-run # preview, no changes
17
+ wip-release patch --no-publish # bump + tag only
18
+ ```
19
+
20
+ ## What It Does
21
+
22
+ ```
23
+ wip-grok: 1.0.0 -> 1.0.1 (patch)
24
+ ────────────────────────────────────────
25
+ ✓ package.json -> 1.0.1
26
+ ✓ SKILL.md -> 1.0.1
27
+ ✓ CHANGELOG.md updated
28
+ ✓ Committed and tagged v1.0.1
29
+ ✓ Pushed to remote
30
+ ✓ Published to npm
31
+ ✓ Published to GitHub Packages
32
+ ✓ GitHub release v1.0.1 created
33
+ ✓ Published to ClawHub
34
+
35
+ Done. wip-grok v1.0.1 released.
36
+ ```
37
+
38
+ ## Pipeline Steps
39
+
40
+ 1. **Bump `package.json`** ... patch, minor, or major
41
+ 2. **Sync `SKILL.md`** ... updates version in YAML frontmatter (if file exists)
42
+ 3. **Update `CHANGELOG.md`** ... prepends new version entry with date and notes
43
+ 4. **Git commit + tag** ... commits changed files, creates `vX.Y.Z` tag
44
+ 5. **Push** ... pushes commit and tag to remote
45
+ 6. **npm publish** ... publishes to npmjs.com (auth via 1Password)
46
+ 7. **GitHub Packages** ... publishes to npm.pkg.github.com
47
+ 8. **GitHub release** ... creates release with changelog notes
48
+ 9. **ClawHub publish** ... publishes skill to ClawHub (if SKILL.md exists)
49
+
50
+ ## Flags
51
+
52
+ | Flag | What |
53
+ |------|------|
54
+ | `--notes="text"` | Changelog entry text |
55
+ | `--dry-run` | Show what would happen, change nothing |
56
+ | `--no-publish` | Bump + tag only, skip npm and GitHub release |
57
+
58
+ ## Auth
59
+
60
+ npm token is fetched from 1Password at publish time. No `.npmrc` files stored. No credentials in repos.
61
+
62
+ Requires:
63
+ - `op` CLI installed and configured
64
+ - 1Password SA token at `~/.openclaw/secrets/op-sa-token`
65
+ - "npm Token" item in "Agent Secrets" vault
66
+ - `gh` CLI authenticated (for GitHub Packages and releases)
67
+ - `clawhub` CLI authenticated (for ClawHub skill publishing)
68
+
69
+ ## As a Module
70
+
71
+ ```javascript
72
+ import { release, detectCurrentVersion, bumpSemver } from '@wipcomputer/wip-release';
73
+
74
+ const current = detectCurrentVersion('/path/to/repo');
75
+ const next = bumpSemver(current, 'minor');
76
+ console.log(`${current} -> ${next}`);
77
+
78
+ await release({
79
+ repoPath: '/path/to/repo',
80
+ level: 'patch',
81
+ notes: 'fix auth',
82
+ dryRun: false,
83
+ noPublish: false,
84
+ });
85
+ ```
86
+
87
+ ## Exports
88
+
89
+ | Function | What |
90
+ |----------|------|
91
+ | `release({ repoPath, level, notes, dryRun, noPublish })` | Full pipeline |
92
+ | `detectCurrentVersion(repoPath)` | Read version from package.json |
93
+ | `bumpSemver(version, level)` | Bump a semver string |
94
+ | `syncSkillVersion(repoPath, newVersion)` | Update SKILL.md frontmatter |
95
+ | `updateChangelog(repoPath, newVersion, notes)` | Prepend to CHANGELOG.md |
96
+ | `publishNpm(repoPath)` | Publish to npmjs.com |
97
+ | `publishGitHubPackages(repoPath)` | Publish to npm.pkg.github.com |
98
+ | `createGitHubRelease(repoPath, newVersion, notes, currentVersion)` | Create GitHub release with rich notes |
99
+ | `buildReleaseNotes(repoPath, currentVersion, newVersion, notes)` | Generate detailed release notes |
100
+ | `publishClawHub(repoPath, newVersion, notes)` | Publish skill to ClawHub |
@@ -0,0 +1,139 @@
1
+ ---
2
+ name: wip-release
3
+ description: One-command release pipeline. Bumps version, updates changelog + SKILL.md, publishes to npm + GitHub.
4
+ license: MIT
5
+ interface: [cli, module, mcp]
6
+ metadata:
7
+ display-name: "Release Pipeline"
8
+ version: "1.2.4"
9
+ homepage: "https://github.com/wipcomputer/wip-release"
10
+ author: "Parker Todd Brooks"
11
+ category: dev-tools
12
+ capabilities:
13
+ - version-bump
14
+ - changelog-update
15
+ - skill-sync
16
+ - npm-publish
17
+ - github-release
18
+ requires:
19
+ bins: [git, npm, gh, op, clawhub]
20
+ secrets:
21
+ - path: ~/.openclaw/secrets/op-sa-token
22
+ description: 1Password service account token
23
+ - vault: Agent Secrets
24
+ item: npm Token
25
+ description: npm publish token
26
+ openclaw:
27
+ requires:
28
+ bins: [git, npm, gh, op]
29
+ install:
30
+ - id: node
31
+ kind: node
32
+ package: "@wipcomputer/wip-release"
33
+ bins: [wip-release]
34
+ label: "Install via npm"
35
+ emoji: "🚀"
36
+ compatibility: Requires git, npm, gh, op (1Password CLI). Node.js 18+.
37
+ ---
38
+
39
+ # wip-release
40
+
41
+ Local release pipeline. One command bumps version, updates all docs, publishes everywhere.
42
+
43
+ ## When to Use This Skill
44
+
45
+ **Use wip-release for:**
46
+ - Releasing a new version of any @wipcomputer package
47
+ - After merging a PR to main and you need to publish
48
+ - Bumping version + changelog + SKILL.md in one step
49
+
50
+ **Use --dry-run for:**
51
+ - Previewing what a release would do before committing
52
+
53
+ **Use --no-publish for:**
54
+ - Bumping version and tagging without publishing to registries
55
+
56
+ ### Do NOT Use For
57
+
58
+ - Pre-release / alpha versions (not yet supported)
59
+ - Repos without a package.json
60
+
61
+ ## API Reference
62
+
63
+ ### CLI
64
+
65
+ ```bash
66
+ wip-release patch --notes="fix X" # full pipeline
67
+ wip-release minor --dry-run # preview only
68
+ wip-release major --no-publish # bump + tag only
69
+ wip-release patch --skip-product-check # skip product docs gate
70
+ ```
71
+
72
+ ### Product Docs Gate
73
+
74
+ wip-release checks that product docs (dev update, roadmap, readme-first) were updated before publishing. Only runs on repos with an `ai/` directory.
75
+
76
+ - **patch**: warns if product docs are stale (non-blocking)
77
+ - **minor/major**: blocks release until product docs are updated
78
+ - **--skip-product-check**: bypasses the gate
79
+
80
+ Checks:
81
+ 1. `ai/dev-updates/` has a file modified since the last release tag
82
+ 2. `ai/product/plans-prds/roadmap.md` was modified since last release
83
+ 3. `ai/product/readme-first-product.md` was modified since last release
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:** Add `.publish-skill.json` to your repo root:
90
+ ```json
91
+ { "name": "wip-my-tool", "websiteRepo": "/path/to/website-repo" }
92
+ ```
93
+
94
+ **How it works:**
95
+ 1. If SKILL.md exists and a website repo is configured, copies SKILL.md to `{website}/wip.computer/install/{name}.txt`
96
+ 2. Runs `deploy.sh` in the website repo to push live
97
+ 3. Non-blocking: if deploy fails, the release still succeeds
98
+
99
+ **Website repo resolution:**
100
+ 1. `.publish-skill.json` `websiteRepo` field (per-repo)
101
+ 2. `WIP_WEBSITE_REPO` env var (global fallback)
102
+
103
+ **Name resolution (first match wins):**
104
+ 1. `.publish-skill.json` `name` field
105
+ 2. `package.json` name (with `@scope/` prefix stripped)
106
+ 3. Directory name (with `-private` suffix stripped)
107
+
108
+ ### Module
109
+
110
+ ```javascript
111
+ import { release, detectCurrentVersion, bumpSemver, syncSkillVersion } from '@wipcomputer/wip-release';
112
+
113
+ await release({ repoPath: '.', level: 'patch', notes: 'fix', dryRun: false, noPublish: false });
114
+ ```
115
+
116
+ ## Troubleshooting
117
+
118
+ ### "Could not fetch npm token from 1Password"
119
+ Check that `~/.openclaw/secrets/op-sa-token` exists and `op` CLI is installed.
120
+
121
+ ### "Push failed"
122
+ Branch protection may prevent direct pushes. Make sure you're on main after merging a PR.
123
+
124
+ ### SKILL.md not updated
125
+ Only updates if the file has a YAML frontmatter `version:` field between `---` markers.
126
+
127
+ ## MCP
128
+
129
+ Tools: `release`, `release_status`
130
+
131
+ Add to `.mcp.json`:
132
+ ```json
133
+ {
134
+ "wip-release": {
135
+ "command": "node",
136
+ "args": ["/path/to/tools/wip-release/mcp-server.mjs"]
137
+ }
138
+ }
139
+ ```
@@ -0,0 +1,161 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * wip-release/cli.mjs
5
+ * Release tool CLI. Bumps version, updates docs, publishes.
6
+ */
7
+
8
+ import { release, detectCurrentVersion } from './core.mjs';
9
+
10
+ const args = process.argv.slice(2);
11
+ const level = args.find(a => ['patch', 'minor', 'major'].includes(a));
12
+
13
+ function flag(name) {
14
+ const prefix = `--${name}=`;
15
+ const found = args.find(a => a.startsWith(prefix));
16
+ return found ? found.slice(prefix.length) : null;
17
+ }
18
+
19
+ const dryRun = args.includes('--dry-run');
20
+ const noPublish = args.includes('--no-publish');
21
+ const skipProductCheck = args.includes('--skip-product-check');
22
+ const skipStaleCheck = args.includes('--skip-stale-check');
23
+ const skipWorktreeCheck = args.includes('--skip-worktree-check');
24
+ const notesFilePath = flag('notes-file');
25
+ let notes = flag('notes');
26
+ // Bug fix #121: use strict check, not truthiness. --notes="" is empty, not absent.
27
+ let notesSource = (notes !== null && notes !== undefined && notes !== '') ? 'flag' : 'none';
28
+
29
+ // Release notes priority (highest wins):
30
+ // 1. --notes-file=path Explicit file path (always wins)
31
+ // 2. RELEASE-NOTES-v{ver}.md In repo root (always wins over --notes flag)
32
+ // 3. ai/dev-updates/YYYY-MM-DD* Today's dev update (wins over --notes flag if longer)
33
+ // 4. --notes="text" Flag fallback (only if nothing better exists)
34
+ //
35
+ // Rule: written release notes on disk ALWAYS beat a CLI one-liner.
36
+ // The --notes flag is a fallback, not an override.
37
+ {
38
+ const { readFileSync, existsSync } = await import('node:fs');
39
+ const { resolve, join } = await import('node:path');
40
+ const flagNotes = notes; // save original flag value for fallback
41
+
42
+ if (notesFilePath) {
43
+ // 1. Explicit --notes-file (highest priority)
44
+ const resolved = resolve(notesFilePath);
45
+ if (!existsSync(resolved)) {
46
+ console.error(` ✗ Notes file not found: ${resolved}`);
47
+ process.exit(1);
48
+ }
49
+ notes = readFileSync(resolved, 'utf8').trim();
50
+ notesSource = 'file';
51
+ } else if (level) {
52
+ // 2. Auto-detect RELEASE-NOTES-v{version}.md (ALWAYS checks, even if --notes provided)
53
+ try {
54
+ const { detectCurrentVersion, bumpSemver } = await import('./core.mjs');
55
+ const cwd = process.cwd();
56
+ const currentVersion = detectCurrentVersion(cwd);
57
+ const newVersion = bumpSemver(currentVersion, level);
58
+ const dashed = newVersion.replace(/\./g, '-');
59
+ const autoFile = join(cwd, `RELEASE-NOTES-v${dashed}.md`);
60
+ if (existsSync(autoFile)) {
61
+ const fileContent = readFileSync(autoFile, 'utf8').trim();
62
+ if (flagNotes && flagNotes !== fileContent) {
63
+ console.log(` ! --notes flag ignored: RELEASE-NOTES-v${dashed}.md takes priority`);
64
+ }
65
+ notes = fileContent;
66
+ notesSource = 'file';
67
+ console.log(` ✓ Found RELEASE-NOTES-v${dashed}.md`);
68
+ }
69
+ } catch {}
70
+ }
71
+
72
+ // 3. Auto-detect dev update from ai/dev-updates/ (wins over --notes flag if longer)
73
+ if (level && (!notes || (notesSource === 'flag' && notes.length < 200))) {
74
+ try {
75
+ const { readdirSync } = await import('node:fs');
76
+ const devUpdatesDir = join(process.cwd(), 'ai', 'dev-updates');
77
+ if (existsSync(devUpdatesDir)) {
78
+ const today = new Date().toISOString().split('T')[0];
79
+ const todayFiles = readdirSync(devUpdatesDir)
80
+ .filter(f => f.startsWith(today) && f.endsWith('.md'))
81
+ .sort()
82
+ .reverse();
83
+
84
+ if (todayFiles.length > 0) {
85
+ const devUpdatePath = join(devUpdatesDir, todayFiles[0]);
86
+ const devUpdateContent = readFileSync(devUpdatePath, 'utf8').trim();
87
+ if (devUpdateContent.length > (notes || '').length) {
88
+ if (flagNotes) {
89
+ console.log(` ! --notes flag ignored: dev update takes priority`);
90
+ }
91
+ notes = devUpdateContent;
92
+ notesSource = 'dev-update';
93
+ console.log(` ✓ Found dev update: ai/dev-updates/${todayFiles[0]}`);
94
+ }
95
+ }
96
+ }
97
+ } catch {}
98
+ }
99
+ }
100
+
101
+ if (!level || args.includes('--help') || args.includes('-h')) {
102
+ const cwd = process.cwd();
103
+ let current = '';
104
+ try { current = ` (current: ${detectCurrentVersion(cwd)})`; } catch {}
105
+
106
+ console.log(`wip-release ... local release tool${current}
107
+
108
+ Usage:
109
+ wip-release patch 1.0.0 -> 1.0.1
110
+ wip-release minor 1.0.0 -> 1.1.0
111
+ wip-release major 1.0.0 -> 2.0.0
112
+
113
+ Flags:
114
+ --notes="description" Release narrative (what was built and why)
115
+ --notes-file=path Read release narrative from a markdown file
116
+ --dry-run Show what would happen, change nothing
117
+ --no-publish Bump + tag only, skip npm/GitHub
118
+ --skip-product-check Skip product docs check (dev update, roadmap, readme-first)
119
+ --skip-stale-check Skip stale remote branch check
120
+ --skip-worktree-check Skip worktree guard (allow release from worktree)
121
+
122
+ Release notes (highest priority wins, files ALWAYS beat --notes flag):
123
+ 1. --notes-file=path Explicit file path (always wins)
124
+ 2. RELEASE-NOTES-v{ver}.md In repo root (wins over --notes)
125
+ 3. ai/dev-updates/YYYY-MM-DD* Today's dev update (wins over --notes if longer)
126
+ 4. --notes="text" Fallback only (use for repos without release notes files)
127
+ Written notes on disk always take priority over a CLI one-liner.
128
+
129
+ Skill publish to website:
130
+ Add .publish-skill.json to repo root: { "name": "my-tool" }
131
+ Set WIP_WEBSITE_REPO env var to your website repo path.
132
+ After release, SKILL.md is copied to {website}/wip.computer/install/{name}.txt
133
+ and deploy.sh is run to push to VPS.
134
+
135
+ Pipeline:
136
+ 1. Bump package.json version
137
+ 2. Sync SKILL.md version (if exists)
138
+ 3. Update CHANGELOG.md
139
+ 4. Git commit + tag
140
+ 5. Push to remote
141
+ 6. npm publish (via 1Password)
142
+ 7. GitHub Packages publish
143
+ 8. GitHub release create
144
+ 9. Publish SKILL.md to website (if configured)`);
145
+ process.exit(level ? 0 : 1);
146
+ }
147
+
148
+ release({
149
+ repoPath: process.cwd(),
150
+ level,
151
+ notes,
152
+ notesSource,
153
+ dryRun,
154
+ noPublish,
155
+ skipProductCheck,
156
+ skipStaleCheck,
157
+ skipWorktreeCheck,
158
+ }).catch(err => {
159
+ console.error(` ✗ ${err.message}`);
160
+ process.exit(1);
161
+ });