[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6HZQ2D41X8YV1DQBJXDF4PF":3,"skill-same:01M6HZQ2D41X8YV1DQBJXDF4PF":45},{"skillNo":4,"name":5,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":6,"repositoryNo":11,"starsCount":12,"licenseSpdxId":13,"licenseFileUrl":6,"sourceHtmlUrl":14,"categories":15,"keywords":16,"publishedAt":20,"linkOnly":21,"markdownContent":22,"markdownBody":22,"frontMatter":23,"refName":24,"commitSha":25,"skillDirectory":26,"forksCount":12,"repositoryHtmlUrl":27,"repositoryHomepageUrl":28,"ownerHtmlUrl":29,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":30,"install":31,"resources":44},"01M6HZQ2D41X8YV1DQBJXDF4PF","make-release",null,"Tatsh\u002Fwiswa","Tatsh","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F724848?v=4","01M6HZPX9FT9AY6CK9CWK82S26","01M6HZPXE07J6YKYW0KJFNFFRR",0,"MIT","https:\u002F\u002Fgithub.com\u002FTatsh\u002Fwiswa\u002Fblob\u002Fmaster\u002F.claude\u002Fskills\u002Fmake-release\u002FSKILL.md",[],[17,18,19],"release","make","make release","2026-11-10 10:12:30",false,"# Release\n\nPrepare and publish a new release for the wiswa project.\n\nYou manage the release process: update the changelog, determine the version bump, run pre-commit\nchecks, bump the version, and push, and align GitHub release notes\nwith the changelog.\n\n## Workflow\n\n1. **Review changes since last tag.** Run `git log $(git describe --tags --abbrev=0)..HEAD\n--oneline` to see all commits since the last release.\n\n1. **Update CHANGELOG.md.** Add entries under `[Unreleased]` if not already present. Use the\n   appropriate sections: Added, Changed, Fixed, Removed.\n\n1. **Determine the version bump** based on Semantic Versioning:\n   - **patch**: bug fixes, dependency updates, documentation changes.\n   - **minor**: new features, new commands, new public API additions.\n   - **major**: breaking changes to public API, removed commands\u002Ffunctions.\n\n1. **Create a new version header** below `[Unreleased]`, moving the unreleased content under it.\n   Format: `## [X.Y.Z] - YYYY-MM-DD`. Leave `[Unreleased]` empty above it.\n\n1. **Bring the security policy's supported versions up to date.** `SECURITY.md` is generated from\n   `security_policy_supported_versions` in `.wiswa.jsonnet`, so edit that setting and the rendered\n   table in the same commit. Editing `SECURITY.md` alone is reverted by the next regen. When NEW\n   opens a series the table does not already list, replace the stale entry with the new one (a\n   `0.5.1` release is covered by `0.5.x`); a patch inside a series already listed does not need a\n   change.\n   Record which series you dropped. Dropping one ends its support.\n\n1. **Launch agents in parallel** before bumping:\n   - **copy-editor** - to fix prose in the changelog entries.\n   - **qa-fixer** - to format and fix any lint\u002Fspelling issues.\n\n1. **Run the test suite with coverage.** Run `yarn test:cov`. Every test must pass and total\n   coverage must reach 100%, unless `[tool.coverage.report]` in `pyproject.toml` sets\n   `fail_under`, which is then the threshold. Close a shortfall by writing the missing tests.\n\n1. **Confirm the last CI runs passed.** Nothing is released on top of a red\n   `master`. List the project's workflows with `gh workflow list`, and for\n   each one that runs on pushes rather than only on tags, read its most recent run:\n   `gh run list --workflow \u003Cfile> --branch master --limit 1`. This covers\n   the QA and test workflows and the packaging ones the project has - Flatpak, Snap, AppImage,\n   and PyInstaller. Every conclusion must be `success`; read a failure with\n   `gh run view \u003Crun-id> --log-failed` and fix it before releasing. A workflow that has never run\n   is not a failure.\n\n   Compare the head SHA of the newest **tests** run against `git rev-parse HEAD`. When they\n   differ, the commits about to be released were never tested; say so, and let the user decide\n   whether to push and wait before continuing.\n\n1. **Run `pre-commit run -a` outside the sandbox** to ensure all hooks pass. The hooks write\n   across the working tree, which the sandbox's read-only mount blocks. Fix any issues before\n   proceeding.\n\n1. **Record the current HEAD** before bumping: `git rev-parse HEAD` (save this as `PRE_BUMP_REF`).\n\n1. **Pre-scan `version_files` for collision risk.** Note OLD (the current\n   `[tool.commitizen].version`) and NEW (the post-bump version for the selected increment).\n   For each entry in `[tool.commitizen].version_files`, run\n   `rg --fixed-strings --line-number 'OLD' \u003Cfile>` (or `grep -nF 'OLD' \u003Cfile>`). Exactly one\n   match is the canonical version field cz is meant to bump. Every other match is a\n   **collision candidate**: cz uses plain string substitution, so any substring `OLD` in the\n   file is replaced with `NEW`, regardless of context. Save the candidate list (file, line\n   number, full pre-bump line) so the matches can be reverted after the bump. The classic\n   example: OLD `0.0.0` and NEW `0.0.1` rewrite a `\"some-dep\": \"10.0.0\"` line into\n   `\"some-dep\": \"10.0.1\"` even though `10.0.0` is unrelated to the project version.\n\n1. **Run `cz bump --files-only --increment {MAJOR,MINOR,PATCH}`** with the appropriate increment.\n   This only updates version strings in files without committing or tagging. Never pass\n   `--changelog` or `-ch` to `cz bump`. When the repository has **no existing tags** (the first\n   release), also pass `--yes`: with no tag to compare against, cz asks \"Is this the first tag\n   created?\" interactively, and a non-interactive shell aborts with `EOFError` before writing\n   anything. `--yes` answers that prompt truthfully and changes nothing else about the\n   substitution. If `cz bump` fails for any other reason:\n   1. **Restore the repository** to the pre-bump state: `git checkout -- .`\n   1. **Stop work immediately and alert the user.** Do not attempt to work around the failure.\n\n1. **Revert accidental bump collisions.** For every collision candidate recorded in the\n   pre-scan, open the same `file:line` and confirm whether cz rewrote a substring inside an\n   unrelated value (for example `10.0.0` → `10.0.1`). If so, restore that line to its\n   pre-bump content; leave the canonical version-field match in its post-bump state. If you\n   are unsure whether a change is intended, prefer to revert and stop with a report rather\n   than ship the bump with a corrupted dependency or transitive version.\n\n1. **Set the release date in `CITATION.cff`** if the file exists. Replace the `date-released`\n   value with today's date in `YYYY-MM-DD` form. `cz bump` does not update this field.\n\n1. **Verify version-bound and source-bound files.** Stop and report if any check fails:\n   - **`CITATION.cff`** if present: `version` matches `NEW` and `date-released` equals today's\n     date. If `cz bump` did not update `version`, the file is missing from\n     `[tool.commitizen].version_files` - add it in `.wiswa.jsonnet` and restart the bump.\n   - **Flatpak manifest** (`flatpak\u002F**`, any `*.flatpak.{json,yaml}`) if present: every version\n     reference is updated to `NEW` (cz must drive this through `version_files` - fix the\n     configuration as above if it did not), and every `sources` entry pointing at this\n     repository uses `tag: vNEW` with a fresh `commit:` SHA where applicable. No local `path:`\n     sources, no moving branch.\n   - **Snapcraft** (`snap\u002Fsnapcraft.yaml` or top-level `snapcraft.yaml`) if present: every\n     version reference and every part's `source-tag:` equal `NEW` \u002F `vNEW`. `source:` points at\n     the remote repository, never a local path. Same `version_files` rule for cz.\n\n1. **Run `uv lock`** to update `uv.lock` with the new version.\n\n1. **Generate and verify man pages.** Run `yarn gen-manpage` and then `git add man\u002F`. Confirm\n   the embedded `.TH` line shows version `NEW` and today's date; if not, stop and report.\n\n1. **Commit the version bump outside the sandbox.** Stage all changed files and commit with\n   `git commit -S -s -m 'bump: vOLD → vNEW'` (replace\n   OLD\u002FNEW with actual versions). Run outside the sandbox because the pre-commit hooks invoked\n   by the commit need to write across the working tree.\n\n1. **Create a signed tag.** Run\n   `git tag -s vNEW -m 'vNEW'` (replace NEW with the\n   new version).\n\n1. **Push the commit and tag.** Run `git push && git push --tags`.\n\n1. **Update GitHub release notes** using `gh` (authenticated for this repository). After the tag\n   is on the remote, automation may create the GitHub **Release** record later or as a **draft**;\n   do not skip this step when a draft exists.\n   - **Wait for the release:** Poll until `gh release view vNEW` exits successfully, including\n     when `isDraft` is true. Use a short sleep between attempts and a sensible overall timeout; if\n     the release never appears, stop and report the failure.\n   - **Body from `CHANGELOG.md`:** Copy only the content for this version (from the first\n     `### Added`, `### Changed`, `### Fixed`, or `### Removed` under that version through the line\n     before the next `## [` version header). Do **not** include the `## [X.Y.Z] - YYYY-MM-DD`\n     heading line. For GitHub's layout, promote each of those subsection headings from `###` to\n     `##` (`### Added` → `## Added`, and the same pattern for Changed, Fixed, and Removed).\n   - **Wrapping within list items:** Undo changelog hard-wraps inside one bullet: when a list line\n     ends with a single newline and the following line continues the same item (for example an\n     indented continuation), join them with one space so `- item with long sentence` plus\n     `line 2` reads as `- item with long sentence line 2`. Do **not** join across a paragraph\n     break: leave any run of **two or more consecutive newlines** (`\\n\\n` or more) unchanged.\n   - **Full Changelog line:** After the body, append **one blank line**, then exactly:\n     `**Full Changelog**: https:\u002F\u002Fgithub.com\u002FTatsh\u002Fwiswa\u002Fcompare\u002FvPREV...vNEW`\n     where `vNEW` is this release's tag. Set `vPREV` to the tag of the\n     **most recent other GitHub release** (for example from `gh release list`, ordered by recency,\n     skipping `vNEW`). If no earlier release exists on GitHub, fall back to the previous version\n     in `CHANGELOG.md` immediately below this entry, or the git tag that precedes `vNEW`.\n   - **Apply:** Write the combined Markdown to a file (for example under `.wiswa-ci\u002F`) and run\n     `gh release edit vNEW --notes-file \u003Cpath>`.\n\n1. **Monitor CI until the release is undrafted.** On GitHub, the release pipeline triggered\n   by the tag push un-drafts the GitHub Release on success. Poll runs created **at or after\n   the push** (use `gh run list --branch vNEW` and\u002For per-workflow filters; ignore older\n   runs) on a short sleep until every post-push run reaches a terminal status and\n   `gh release view vNEW --json isDraft -q .isDraft` returns `false`. Cap the loop with a\n   sensible overall timeout. On all-green and undrafted, report the release URL and stop.\n\n   If any post-push run **failed**, recover as follows:\n   1. **Alert the user** with the failing run URLs and a one-line summary of the workflow\n      and job that failed.\n   1. **Fetch the failing logs** with `gh run view \u003Crun-id> --log-failed` (or `--log` for\n      the full transcript) and read them to identify the root cause.\n   1. **Delete the broken release and tag.** Run `gh release delete vNEW --yes`,\n      `git push origin :refs\u002Ftags\u002FvNEW`, and `git tag -d vNEW`.\n   1. **If the release was already un-drafted before the failure surfaced**, do **not**\n      reuse `vNEW` after the cleanup; a published release is part of the public history.\n      Bump one more patch level so the recovery release is `vNEW+1`, leaving the failed\n      tag as a recorded mistake.\n   1. **Apply the fix** if the logs make the root cause clear, as a normal commit\n      (separate from the original bump commit). Then restart from the version-bump step\n      with the same OLD→NEW (or OLD→NEW+1 in the premature-undraft case).\n   1. **If the cause is unclear**, stop and hand back to the user with the logs and the\n      cleanup state.\n\n## Rules\n\n- Never use `--no-verify` or skip hooks.\n- Never force-push.\n- Never lower a coverage threshold, skip a test, or exclude a file from measurement to get past\n  the pre-release checks. A shortfall is closed by writing tests or fixing the code.\n- If any step fails, stop and report the error. Do not continue the release process.\n- The `[Unreleased]` section must always exist at the top of the changelog after the release.\n- Run `pre-commit run -a` and the version-bump `git commit` outside the sandbox; both need\n  write access across the working tree.\n- Flatpak manifests and `snapcraft.yaml` at release time always build from the about-to-be\n  pushed tag, never from a local path or moving branch.\n- Never hand-patch a version reference in `CITATION.cff`, a flatpak manifest, or\n  `snapcraft.yaml` to compensate for a missing `[tool.commitizen].version_files` entry. Fix\n  the configuration in `.wiswa.jsonnet`, then restart the bump.\n- `cz bump --files-only` is plain string substitution, not pattern-aware. Always pre-scan\n  every `version_files` entry for OLD substrings before bumping, and revert non-canonical\n  matches afterwards so unrelated literals like `10.0.0` are not corrupted into `10.0.1`.\n- A release is not complete until every post-push CI run reaches a terminal status and the\n  GitHub Release is un-drafted. If recovery requires deleting a release that was already\n  un-drafted, bump one more patch level instead of reusing the failed tag - a published\n  release is part of the public history and must not be silently replaced.\n",{},"master","b1935933a90b8d859d140f02d9a436899906f5a0",".claude\u002Fskills\u002Fmake-release","https:\u002F\u002Fgithub.com\u002FTatsh\u002Fwiswa","https:\u002F\u002Ftatsh.github.io\u002Fwiswa\u002F","https:\u002F\u002Fgithub.com\u002FTatsh","2026-11-11 16:43:59",{"source":7,"skillName":5,"commands":32,"prompt":42,"zipAvailable":43},[33,36,39],{"tool":34,"command":35},"npx","npx skills add Tatsh\u002Fwiswa --skill make-release",{"tool":37,"command":38},"bunx","bunx skills add Tatsh\u002Fwiswa --skill make-release",{"tool":40,"command":41},"pnpm","pnpm dlx skills add Tatsh\u002Fwiswa --skill make-release","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FTatsh\u002Fwiswa\u002Fblob\u002Fmaster\u002F.claude\u002Fskills\u002Fmake-release\u002FSKILL.md",true,[],[46,53,67],{"skillNo":47,"name":48,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":6,"repositoryNo":11,"starsCount":12,"licenseSpdxId":13,"licenseFileUrl":6,"sourceHtmlUrl":49,"categories":50,"keywords":51,"publishedAt":20},"01M6HZQ8579Z77A5DS08D1NC2P","regen","https:\u002F\u002Fgithub.com\u002FTatsh\u002Fwiswa\u002Fblob\u002Fmaster\u002F.claude\u002Fskills\u002Fregen\u002FSKILL.md",[],[52],"Regen",{"skillNo":54,"name":55,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":6,"repositoryNo":11,"starsCount":12,"licenseSpdxId":13,"licenseFileUrl":6,"sourceHtmlUrl":56,"categories":57,"keywords":63,"publishedAt":20},"01M6HZQ4MSKRM9RCCSJ49TTH87","prose-lint","https:\u002F\u002Fgithub.com\u002FTatsh\u002Fwiswa\u002Fblob\u002Fmaster\u002F.claude\u002Fskills\u002Fprose-lint\u002FSKILL.md",[58],{"categoryNo":59,"categoryName":60,"taxonomyType":61,"taxonomyTypeDesc":62},"01JBSEEDCAT000000000000007","代码审查","SCENARIO","使用场景",[64,65,66],"lint","prose","prose lint",{"skillNo":68,"name":69,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":6,"repositoryNo":11,"starsCount":12,"licenseSpdxId":13,"licenseFileUrl":6,"sourceHtmlUrl":70,"categories":71,"keywords":72,"publishedAt":20},"01M6HZPZ6E0N88TXZ9EX2DAGK7","ci","https:\u002F\u002Fgithub.com\u002FTatsh\u002Fwiswa\u002Fblob\u002Fmaster\u002F.claude\u002Fskills\u002Fci\u002FSKILL.md",[],[69]]