diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index 2490aac..13cff25 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -40,7 +40,7 @@ body:
id: version
attributes:
label: ContextForge version
- placeholder: "0.4.2"
+ placeholder: "0.4.2.post2"
validations:
required: true
- type: input
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index ce3f3cc..470c25b 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -4,7 +4,7 @@ on:
workflow_dispatch:
inputs:
tag:
- description: Existing signed annotated tag to publish (for example v0.4.2)
+ description: Existing signed annotated tag to publish (for example v0.4.2.post2)
required: true
type: string
@@ -49,12 +49,12 @@ jobs:
run: |
case "$TAG" in
v[0-9]*.[0-9]*.[0-9]*) ;;
- *) echo "tag must match vX.Y.Z" >&2; exit 1 ;;
+ *) echo "tag must match vX.Y.Z or a PEP 440 post release such as vX.Y.Z.postN" >&2; exit 1 ;;
esac
test "$(git cat-file -t "refs/tags/$TAG")" = "tag"
- test "$(git rev-parse "$TAG^{}")" = "$GITHUB_SHA"
+ TAG_COMMIT="$(git rev-parse "$TAG^{}")"
git fetch origin main --no-tags
- git merge-base --is-ancestor "$GITHUB_SHA" origin/main
+ git merge-base --is-ancestor "$TAG_COMMIT" origin/main
VERSION="$(sed -n 's/^__version__ = "\([^"]*\)"$/\1/p' src/contextforge/_metadata.py)"
test "$TAG" = "v$VERSION"
grep -F "## [$VERSION]" CHANGELOG.md
@@ -114,12 +114,13 @@ jobs:
- name: Create or refresh draft release
env:
GH_TOKEN: ${{ github.token }}
+ GH_REPO: ${{ github.repository }}
TAG: ${{ inputs.tag }}
run: |
- if gh release view "$TAG" >/dev/null 2>&1; then
- gh release upload "$TAG" release-assets/* --clobber
+ if gh release view "$TAG" --repo "$GH_REPO" >/dev/null 2>&1; then
+ gh release upload "$TAG" release-assets/* --repo "$GH_REPO" --clobber
else
- gh release create "$TAG" release-assets/* --draft --verify-tag --generate-notes --title "ContextForge $TAG"
+ gh release create "$TAG" release-assets/* --repo "$GH_REPO" --draft --verify-tag --generate-notes --title "ContextForge $TAG"
fi
publish-testpypi:
@@ -141,7 +142,7 @@ jobs:
name: python-distributions
path: publish/
- name: Publish with Trusted Publishing
- uses: pypa/gh-action-pypi-publish@ec4db0b4ddc65acdf4bff5fa45ac92d78b56bdf0 # v1.9.0
+ uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
with:
packages-dir: publish/
repository-url: https://test.pypi.org/legacy/
@@ -194,6 +195,6 @@ jobs:
name: python-distributions
path: publish/
- name: Publish with Trusted Publishing
- uses: pypa/gh-action-pypi-publish@ec4db0b4ddc65acdf4bff5fa45ac92d78b56bdf0 # v1.9.0
+ uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
with:
packages-dir: publish/
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d9c1373..c6fa2fb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,11 +2,28 @@
All notable changes to this project will be documented in this file.
-The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
-and this project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
+Feature releases follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html),
+and Python distribution versions follow PEP 440.
## [Unreleased]
+## [0.4.2.post2] - 2026-08-21
+
+### Fixed
+
+- Updated the SHA-pinned PyPI publishing action to a release that supports
+ Core Metadata 2.4, matching the metadata generated for ContextForge wheels
+ and source distributions.
+
+## [0.4.2.post1] - 2026-08-21
+
+### Fixed
+
+- Made the CLI help regression validation insensitive to ANSI terminal styling
+ so the same documented options are verified consistently on Linux and
+ Windows CI runners.
+
## [0.4.2] - 2026-08-21
### Added
diff --git a/README.md b/README.md
index 2c78936..60360a2 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
-
+
ContextForge
@@ -28,10 +28,10 @@ commands.
> [!IMPORTANT]
-> ContextForge is pre-alpha software. Version `0.4.2` is the first public-release
-> candidate. Discovery benchmarking is experimental and its results should be
-> reviewed alongside the recorded provider, model, configuration, and source
-> snapshot.
+> ContextForge is pre-alpha software. Version `0.4.2.post2` is the current
+> first public-release candidate, including packaging-workflow corrections.
+> Discovery benchmarking is experimental and its results should be reviewed
+> alongside the recorded provider, model, configuration, and source snapshot.
## Why ContextForge
diff --git a/ROADMAP.md b/ROADMAP.md
index 4353776..b84271e 100644
--- a/ROADMAP.md
+++ b/ROADMAP.md
@@ -55,7 +55,12 @@ This roadmap describes broad milestones only. It does not promise dates.
fixed source, index, model, and context-window provenance.
- [x] Add locked distribution builds, clean-install validation, SBOM generation,
Trusted Publishing workflows, and public contribution/security policies.
-- [ ] Publish the reviewed signed release through TestPyPI and PyPI.
+- [x] Correct ANSI-sensitive CLI help validation for consistent Linux and
+ Windows release CI.
+- [x] Update the pinned publishing action to support the Core Metadata 2.4
+ generated by the release build.
+- [ ] Publish the reviewed signed `v0.4.2.post2` release through TestPyPI and
+ PyPI.
## Later
diff --git a/docs/RELEASE_CHECKLIST.md b/docs/RELEASE_CHECKLIST.md
index 539e817..93dbc8b 100644
--- a/docs/RELEASE_CHECKLIST.md
+++ b/docs/RELEASE_CHECKLIST.md
@@ -13,6 +13,8 @@ index API token is stored in repository secrets.
- [ ] Confirm the supported Python versions in `pyproject.toml` and CI.
- [ ] Confirm `contextforge-repo` is still unregistered on both PyPI and
TestPyPI, and both Trusted Publisher configurations match `release.yml`.
+- [ ] Confirm the SHA-pinned PyPI publishing action supports the Core Metadata
+ version emitted by the current build backend.
- [ ] Update the separate Wiki repository when public behavior or commands
changed; before changing visibility, replace its installation command with
`python -m pip install contextforge-repo`.
@@ -97,7 +99,8 @@ uv run contextforge benchmark discovery 'C:\Repositories' `
- [ ] Merge the reviewed release pull request from `dev` into `main`.
- [ ] Verify the exact merge commit contains the intended version and changelog.
-- [ ] Create a signed annotated `vX.Y.Z` tag on that exact commit.
+- [ ] Create a signed annotated `vX.Y.Z` tag on that exact commit, or
+ `vX.Y.Z.postN` for a PEP 440 post release.
- [ ] Push the tag without rewriting earlier tags.
- [ ] Synchronize `dev` with the released `main`.
diff --git a/src/contextforge/_metadata.py b/src/contextforge/_metadata.py
index 5a7dd42..7588a07 100644
--- a/src/contextforge/_metadata.py
+++ b/src/contextforge/_metadata.py
@@ -3,4 +3,4 @@
APP_NAME = "ContextForge"
APP_SLUG = "contextforge"
APP_TAGLINE = "Build bounded, reviewable repository context for coding agents."
-__version__ = "0.4.2"
+__version__ = "0.4.2.post2"
diff --git a/tests/test_openai_compatible.py b/tests/test_openai_compatible.py
index 411990a..5aab9ca 100644
--- a/tests/test_openai_compatible.py
+++ b/tests/test_openai_compatible.py
@@ -6,6 +6,7 @@
from typing import Any, Literal
import pytest
+from click import unstyle
from pydantic import BaseModel, ConfigDict
from typer.testing import CliRunner
@@ -658,10 +659,11 @@ def test_cli_help_and_provider_selection_include_base_url(tmp_path: Path) -> Non
)
assert help_result.exit_code == 0
- assert "--base-url" in help_result.output
- assert "--request-timeout" in help_result.output
- assert "--context-window" in help_result.output
- assert "--max-output-tokens" in help_result.output
+ help_output = unstyle(help_result.output)
+ assert "--base-url" in help_output
+ assert "--request-timeout" in help_output
+ assert "--context-window" in help_output
+ assert "--max-output-tokens" in help_output
assert selected.exit_code == 1
assert "OpenAI-compatible base URL must be an HTTP URL" in selected.output