Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
315 changes: 162 additions & 153 deletions .codex/skills/release-version/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,225 +1,234 @@
---
name: release-version
description: Use when preparing or publishing a new semantic version release, updating bilingual changelogs, creating Git tags, or publishing GitHub/Gitee release pages for this repository.
description: Use when preparing or publishing a new release of this fork, updating CHANGELOG.md, reconciling dev with main, creating Git tags, or publishing the GitHub Release page for DOS/Crove-Desk.
---

# Release Version

## Overview

Create releases with a strict `vx.y.z` tag, produce bilingual changelog entries from actual Git history, publish both the `docs` submodule update and repository tag, and create the GitHub and Gitee Release page entries in one controlled workflow.
Create a release with a `vX.Y.Z-crove.N` tag, derive the changelog entry from the
real Git range, reconcile `dev` with `main` before tagging, and publish the GitHub
Release page. Pushing the tag is what builds the production image.

Run the workflow from the repository root. Read [references/changelog-style.md](references/changelog-style.md) before drafting the human-facing update notes.
Run the workflow from the repository root. Read
[references/changelog-style.md](references/changelog-style.md) before drafting the
notes.

This skill was inherited from upstream `huabeitech/agent-desk` and has been
rewritten for the fork. Three things it used to say are no longer true here: the
`docs` submodule was removed (upstream PR #35) so there is no bilingual docs
changelog, there is no Gitee mirror, and the release repository is
`DOS/Crove-Desk` rather than `huabeitech/agent-desk`.

## Workflow

1. Validate the requested version.
2. Inspect the repository and determine the comparison range.
3. Draft bilingual changelog entries from the actual diff.
4. Commit and push the `docs` submodule.
5. Commit the parent repository update if the submodule pointer changed.
6. Create and push the annotated tag.
7. Create GitHub and Gitee Release page entries for the tag.
8. Verify both remote tags and both Release pages.

Do not skip the repository inspection step. Release notes must come from the real diff between tags, not from guesswork.
2. Reconcile `dev` and `main`.
3. Inspect the repository and determine the comparison range.
4. Draft the `CHANGELOG.md` entry from the actual diff.
5. Run the verification suite.
6. Commit and push the changelog.
7. Create and push the annotated tag.
8. Create the GitHub Release page for the tag.
9. Verify the production image build and the remote tag.

Do not skip the repository inspection step. Release notes must come from the real
diff between tags, not from guesswork.

## Validate The Version

- Accept only tags that match `^v\d+\.\d+\.\d+$`.
- Reject date-style tags such as `v20260414`.
- Accept only tags that match `^v\d+\.\d+\.\d+-crove\.\d+$`.
- Reject bare `vX.Y.Z` and reject date-style tags such as `v20260414`.
- Confirm the target tag does not already exist locally or on any configured remote.
- Prefer the latest reachable semver tag as the previous release tag.
- If no earlier semver tag exists, fall back to the latest reachable tag of any format and state that fallback in the changelog drafting notes.
- Prefer the latest reachable `-crove.N` tag as the previous release tag.

Use the helper script first:
**The `-crove.N` suffix is load-bearing, not cosmetic.**
`.github/workflows/sync-upstream.yml` lines 79-88 skip the entire upstream sync
when this fork already holds a tag whose name matches the upstream target tag, and
line 121 pushes upstream's tag into the fork afterwards. A bare `v1.7.0` here
would therefore silently disable every future upstream sync the moment upstream
released `v1.7.0`. Upstream owns the plain `vX.Y.Z` namespace; the fork must not
allocate from it.

```bash
python3 .codex/skills/release-version/scripts/collect_release_context.py \
--repo . \
--tag v1.2.3
--tag v1.7.1-crove.1
```

If the caller already specifies the previous tag, pass it explicitly:
Pass `--previous-tag` explicitly when the caller already knows the baseline.

```bash
python3 .codex/skills/release-version/scripts/collect_release_context.py \
--repo . \
--tag v1.2.3 \
--previous-tag v1.2.2
```
## Reconcile dev And main

If the repository-local helper is unavailable, fall back to `~/.codex/skills/release-version/scripts/collect_release_context.py`.
`dev` is the integration branch: `sync-upstream.yml` merges upstream tags into it
and pushes it directly, and `deploy-beta.yml` builds `:beta` from every push to
it. `main` is the default branch and is what Dependabot scans. The two drift.

## Inspect The Repository

- Check `git status --short` in the parent repo.
- Check `git -C docs status --short` in the `docs` submodule.
- Read the JSON output of `collect_release_context.py`.
- Use the commit list, changed files, and insertions/deletions to decide what is user-visible.
- Prioritize behavior changes, new features, fixes, migrations, API changes, configuration changes, and documentation changes that matter to adopters.
- Ignore pure formatting churn unless it changes usage.

If the working tree contains unrelated changes that would be risky to include in the release, stop and ask the user before proceeding.

## Draft The Changelog
Before tagging, check both directions:

Update these files:

- `docs/zh/docs/changelog.md`
- `docs/en/docs/changelog.md`
```bash
git fetch origin
git rev-list --count origin/main..dev
git rev-list --count dev..origin/main
```

Prepend a new entry using this exact structure:
If the second count is non-zero, **merge `origin/main` into `dev` first** and only
then tag. Tagging `dev` while `main` holds commits `dev` lacks ships a release
that silently regresses whatever is on `main`. This is not hypothetical: the
`web/pnpm-workspace.yaml` fix and the dependency overrides that drove Dependabot
from 162 alerts to 34 existed only on `main`, and merging `dev` over `main`
without reconciling first would have reverted them.

```md
## ${tag} (${yyyy-MM-dd})
Expect a `web/pnpm-lock.yaml` conflict when this happens. Resolve it toward
whichever side was generated together with the current `web/pnpm-workspace.yaml`,
then prove the choice instead of arguing it:

### 更新内容
```bash
cd web && pnpm install --frozen-lockfile
```

${content}
That is the exact command CI and the Docker build run. `Lockfile is up to date`
plus exit 0 settles it.

### 发布地址
After reconciling, bring `main` up to `dev` so the default branch and the release
tag point at the same commit:

- Github: <https://github.com/huabeitech/agent-desk/releases/tag/${tag}>
- Gitee: <https://gitee.com/huabeitech/agent-desk/releases/tag/${tag}>
```bash
git push origin dev:main
git branch -f main dev
```

For the English file, keep the same links and heading level, but translate the section heading and content naturally:
## Inspect The Repository

```md
## ${tag} (${yyyy-MM-dd})
- Check `git status --short`. If the working tree holds unrelated changes, stop
and ask before proceeding - a release commit must not sweep them up.
- Read the JSON output of `collect_release_context.py`.
- Use the commit list, changed files, and insertions/deletions to decide what is
user-visible.
- Prioritize behavior changes, new features, fixes, migrations, API changes,
configuration changes, and documentation changes that matter to adopters.
- Ignore pure formatting churn unless it changes usage.

### Updates
## Draft The Changelog

${content}
Update `CHANGELOG.md` at the repository root. It is English-only and follows Keep
a Changelog. Prepend the new entry directly above the previous one:

### Release Links
```md
## [1.7.1-crove.1] - YYYY-MM-DD

- Github: <https://github.com/huabeitech/agent-desk/releases/tag/${tag}>
- Gitee: <https://gitee.com/huabeitech/agent-desk/releases/tag/${tag}>
### Security
### Added
### Changed
### Fixed
### Known issues
```

Omit any section that has nothing in it. Keep `### Known issues` even when it is
uncomfortable: it is where regressions this release deliberately did not fix get
recorded, and it is the section adopters most need.

Changelog writing rules:

- Write concise, user-facing summaries instead of raw commit subjects.
- Keep Chinese and English entries semantically aligned.
- Prefer 3-6 bullets unless the release is extremely small.
- Group related changes into a single bullet when that reads better.
- Mention compatibility-sensitive changes explicitly.
- If the comparison baseline is a non-semver fallback tag, note that in your private reasoning, not in the public changelog unless the user asks for it.

## Commit And Push The Docs Submodule

After editing the changelog files:

1. Run `git -C docs status --short`.
2. Review the diff with `git -C docs diff -- zh/docs/changelog.md en/docs/changelog.md`.
3. Commit inside the `docs` submodule with a focused message such as `docs: update changelog for v1.2.3`.
4. Push the `docs` submodule commit to its remote branch.

Branch rule:

- If `docs` is on a local branch, push that branch.
- If `docs` is detached, push `HEAD` to `origin/main` unless the repository clearly uses another default branch.
- Every claim must trace to a commit, a file, or a command you actually ran.
- State what a fix does *not* cover when the fix is partial. Marking a half-fixed
issue as fixed is worse than leaving it listed.

## Commit The Parent Repository
## Verify Before Tagging

If the `docs` submodule pointer changed in the parent repository, commit it before tagging. Otherwise the release tag will not reference the new changelog revision.

Recommended flow:
Run these and report real output. Do not claim a check you did not run.

```bash
git status --short
git add docs
git commit -m "chore: update docs submodule for v1.2.3"
go build -tags dev ./...
go vet -tags dev ./...
go test -count=1 -tags dev ./internal/services/... ./internal/repositories/... \
./internal/pkg/... ./internal/oidcclient/... ./internal/migration/... \
./internal/builders/... ./internal/bootstrap/... ./internal/handlers/...
cd web && pnpm install --frozen-lockfile
cd web && pnpm typecheck
cd web && node --test "**/*.test.mjs"
Comment on lines +150 to +152

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If these commands are executed sequentially in a single persistent shell session (which is common for AI agents or developers running scripts), the second and third cd web commands will fail because the shell is already inside the web directory.

Using subshells (cd web && ...) ensures that the working directory of the parent shell remains at the repository root, making the sequence robust and preventing directory resolution errors.

Suggested change
cd web && pnpm install --frozen-lockfile
cd web && pnpm typecheck
cd web && node --test "**/*.test.mjs"
(cd web && pnpm install --frozen-lockfile)
(cd web && pnpm typecheck)
(cd web && node --test "**/*.test.mjs")

git diff --check
```

Only include unrelated parent-repo changes if the user explicitly wants them in the release commit.

## Create And Push The Tag
`-tags dev` is required: without it the `//go:embed all:out` directive in
`web/embed.go` fails on a tree that has no `web/out`. `pnpm lint` currently
reports pre-existing `react-hooks` errors (PROC-16) and is wired into CI as
non-blocking, so treat *new* lint errors as the signal rather than the absolute
count.

Create an annotated tag after the repository state is ready:
## Commit And Push The Changelog

```bash
git tag -a v1.2.3 -m "Release v1.2.3"
git add CHANGELOG.md
git commit -m "docs(changelog): add the vX.Y.Z-crove.N entry"
git push origin dev
git push origin dev:main
```

Push the commit branch first if needed, then push the tag to every configured remote that should publish releases:

```bash
git push github HEAD
git push origin HEAD
git push github v1.2.3
git push origin v1.2.3
```
Stage only the changelog. Never `git add -A` in this repository - other sessions
frequently hold unrelated work in the same tree.

Adjust the branch name if `HEAD` is not tracking the intended release branch.

## Create GitHub And Gitee Releases

Pushing tags is not enough. The release is incomplete until both Release pages exist:

- GitHub: `https://github.com/huabeitech/agent-desk/releases/tag/${tag}`
- Gitee: `https://gitee.com/huabeitech/agent-desk/releases/tag/${tag}`

Use the same concise release notes derived from the changelog. Prefer a bilingual body with Chinese first and English second.

Required credentials:

- GitHub: `GITHUB_TOKEN` or `GH_TOKEN` with access to `huabeitech/agent-desk` and permission to create releases. For a fine-grained PAT, use an organization-allowed lifetime and grant the repository at least `Contents: Read and write` plus `Metadata: Read`.
- Gitee: `GITEE_ACCESS_TOKEN` or `GITEE_TOKEN` with release write access to `huabeitech/agent-desk`.

Never print tokens in command output or final responses. If the user pastes a token into the conversation, use it only for the requested release operation and recommend rotation after use.

Build the release body from the new changelog entry, for example:
## Create And Push The Tag

```bash
mkdir -p /tmp/agent-desk-release
awk 'BEGIN{p=0} /^## v1\.2\.3 /{p=1; next} /^## v[0-9]/{if(p) exit} p{print}' \
docs/zh/docs/changelog.md | sed '/^### 发布地址/,$d' > /tmp/agent-desk-release/v1.2.3-zh.md
awk 'BEGIN{p=0} /^## v1\.2\.3 /{p=1; next} /^## v[0-9]/{if(p) exit} p{print}' \
docs/en/docs/changelog.md | sed '/^### Release Links/,$d' > /tmp/agent-desk-release/v1.2.3-en.md
{
printf '## 更新内容\n\n'
sed '1,/^### 更新内容$/d' /tmp/agent-desk-release/v1.2.3-zh.md
printf '\n## Updates\n\n'
sed '1,/^### Updates$/d' /tmp/agent-desk-release/v1.2.3-en.md
} > /tmp/agent-desk-release/v1.2.3-release-body.md
git tag -a v1.7.1-crove.1 -m "Release v1.7.1-crove.1" <commit>
git push origin v1.7.1-crove.1
```

Create the GitHub Release:
Tag the reconciled commit, not whatever `HEAD` happens to be. Pushing the tag
triggers `deploy-prod.yml` through its `push: tags: v*` rule.

```bash
token="${GITHUB_TOKEN:-$GH_TOKEN}"
curl -sS -o /tmp/github_release_v1.2.3.json -w '%{http_code}' \
-X POST https://api.github.com/repos/huabeitech/agent-desk/releases \
-H "Authorization: Bearer ${token}" \
-H 'Accept: application/vnd.github+json' \
-H 'X-GitHub-Api-Version: 2022-11-28' \
-H 'Content-Type: application/json' \
-d @<(jq -n --rawfile body /tmp/agent-desk-release/v1.2.3-release-body.md \
'{tag_name:"v1.2.3", target_commitish:"main", name:"v1.2.3", body:$body, draft:false, prerelease:false}')
```
## Create The GitHub Release

Create the Gitee Release:
Pushing the tag builds the image but publishes nothing human-readable. Create the
Release page on `DOS/Crove-Desk`:

```bash
token="${GITEE_ACCESS_TOKEN:-$GITEE_TOKEN}"
curl -sS -o /tmp/gitee_release_v1.2.3.json -w '%{http_code}' \
-X POST https://gitee.com/api/v5/repos/huabeitech/agent-desk/releases \
-H 'Content-Type: application/json' \
-d @<(jq -n --rawfile body /tmp/agent-desk-release/v1.2.3-release-body.md --arg token "${token}" \
'{access_token:$token, tag_name:"v1.2.3", target_commitish:"main", name:"v1.2.3", body:$body, prerelease:false}')
gh release create v1.7.1-crove.1 \
--repo DOS/Crove-Desk \
--title "v1.7.1-crove.1" \
--notes-file <notes.md>
```

If creation returns `422`/already exists, fetch the existing release and verify it references the target tag before treating it as complete. If GitHub returns `Resource not accessible by personal access token`, inspect the API message and ask for a token that satisfies the organization policy and repository permissions.
Build the notes body from the new `CHANGELOG.md` entry. If the first attempt
fails, re-run against the existing release with `gh release edit` rather than
creating a second tag.

There is no Gitee mirror for this fork. Do not attempt to publish there.

## Final Verification

- Confirm `git rev-parse v1.2.3^{tag}` succeeds.
- Confirm `git ls-remote --tags github v1.2.3` and `git ls-remote --tags origin v1.2.3` show the new tag.
- Confirm `curl -sS -o /tmp/github_release_verify.json -w '%{http_code}' https://api.github.com/repos/huabeitech/agent-desk/releases/tags/v1.2.3` returns `200`.
- Confirm `curl -sS -o /tmp/gitee_release_verify.json -w '%{http_code}' https://gitee.com/api/v5/repos/huabeitech/agent-desk/releases/tags/v1.2.3` returns `200`.
- Confirm the `docs` submodule remote contains the changelog commit.
- Confirm both parent and `docs` working trees are clean.
- Summarize the previous tag used for comparison, the files updated, the commit hashes created, the remotes pushed, and the GitHub/Gitee Release URLs.
- `git rev-parse v1.7.1-crove.1^{tag}` succeeds.
- `git ls-remote --tags origin v1.7.1-crove.1` shows the tag.
- `git rev-parse dev origin/dev main origin/main v1.7.1-crove.1^{commit}` all
report the same commit.
- The production build finished:
`gh run list --repo DOS/Crove-Desk --limit 3 --json displayTitle,workflowName,status,conclusion`
- The image tags were actually published. Read them from the build log rather
than assuming them from the workflow config:
`gh run view <run-id> --repo DOS/Crove-Desk --log --job <job-id>` filtered for
`dos/crove-desk:`. Expect `latest`, `X.Y.Z-crove.N` and `vX.Y.Z-crove.N` on one
shared digest, and confirm `org.opencontainers.image.revision` equals the
tagged commit.
- `gh release view v1.7.1-crove.1 --repo DOS/Crove-Desk` resolves.

## What This Does Not Do

Neither `deploy-prod.yml` nor `deploy-beta.yml` deploys anything. Both only build
an OCI image and push it to `ghcr.io/dos/crove-desk`. The operator still has to
pull the new image on the host and restart the service. Say so explicitly in the
handoff - a green workflow is not a live release.

## Completion Checklist

- Tag matches `^v\d+\.\d+\.\d+-crove\.\d+$` and exists on no other remote
- `dev` and `main` reconciled, both pointing at the tagged commit
- `CHANGELOG.md` entry derived from the real diff, Known issues included
- Verification suite run, with real output reported
- Annotated tag pushed and `deploy-prod.yml` succeeded
- Published image digest and `org.opencontainers.image.revision` confirmed
- GitHub Release page created on `DOS/Crove-Desk`
- Operator reminded that pulling the image on the host is still manual
4 changes: 2 additions & 2 deletions .codex/skills/release-version/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
interface:
display_name: "Release Version"
short_description: "Create semver tags and changelog drafts"
default_prompt: "Use $release-version to create a new vx.y.z release, update changelogs, and push docs plus tags."
short_description: "Create -crove.N tags and CHANGELOG.md drafts"
default_prompt: "Use $release-version to create a new vX.Y.Z-crove.N release, reconcile dev with main, update CHANGELOG.md, push the tag, and publish the GitHub Release."
Loading
Loading