diff --git a/.github/workflows/cut-versions.yml b/.github/workflows/cut-versions.yml
new file mode 100644
index 0000000..172b8a2
--- /dev/null
+++ b/.github/workflows/cut-versions.yml
@@ -0,0 +1,97 @@
+name: Auto-cut Stable versions
+
+# Checks every versioned tool for a newer tag upstream (see
+# scripts/auto-cut-versions.js) and, if one exists, cuts Stable and
+# re-cuts Previous versions via scripts/cut-version.js, then merges the
+# result straight to main — see "Cutting Stable or Previous versions" in
+# docs/contribute/versioning.mdx. Fully automatic end to end: a newer tag
+# existing upstream is itself the only signal this waits for, and the
+# build + test run below is the gate, not a human. Runs on a schedule so
+# nobody has to remember to run that script by hand after a release, and
+# nobody has to click merge either.
+
+on:
+ schedule:
+ - cron: '0 6 * * *' # daily, 06:00 UTC
+ workflow_dispatch:
+
+permissions:
+ contents: write
+ pull-requests: write
+
+concurrency:
+ group: auto-cut-versions
+ cancel-in-progress: false
+
+jobs:
+ auto-cut:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+
+ - uses: actions/setup-node@v4
+ with:
+ node-version: 20
+ cache: npm
+
+ - name: Install dependencies
+ run: npm ci
+
+ # See the matching comment in ci.yml for why both are needed.
+ - name: Install Doxygen and Graphviz
+ run: sudo apt-get update && sudo apt-get install -y doxygen graphviz
+
+ - name: Check for new tags and cut Stable
+ run: node scripts/auto-cut-versions.js
+
+ - name: Determine whether anything was cut
+ id: check
+ run: |
+ if [ -f cut-version-summary.md ]; then
+ echo "changed=true" >> "$GITHUB_OUTPUT"
+ else
+ echo "changed=false" >> "$GITHUB_OUTPUT"
+ fi
+
+ # A cut is never pushed unverified — build/test have to pass on the
+ # actual result before a PR is opened or updated with it.
+ - name: Build
+ if: steps.check.outputs.changed == 'true'
+ run: npm run build
+
+ - name: Test
+ if: steps.check.outputs.changed == 'true'
+ run: npm test
+
+ # One fixed branch, force-pushed each run — a run the next day with
+ # no further upstream changes has nothing new to add, and a run
+ # while an earlier auto-cut PR somehow still exists updates that
+ # same PR in place instead of opening a duplicate (normally there
+ # is none: the merge below closes it out the same run it's opened).
+ # Still goes through a PR (not a direct push to main) so the cut
+ # has a normal commit/PR record — merging it is what's automatic
+ # here, not the record-keeping.
+ - name: Open, then merge, the PR
+ if: steps.check.outputs.changed == 'true'
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: |
+ BRANCH="automated/cut-versions"
+ git config user.name "github-actions[bot]"
+ git config user.email "github-actions[bot]@users.noreply.github.com"
+ git checkout -B "$BRANCH"
+ git add -A -- '*_versioned_docs' '*_versioned_sidebars' '*_versions.json' versioned-tools-stable.json
+ git commit -m "$(printf 'Auto-cut Stable version(s)\n\n%s' "$(cat cut-version-summary.md)")"
+ git push --force origin "$BRANCH"
+ if [ -z "$(gh pr list --head "$BRANCH" --state open --json number --jq '.[0].number')" ]; then
+ gh pr create --title "Auto-cut Stable version(s)" --body-file cut-version-summary.md --head "$BRANCH" --base main
+ else
+ gh pr edit "$BRANCH" --body-file cut-version-summary.md
+ fi
+ # Build + Test above already validated this exact commit, so
+ # merge immediately rather than waiting on anything further —
+ # if branch protection on main blocks this (e.g. it requires
+ # its own separate status checks or reviews), this fails loudly
+ # here and the PR is left open for a human, rather than merging
+ # partway or silently doing nothing.
+ gh pr merge "$BRANCH" --merge --delete-branch
diff --git a/.gitignore b/.gitignore
index 46d89ac..69afc83 100644
--- a/.gitignore
+++ b/.gitignore
@@ -48,6 +48,10 @@ versioned-tools/**/*.md
/doxygen2docusaurus.json
/scripts/generated/
+# scripts/auto-cut-versions.js's own scratch output — read by
+# .github/workflows/cut-versions.yml, never committed itself.
+/cut-version-summary.md
+
# Editor / machine-specific
.vscode/
diff --git a/adaptive-grippers-cpp_versioned_docs/version-previous-versions/_readme.md b/adaptive-grippers-cpp_versioned_docs/version-previous-versions/_readme.md
deleted file mode 100644
index a9c3674..0000000
--- a/adaptive-grippers-cpp_versioned_docs/version-previous-versions/_readme.md
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-C++ driver with functions to control `Robotiq` Adaptive Grippers: 2F85, 2F140 and Hand-E. It allows high communication frequency.
-
-:::note
-With the default baudrate of the gripper the maximum achievable communication
-frequency is 250Hz. The communication frequency is set with the
-`ConnectionConfig::connectionFrequency` parameter, which defaults to 100Hz.
-:::
-
-Cross-platform: Linux, Windows, macOS — and freestanding/RTOS targets such
-as STM32 microcontrollers.
-
-
diff --git a/adaptive-grippers-cpp_versioned_docs/version-stable/docs/index.mdx b/adaptive-grippers-cpp_versioned_docs/version-stable/docs/index.mdx
new file mode 100644
index 0000000..ad6a4ad
--- /dev/null
+++ b/adaptive-grippers-cpp_versioned_docs/version-stable/docs/index.mdx
@@ -0,0 +1,15 @@
+---
+title: Introduction guides
+sidebar_label: Introduction guides
+---
+
+import Readme from '../_readme.md';
+
+
GitHub Repository
diff --git a/adaptive-grippers-cpp_versioned_sidebars/version-previous-versions-sidebars.json b/adaptive-grippers-cpp_versioned_sidebars/version-previous-versions-sidebars.json
index 8505830..a8402c3 100644
--- a/adaptive-grippers-cpp_versioned_sidebars/version-previous-versions-sidebars.json
+++ b/adaptive-grippers-cpp_versioned_sidebars/version-previous-versions-sidebars.json
@@ -14,9 +14,13 @@
"label": "Libraries",
"items": [
{
- "type": "doc",
- "id": "index",
- "label": "C++"
+ "type": "category",
+ "label": "C++",
+ "link": {
+ "type": "doc",
+ "id": "index"
+ },
+ "items": []
},
{
"type": "link",
diff --git a/adaptive-grippers-cpp_versioned_sidebars/version-stable-sidebars.json b/adaptive-grippers-cpp_versioned_sidebars/version-stable-sidebars.json
index 8505830..f7b12a9 100644
--- a/adaptive-grippers-cpp_versioned_sidebars/version-stable-sidebars.json
+++ b/adaptive-grippers-cpp_versioned_sidebars/version-stable-sidebars.json
@@ -14,9 +14,23 @@
"label": "Libraries",
"items": [
{
- "type": "doc",
- "id": "index",
- "label": "C++"
+ "type": "category",
+ "label": "C++",
+ "link": {
+ "type": "doc",
+ "id": "index"
+ },
+ "items": [
+ {
+ "type": "category",
+ "label": "Introduction guides",
+ "link": {
+ "type": "doc",
+ "id": "docs/index"
+ },
+ "items": []
+ }
+ ]
},
{
"type": "link",
diff --git a/adaptive-grippers-cpp_versions.json b/adaptive-grippers-cpp_versions.json
index 402035e..47ba807 100644
--- a/adaptive-grippers-cpp_versions.json
+++ b/adaptive-grippers-cpp_versions.json
@@ -1,4 +1,4 @@
[
- "stable",
- "previous-versions"
+ "previous-versions",
+ "stable"
]
diff --git a/docs/contribute/versioning.mdx b/docs/contribute/versioning.mdx
index 1d42c5d..6fdfecc 100644
--- a/docs/contribute/versioning.mdx
+++ b/docs/contribute/versioning.mdx
@@ -204,106 +204,84 @@ also swizzled shorter, to one line
(`src/theme/DocVersionBanner/index.jsx`) — unrelated to any of the above,
just bundled into the same theme-swizzling work.
-## Cutting Stable or Previous versions by hand
-
-There's no CI automation for this yet — every version cut is a manual,
-local operation, run once and committed. `scripts/list-submodule-tags.js`
-finds the current tags directly off each submodule's remote (`git
-ls-remote --tags`, not the local checkout, which can go stale):
-
-```bash
-node scripts/list-submodule-tags.js
-```
-
-**To cut (or re-cut) Stable at the newest tag:**
+## Cutting Stable or Previous versions
+
+`.github/workflows/cut-versions.yml` runs this daily for every tool
+already tracking a Stable tag, fully automatically — end to end, not
+just the cut itself: it checks each one's submodule for a newer tag
+(`scripts/auto-cut-versions.js`), and if there is one, that's the only
+signal it waits for; it cuts it, validates the result with a full build
+and test run, and merges straight to `main` through a PR it opens and
+merges itself. Nobody needs to remember to run this after a release, and
+nobody needs to click merge either. There's no filtering on tag name yet
+(e.g. skipping a pre-release/beta tag) — every tool currently opted into
+versioning only ever tags real releases, so "newest tag" already means
+"newest release" for all of them; a name-based filter is a deliberate,
+not-yet-needed follow-up for the day that stops being true.
+
+Cutting by hand (a new tool's first cut, before it's in
+`versioned-tools-stable.json` for the automation to find; re-cutting a
+specific non-newest tag; or just running it locally instead of waiting
+for the schedule) is one command each, via `scripts/cut-version.js`:
```bash
-cd external/