@cleocode/cleo 2026.5.106 → 2026.5.107

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.
@@ -1,214 +0,0 @@
1
- # CLEO release pipeline — Best-effort fanout workflow.
2
- #
3
- # Generated from packages/cleo/templates/workflows/release-fanout.yml.tmpl by
4
- # `cleo init --workflows` (T9531). DO NOT EDIT the rendered file directly —
5
- # extend via `.workflow-overrides.yml` per SPEC-T9345 R-260.
6
- #
7
- # Implements SPEC-T9345-release-pipeline-v2.md §5.3 (R-240 — R-244, R-260 —
8
- # R-263). Triggers on `release: published` (the GitHub Release event, NOT
9
- # `release: created` which fires on drafts). Each downstream job is an
10
- # independent best-effort fanout — every job carries `continue-on-error:
11
- # true` so a failed docs deploy, docker retag, sentinel notify, studio
12
- # rebuild, or nightly trigger CANNOT mark the release itself as failed.
13
- # These jobs MUST NOT be configured as required status checks (R-244).
14
- #
15
- # Placeholders (replaced at scaffold time — see workflows/README.md):
16
- # <NODE_VERSION> Node.js version (e.g. "22.x")
17
- # <INSTALL_CMD> Install command (e.g. "pnpm install --frozen-lockfile")
18
- # <DOCS_BUILD_CMD> Docs build command (e.g. "pnpm --filter @cleocode/docs run build")
19
- # <ENABLE_DOCS_DEPLOY> Toggle docs-deploy job ("true" | "false")
20
- # <ENABLE_DOCKER_RETAG> Toggle docker-retag job ("true" | "false")
21
- # <ENABLE_SENTINEL_NOTIFY> Toggle sentinel-notify job ("true" | "false")
22
- # <ENABLE_STUDIO_DEPLOY> Toggle studio-deploy job ("true" | "false")
23
- # <ENABLE_NIGHTLY_TRIGGER> Toggle nightly-trigger job ("true" | "false")
24
- # <DOCKER_IMAGE> Docker image name (e.g. "cleocode/cleo")
25
- # <DOCKER_HUB_USER> Docker Hub login user (e.g. "cleocode")
26
- # <SENTINEL_WEBHOOK_URL> Sentinel webhook URL (HTTPS)
27
- # <STUDIO_DEPLOY_HOOK> Studio deploy hook URL (HTTPS)
28
- # (Angle-brackets in this doc comment are intentional — they avoid being
29
- # substituted by the {{...}} regex pass. The placeholders below use {{...}}.)
30
-
31
- name: Release Fanout
32
-
33
- # R-240: trigger on `release: published` ONLY. Draft releases (which fire
34
- # `release: created`) MUST NOT trigger the fanout — operators expect this
35
- # to run AFTER the publish + tag workflow has shipped the artifacts.
36
- on:
37
- release:
38
- types: [published]
39
-
40
- # R-241: workflow-level grants the minimum read scope. Per-job permissions
41
- # escalate ONLY for the jobs that need them (e.g. `pages: write` for docs
42
- # deploy). No top-level write scope — fanout is intentionally read-only at
43
- # the workflow level.
44
- permissions:
45
- contents: read
46
-
47
- # R-243: serialize fanouts against the same release tag. cancel-in-progress
48
- # is FALSE so an in-flight fanout completes rather than losing partial
49
- # work (e.g. a half-pushed docker tag).
50
- concurrency:
51
- group: fanout-${{ github.event.release.tag_name }}
52
- cancel-in-progress: false
53
-
54
- # R-262: bash everywhere — no cross-platform shell drift across the fanout
55
- # jobs (they all run on ubuntu-latest but the contract is explicit).
56
- defaults:
57
- run:
58
- shell: bash
59
-
60
- jobs:
61
- # R-242 (1/5): deploy generated documentation site to GitHub Pages.
62
- # continue-on-error: true so a docs-build regression cannot fail the
63
- # release. Disabled by default — flip {{ENABLE_DOCS_DEPLOY}} to "true"
64
- # at scaffold time. The flag is hoisted into env so the `if:` becomes a
65
- # dynamic expression (avoids actionlint constant-expression warning).
66
- docs-deploy:
67
- name: Deploy docs to GitHub Pages
68
- runs-on: ubuntu-latest
69
- continue-on-error: true
70
- timeout-minutes: 15
71
- env:
72
- ENABLE_DOCS_DEPLOY: '{{ENABLE_DOCS_DEPLOY}}'
73
- if: ${{ env.ENABLE_DOCS_DEPLOY == 'true' }}
74
- # R-241 (per-job): pages: write + id-token: write granted ONLY for the
75
- # docs-deploy job — other fanout jobs MUST NOT inherit GitHub Pages
76
- # write scope.
77
- permissions:
78
- contents: read
79
- pages: write
80
- id-token: write
81
- steps:
82
- # R-263: third-party Actions pinned to major+minor.
83
- - name: Checkout
84
- uses: actions/checkout@v4.1
85
- with:
86
- fetch-depth: 1
87
- timeout-minutes: 5
88
-
89
- - name: Set up Node.js
90
- uses: actions/setup-node@v4.0
91
- with:
92
- node-version: '{{NODE_VERSION}}'
93
- timeout-minutes: 3
94
-
95
- - name: Install dependencies
96
- run: {{INSTALL_CMD}}
97
- timeout-minutes: 5
98
-
99
- - name: Build docs
100
- run: {{DOCS_BUILD_CMD}}
101
- timeout-minutes: 10
102
-
103
- - name: Configure Pages
104
- uses: actions/configure-pages@v5.0
105
- timeout-minutes: 2
106
-
107
- - name: Upload Pages artifact
108
- uses: actions/upload-pages-artifact@v3.0
109
- with:
110
- path: docs/dist
111
- timeout-minutes: 5
112
-
113
- - name: Deploy to GitHub Pages
114
- uses: actions/deploy-pages@v4.0
115
- timeout-minutes: 5
116
-
117
- # R-242 (2/5): retag the published docker image to `latest`. Failure here
118
- # does NOT roll back the release — operators can re-run manually.
119
- docker-retag:
120
- name: Retag docker image to latest
121
- runs-on: ubuntu-latest
122
- continue-on-error: true
123
- timeout-minutes: 10
124
- env:
125
- ENABLE_DOCKER_RETAG: '{{ENABLE_DOCKER_RETAG}}'
126
- DOCKER_IMAGE: '{{DOCKER_IMAGE}}'
127
- DOCKER_HUB_USER: '{{DOCKER_HUB_USER}}'
128
- VERSION: ${{ github.event.release.tag_name }}
129
- if: ${{ env.ENABLE_DOCKER_RETAG == 'true' }}
130
- steps:
131
- - name: Log in to Docker Hub
132
- run: |
133
- set -euo pipefail
134
- echo "${{ secrets.DOCKER_HUB_TOKEN }}" | \
135
- docker login -u "$DOCKER_HUB_USER" --password-stdin
136
- timeout-minutes: 3
137
-
138
- - name: Pull, retag, push
139
- run: |
140
- set -euo pipefail
141
- docker pull "${DOCKER_IMAGE}:${VERSION}"
142
- docker tag "${DOCKER_IMAGE}:${VERSION}" "${DOCKER_IMAGE}:latest"
143
- docker push "${DOCKER_IMAGE}:latest"
144
- timeout-minutes: 5
145
-
146
- # R-242 (3/5): POST a `release.published` event to the Sentinel webhook
147
- # so downstream monitoring can pick the release up. Best-effort — a
148
- # webhook outage MUST NOT mark the release as failed.
149
- sentinel-notify:
150
- name: Notify Sentinel of release
151
- runs-on: ubuntu-latest
152
- continue-on-error: true
153
- timeout-minutes: 5
154
- env:
155
- ENABLE_SENTINEL_NOTIFY: '{{ENABLE_SENTINEL_NOTIFY}}'
156
- SENTINEL_WEBHOOK_URL: '{{SENTINEL_WEBHOOK_URL}}'
157
- SENTINEL_TOKEN: ${{ secrets.SENTINEL_TOKEN }}
158
- VERSION: ${{ github.event.release.tag_name }}
159
- RELEASE_URL: ${{ github.event.release.html_url }}
160
- if: ${{ env.ENABLE_SENTINEL_NOTIFY == 'true' }}
161
- steps:
162
- - name: POST release.published to Sentinel
163
- run: |
164
- set -euo pipefail
165
- curl -fSL -X POST "$SENTINEL_WEBHOOK_URL" \
166
- -H 'Content-Type: application/json' \
167
- -H "Authorization: Bearer ${SENTINEL_TOKEN}" \
168
- -d "{\"event\":\"release.published\",\"version\":\"${VERSION}\",\"url\":\"${RELEASE_URL}\"}"
169
- timeout-minutes: 3
170
-
171
- # R-242 (4/5): trigger a Studio rebuild via deploy hook. Studio runs
172
- # outside this repo, so this job is a fire-and-forget POST.
173
- studio-deploy:
174
- name: Trigger Studio rebuild
175
- runs-on: ubuntu-latest
176
- continue-on-error: true
177
- timeout-minutes: 20
178
- env:
179
- ENABLE_STUDIO_DEPLOY: '{{ENABLE_STUDIO_DEPLOY}}'
180
- STUDIO_DEPLOY_HOOK: '{{STUDIO_DEPLOY_HOOK}}'
181
- STUDIO_DEPLOY_TOKEN: ${{ secrets.STUDIO_DEPLOY_TOKEN }}
182
- VERSION: ${{ github.event.release.tag_name }}
183
- if: ${{ env.ENABLE_STUDIO_DEPLOY == 'true' }}
184
- steps:
185
- - name: POST to Studio deploy hook
186
- run: |
187
- set -euo pipefail
188
- curl -fSL -X POST "$STUDIO_DEPLOY_HOOK" \
189
- -H "Authorization: Bearer ${STUDIO_DEPLOY_TOKEN}" \
190
- -H 'Content-Type: application/json' \
191
- -d "{\"version\":\"${VERSION}\"}"
192
- timeout-minutes: 10
193
-
194
- # R-242 (5/5): dispatch the nightly e2e workflow against the freshly
195
- # published release version. Decoupled from the release path — a failed
196
- # dispatch is logged but does NOT fail the release.
197
- nightly-trigger:
198
- name: Dispatch nightly e2e for release
199
- runs-on: ubuntu-latest
200
- continue-on-error: true
201
- timeout-minutes: 3
202
- env:
203
- ENABLE_NIGHTLY_TRIGGER: '{{ENABLE_NIGHTLY_TRIGGER}}'
204
- GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
205
- VERSION: ${{ github.event.release.tag_name }}
206
- if: ${{ env.ENABLE_NIGHTLY_TRIGGER == 'true' }}
207
- steps:
208
- - name: Dispatch nightly e2e
209
- run: |
210
- set -euo pipefail
211
- gh workflow run nightly-e2e.yml \
212
- --repo "${{ github.repository }}" \
213
- -f release_version="$VERSION"
214
- timeout-minutes: 2
@@ -1,296 +0,0 @@
1
- # CLEO release pipeline — Prepare bump-PR workflow.
2
- #
3
- # Generated from packages/cleo/templates/workflows/release-prepare.yml.tmpl by
4
- # `cleo init --workflows` (T9531). DO NOT EDIT the rendered file directly —
5
- # extend via `.workflow-overrides.yml` per SPEC-T9345 R-260.
6
- #
7
- # Implements SPEC-T9345-release-pipeline-v2.md §5.1 (R-200 — R-210, R-260 —
8
- # R-263). Triggers ONLY on workflow_dispatch; runs preflight (lint +
9
- # typecheck + test + build) BEFORE creating any commit; prepares the
10
- # release/<version> branch and opens the bump-PR via `gh pr create`.
11
- #
12
- # Placeholders (replaced at scaffold time — see workflows/README.md):
13
- # <NODE_VERSION> Node.js version (e.g. "22.x")
14
- # <INSTALL_CMD> Install command (e.g. "pnpm install --frozen-lockfile")
15
- # <LINT_CMD> tool:lint (ADR-061 resolved)
16
- # <TYPECHECK_CMD> tool:typecheck (ADR-061 resolved)
17
- # <TEST_CMD> tool:test (ADR-061 resolved)
18
- # <BUILD_CMD> tool:build (ADR-061 resolved)
19
- # <BRANCH_PREFIX> Release branch prefix (default: "release")
20
- # <PR_LABEL> GitHub label applied to bump-PR (default: "release")
21
- # (Angle-brackets in this doc comment are intentional — they avoid being
22
- # substituted by the {{...}} regex pass. The placeholders below use {{...}}.)
23
-
24
- name: Release Prepare
25
-
26
- # R-200: workflow_dispatch only — MUST NOT trigger on push to any branch.
27
- # R-201: required input `version`; optional `plan-blob-sha256`, `epic`, `channel`.
28
- on:
29
- workflow_dispatch:
30
- inputs:
31
- version:
32
- description: 'Version to release (e.g. v2026.6.0)'
33
- type: string
34
- required: true
35
- plan-blob-sha256:
36
- description: 'SHA256 of pre-computed plan JSON (optional)'
37
- type: string
38
- required: false
39
- epic:
40
- description: 'Epic task ID (e.g. T9999) used by `cleo release plan`'
41
- type: string
42
- required: false
43
- channel:
44
- description: 'Release channel'
45
- type: choice
46
- required: false
47
- default: latest
48
- options:
49
- - latest
50
- - beta
51
- - alpha
52
- - rc
53
-
54
- # R-202: contents:write (commit + branch), pull-requests:write (gh pr create),
55
- # id-token:write (signed tags only). MUST NOT request packages:write — npm
56
- # publish belongs to release-publish.yml.
57
- permissions:
58
- contents: write
59
- pull-requests: write
60
- id-token: write
61
-
62
- # R-207: concurrent prepare runs against the same version queue rather than
63
- # collide. cancel-in-progress=false preserves in-flight work.
64
- concurrency:
65
- group: release-prepare-${{ inputs.version }}
66
- cancel-in-progress: false
67
-
68
- # R-262: bash everywhere — no cross-platform shell drift.
69
- defaults:
70
- run:
71
- shell: bash
72
-
73
- jobs:
74
- # R-204: lint + typecheck + test + build BEFORE any commit. Failure here
75
- # MUST fail the workflow and prevent `prepare` from running.
76
- preflight:
77
- name: Preflight (lint + typecheck + test + build)
78
- runs-on: ubuntu-latest
79
- timeout-minutes: 20
80
- steps:
81
- # R-263: third-party Actions pinned to major+minor.
82
- - name: Checkout
83
- uses: actions/checkout@v4.1
84
- with:
85
- fetch-depth: 0
86
- timeout-minutes: 5
87
-
88
- - name: Set up Node.js
89
- uses: actions/setup-node@v4.0
90
- with:
91
- node-version: '{{NODE_VERSION}}'
92
- timeout-minutes: 3
93
-
94
- - name: Install dependencies
95
- run: {{INSTALL_CMD}}
96
- timeout-minutes: 5
97
-
98
- - name: Lint
99
- run: {{LINT_CMD}}
100
- timeout-minutes: 5
101
-
102
- - name: Typecheck
103
- run: {{TYPECHECK_CMD}}
104
- timeout-minutes: 5
105
-
106
- - name: Test
107
- run: {{TEST_CMD}}
108
- timeout-minutes: 10
109
-
110
- - name: Build
111
- run: {{BUILD_CMD}}
112
- timeout-minutes: 10
113
-
114
- # R-208: status check `release-prepare/preflight` is reported by GitHub
115
- # automatically against the bump-PR head SHA once the PR is open. No
116
- # extra step is required — branch protection MUST require this check.
117
-
118
- # R-203: prepare needs preflight.
119
- # R-205: plan resolution → version bump → CHANGELOG → commit → push → bump-PR.
120
- prepare:
121
- name: Prepare bump-PR
122
- runs-on: ubuntu-latest
123
- needs: preflight
124
- timeout-minutes: 20
125
- outputs:
126
- branch: ${{ steps.branch.outputs.name }}
127
- branch_created: ${{ steps.push.outputs.created }}
128
- env:
129
- # R-210: only GITHUB_TOKEN required. NPM_TOKEN is publish-only.
130
- GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
131
- steps:
132
- - name: Checkout
133
- uses: actions/checkout@v4.1
134
- with:
135
- fetch-depth: 0
136
- token: ${{ secrets.GITHUB_TOKEN }}
137
- timeout-minutes: 5
138
-
139
- - name: Configure git identity
140
- run: |
141
- git config user.email "actions@github.com"
142
- git config user.name "GitHub Actions"
143
- timeout-minutes: 1
144
-
145
- - name: Cut release branch
146
- id: branch
147
- run: |
148
- BRANCH="{{BRANCH_PREFIX}}/${{ inputs.version }}"
149
- git checkout -b "$BRANCH"
150
- echo "name=$BRANCH" >> "$GITHUB_OUTPUT"
151
- timeout-minutes: 2
152
-
153
- - name: Set up Node.js
154
- uses: actions/setup-node@v4.0
155
- with:
156
- node-version: '{{NODE_VERSION}}'
157
- timeout-minutes: 3
158
-
159
- - name: Install dependencies
160
- run: {{INSTALL_CMD}}
161
- timeout-minutes: 5
162
-
163
- # R-205(a)/(b): resolve plan — call `cleo release plan` if sha is empty,
164
- # otherwise verify the existing plan blob via sha256.
165
- - name: Resolve release plan
166
- id: plan
167
- run: |
168
- mkdir -p .cleo/release
169
- PLAN_FILE=".cleo/release/${{ inputs.version }}.plan.json"
170
- if [ -z "${{ inputs.plan-blob-sha256 }}" ]; then
171
- echo "No plan-blob-sha256 input — generating fresh plan."
172
- EPIC_ARGS=()
173
- if [ -n "${{ inputs.epic }}" ]; then
174
- EPIC_ARGS=(--epic "${{ inputs.epic }}")
175
- fi
176
- cleo release plan "${{ inputs.version }}" "${EPIC_ARGS[@]}" --json > "$PLAN_FILE"
177
- else
178
- echo "Verifying pre-computed plan against sha256=${{ inputs.plan-blob-sha256 }}"
179
- if [ ! -f "$PLAN_FILE" ]; then
180
- echo "::error::Plan file $PLAN_FILE not found — cannot verify sha256"
181
- exit 1
182
- fi
183
- ACTUAL=$(sha256sum "$PLAN_FILE" | awk '{print $1}')
184
- if [ "$ACTUAL" != "${{ inputs.plan-blob-sha256 }}" ]; then
185
- echo "::error::Plan sha256 mismatch — expected ${{ inputs.plan-blob-sha256 }}, got $ACTUAL"
186
- exit 1
187
- fi
188
- fi
189
- echo "plan_file=$PLAN_FILE" >> "$GITHUB_OUTPUT"
190
- timeout-minutes: 5
191
-
192
- # R-205(c): bump version files via `cleo version-bump`.
193
- - name: Bump version
194
- run: cleo version-bump --version "${{ inputs.version }}"
195
- timeout-minutes: 3
196
-
197
- # R-205(d): regenerate CHANGELOG via the preserved `cleo release
198
- # changelog` primitive, scoped to commits since the previous tag.
199
- - name: Regenerate CHANGELOG
200
- run: |
201
- PREV_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
202
- if [ -n "$PREV_TAG" ]; then
203
- cleo release changelog --since "$PREV_TAG"
204
- else
205
- cleo release changelog
206
- fi
207
- timeout-minutes: 3
208
-
209
- # R-205(e): commit with the canonical subject line.
210
- - name: Commit prepare
211
- run: |
212
- git add -A
213
- git commit -m "release: prepare ${{ inputs.version }}"
214
- timeout-minutes: 2
215
-
216
- - name: Push branch
217
- id: push
218
- run: |
219
- git push origin "${{ steps.branch.outputs.name }}"
220
- echo "created=true" >> "$GITHUB_OUTPUT"
221
- timeout-minutes: 5
222
-
223
- # R-205(f): open the bump-PR via `gh pr create`.
224
- - name: Open bump-PR
225
- run: |
226
- gh pr create \
227
- --base main \
228
- --head "${{ steps.branch.outputs.name }}" \
229
- --title "release: prepare ${{ inputs.version }}" \
230
- --label "{{PR_LABEL}}" \
231
- --body-file "${{ steps.plan.outputs.plan_file }}"
232
- timeout-minutes: 5
233
-
234
- # R-209(c): emit recovery hint into the job summary artifact.
235
- - name: Emit recovery hint to job summary
236
- if: always()
237
- run: |
238
- {
239
- echo "## Release Prepare — ${{ inputs.version }}"
240
- echo ""
241
- echo "Branch: \`${{ steps.branch.outputs.name }}\`"
242
- echo ""
243
- echo "**Recovery command** (if anything went wrong):"
244
- echo ""
245
- echo "\`\`\`"
246
- echo "cleo release plan ${{ inputs.version }} --epic ${{ inputs.epic }}; cleo release open ${{ inputs.version }}"
247
- echo "\`\`\`"
248
- } >> "$GITHUB_STEP_SUMMARY"
249
- timeout-minutes: 1
250
-
251
- # R-209(a)(b): on failure, delete the half-cut release branch and print
252
- # the recovery command. continue-on-error so cleanup itself cannot fail
253
- # the workflow further.
254
- cleanup-on-failure:
255
- name: Cleanup on failure
256
- runs-on: ubuntu-latest
257
- needs:
258
- - preflight
259
- - prepare
260
- if: failure()
261
- timeout-minutes: 10
262
- env:
263
- GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
264
- steps:
265
- - name: Checkout
266
- uses: actions/checkout@v4.1
267
- with:
268
- fetch-depth: 0
269
- token: ${{ secrets.GITHUB_TOKEN }}
270
- timeout-minutes: 5
271
-
272
- - name: Delete release branch (best-effort)
273
- continue-on-error: true
274
- run: |
275
- BRANCH="{{BRANCH_PREFIX}}/${{ inputs.version }}"
276
- if git ls-remote --exit-code --heads origin "$BRANCH" >/dev/null 2>&1; then
277
- echo "Deleting remote branch $BRANCH"
278
- git push origin --delete "$BRANCH" || true
279
- else
280
- echo "No remote branch $BRANCH to delete."
281
- fi
282
- timeout-minutes: 5
283
-
284
- - name: Print recovery command
285
- run: |
286
- echo "::notice::Recovery: cleo release plan ${{ inputs.version }} --epic ${{ inputs.epic }}; cleo release open ${{ inputs.version }}"
287
- {
288
- echo "## Release Prepare FAILED — ${{ inputs.version }}"
289
- echo ""
290
- echo "Run this to recover:"
291
- echo ""
292
- echo "\`\`\`"
293
- echo "cleo release plan ${{ inputs.version }} --epic ${{ inputs.epic }}; cleo release open ${{ inputs.version }}"
294
- echo "\`\`\`"
295
- } >> "$GITHUB_STEP_SUMMARY"
296
- timeout-minutes: 1