@icebreakers/monorepo-templates 2.2.0 → 2.3.0
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.
- package/assets/.agents/skills/repoctl/references/commands.md +5 -0
- package/assets/.github/workflows/ci.yml +1 -1
- package/assets/.github/workflows/release.yml +34 -0
- package/assets/package.json +5 -5
- package/assets/pnpm-workspace.yaml +5 -5
- package/package.json +5 -5
- package/templates/client/package.json +7 -7
- package/templates/next/package.json +3 -3
- package/templates/nimbus/UPSTREAM.md +3 -3
- package/templates/nimbus/nimbus.json +1 -1
- package/templates/nimbus/package.json +2 -2
- package/templates/react-lib/package.json +4 -4
- package/templates/react-vite/package.json +3 -3
- package/templates/server/package.json +1 -1
- package/templates/vitepress/package.json +2 -2
- package/templates/vitepress/tasks/release.md +23 -3
- package/templates/vitepress/zh/tasks/release.md +22 -2
- package/templates/vue-lib/package.json +4 -4
|
@@ -153,11 +153,16 @@ Usage:
|
|
|
153
153
|
- `pnpm exec repo release ci --mode prepare`
|
|
154
154
|
- `pnpm exec repo release ci --mode publish`
|
|
155
155
|
- `pnpm exec repo release ci --mode publish-unpublished --package <name> --version <version>`
|
|
156
|
+
- `pnpm exec repo release ci --mode oidc-audit`
|
|
156
157
|
|
|
157
158
|
The command uses `GITHUB_TOKEN`, `GITHUB_REPOSITORY`, `GITHUB_API_URL`, and
|
|
158
159
|
`GITHUB_SHA` to upsert the Release PR, package tags, and GitHub Releases. It
|
|
159
160
|
consumes `pnpm-publish-summary.json` and is safe to retry.
|
|
160
161
|
|
|
162
|
+
`oidc-audit` independently checks every versioned public child package using the current GitHub-hosted job's OIDC identity and the official npm registry. It returns safe JSON (`schemaVersion: 1`) with allowlisted identity fields, per-package HTTP status/message and aggregate success. The CLI fails if any exchange fails, but still checks all packages. It does not load release configuration, consume intents, execute quality scripts/hooks, publish, or create tags/Releases. Recovery flags (`source-sha`, `dry-run`, `package`, `version`) are incompatible. The managed workflow has a separate read-only audit job with Node 24, `id-token: write` and installation lifecycle scripts disabled; generated projects need only installed repoctl, while the source workspace builds its tooling closure.
|
|
163
|
+
|
|
164
|
+
Use `auditReleaseOidc({ cwd, env?, fetch? })` for the same programmatic report. JWTs, request tokens and exchange tokens are never included or saved. A 404 alone cannot identify expired trust: check npm package settings and repository/workflow/environment matching. If npm explicitly says `Expired`, delete/recreate the configuration and perform the first successful publish within 48 hours under [npm's policy](https://github.blog/changelog/2026-10-02-unvalidated-npm-trusted-publishing-configurations-now-expire/). A successful exchange does not complete that initial publish validation; auditing immediately before publishing narrows that gap.
|
|
165
|
+
|
|
161
166
|
## workspace upgrade (alias: ws up)
|
|
162
167
|
|
|
163
168
|
Purpose: sync monorepo assets and scripts into the workspace.
|
|
@@ -22,6 +22,7 @@ on:
|
|
|
22
22
|
- publish
|
|
23
23
|
- publish-unpublished
|
|
24
24
|
- reconcile
|
|
25
|
+
- oidc-audit
|
|
25
26
|
package:
|
|
26
27
|
description: Package used for unpublished-version recovery
|
|
27
28
|
required: false
|
|
@@ -56,6 +57,7 @@ concurrency:
|
|
|
56
57
|
|
|
57
58
|
jobs:
|
|
58
59
|
release:
|
|
60
|
+
if: ${{ inputs.mode != 'oidc-audit' }}
|
|
59
61
|
name: Release
|
|
60
62
|
runs-on: ubuntu-latest
|
|
61
63
|
steps:
|
|
@@ -122,3 +124,35 @@ jobs:
|
|
|
122
124
|
repoctl-release-progress.json
|
|
123
125
|
if-no-files-found: ignore
|
|
124
126
|
retention-days: 14
|
|
127
|
+
|
|
128
|
+
oidc-audit:
|
|
129
|
+
name: Audit npm OIDC
|
|
130
|
+
if: ${{ github.event_name == 'workflow_dispatch' && inputs.mode == 'oidc-audit' }}
|
|
131
|
+
runs-on: ubuntu-latest
|
|
132
|
+
permissions:
|
|
133
|
+
contents: read
|
|
134
|
+
id-token: write
|
|
135
|
+
steps:
|
|
136
|
+
- name: Checkout Repo
|
|
137
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
138
|
+
with:
|
|
139
|
+
persist-credentials: false
|
|
140
|
+
|
|
141
|
+
- uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
|
|
142
|
+
|
|
143
|
+
- name: Setup Node.js environment
|
|
144
|
+
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
|
145
|
+
with:
|
|
146
|
+
node-version: 24
|
|
147
|
+
cache: pnpm
|
|
148
|
+
|
|
149
|
+
- name: Install Dependencies without lifecycle scripts
|
|
150
|
+
run: pnpm install --frozen-lockfile --ignore-scripts
|
|
151
|
+
|
|
152
|
+
- name: Audit every publishable package
|
|
153
|
+
env:
|
|
154
|
+
REPO_RELEASE_PACKAGE: ${{ inputs.package }}
|
|
155
|
+
REPO_RELEASE_VERSION: ${{ inputs.version }}
|
|
156
|
+
REPO_RELEASE_DRY_RUN: ${{ inputs.dry-run }}
|
|
157
|
+
REPO_RELEASE_RECOVERY_SOURCE_SHA: ${{ inputs.source-sha }}
|
|
158
|
+
run: pnpm exec repo release ci --mode oidc-audit
|
package/assets/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"type": "module",
|
|
4
4
|
"version": "0.0.0",
|
|
5
5
|
"private": true,
|
|
6
|
-
"packageManager": "pnpm@12.
|
|
6
|
+
"packageManager": "pnpm@12.9.1",
|
|
7
7
|
"description": "Source workspace for repoctl and Icebreaker's shared development packages",
|
|
8
8
|
"author": "ice breaker <hi@sonofmagic.top>",
|
|
9
9
|
"license": "MIT",
|
|
@@ -69,10 +69,10 @@
|
|
|
69
69
|
"devDependencies": {
|
|
70
70
|
"@commitlint/cli": "^21.2.3",
|
|
71
71
|
"@eslint/config-inspector": "^3.5.0",
|
|
72
|
-
"@types/node": "^26.6.
|
|
72
|
+
"@types/node": "^26.6.4",
|
|
73
73
|
"@vitest/coverage-v8": "~5.0.3",
|
|
74
|
-
"eslint": "^10.
|
|
75
|
-
"execa": "^10.0
|
|
74
|
+
"eslint": "^10.12.0",
|
|
75
|
+
"execa": "^10.1.0",
|
|
76
76
|
"husky": "^9.1.7",
|
|
77
77
|
"lint-staged": "^17.6.0",
|
|
78
78
|
"only-allow": "^1.2.2",
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
"tailwindcss": "^4.3.3",
|
|
82
82
|
"tsd": "^0.33.0",
|
|
83
83
|
"tsdown": "0.23.0",
|
|
84
|
-
"turbo": "^2.11.
|
|
84
|
+
"turbo": "^2.11.7",
|
|
85
85
|
"typescript": "^6.0.3",
|
|
86
86
|
"vitest": "~5.0.3",
|
|
87
87
|
"yaml": "^2.9.1"
|
|
@@ -18,12 +18,12 @@ allowBuilds:
|
|
|
18
18
|
overrides:
|
|
19
19
|
prettier: 3.9.9
|
|
20
20
|
typescript: 6.0.3
|
|
21
|
-
"@arethetypeswrong/core>typescript": 5.
|
|
22
|
-
vite: 8.3.
|
|
23
|
-
postcss: 8.5.
|
|
21
|
+
"@arethetypeswrong/core>typescript": 5.9.3
|
|
22
|
+
vite: 8.3.3
|
|
23
|
+
postcss: 8.5.29
|
|
24
24
|
postcss-selector-parser: 7.1.6
|
|
25
|
-
js-yaml: 5.4.
|
|
26
|
-
nanoid: 6.0.
|
|
25
|
+
js-yaml: 5.4.3
|
|
26
|
+
nanoid: 6.0.2
|
|
27
27
|
brace-expansion: 5.0.12
|
|
28
28
|
minimatch@<4>brace-expansion: 1.1.21
|
|
29
29
|
minimatch@>=4 <10>brace-expansion: 2.1.7
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@icebreakers/monorepo-templates",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.3.0",
|
|
5
5
|
"description": "Built-in project templates and managed workspace assets for repoctl",
|
|
6
6
|
"author": "ice breaker <hi@sonofmagic.top>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -46,10 +46,10 @@
|
|
|
46
46
|
"node": ">=22.13.0"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@inquirer/checkbox": "^5.2.
|
|
50
|
-
"@inquirer/input": "^5.1.
|
|
51
|
-
"@inquirer/password": "^5.2.
|
|
52
|
-
"@inquirer/select": "^5.2.
|
|
49
|
+
"@inquirer/checkbox": "^5.2.6",
|
|
50
|
+
"@inquirer/input": "^5.1.7",
|
|
51
|
+
"@inquirer/password": "^5.2.3",
|
|
52
|
+
"@inquirer/select": "^5.2.6",
|
|
53
53
|
"commander": "^15.0.0",
|
|
54
54
|
"nanoexec": "^1.1.0",
|
|
55
55
|
"yaml": "^2.9.1"
|
|
@@ -37,9 +37,9 @@
|
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"@faker-js/faker": "^10.6.0",
|
|
40
|
-
"@tanstack/vue-query": "^5.104.
|
|
41
|
-
"@tanstack/vue-query-devtools": "^6.3.
|
|
42
|
-
"@tanstack/vue-table": "^9.2.
|
|
40
|
+
"@tanstack/vue-query": "^5.104.1",
|
|
41
|
+
"@tanstack/vue-query-devtools": "^6.3.1",
|
|
42
|
+
"@tanstack/vue-table": "^9.2.6",
|
|
43
43
|
"@tanstack/vue-virtual": "^3.13.39",
|
|
44
44
|
"@trpc/client": "^11.19.0",
|
|
45
45
|
"clsx": "^2.1.1",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"tailwind-merge": "^3.7.0",
|
|
48
48
|
"tailwind-variants": "^3.3.1",
|
|
49
49
|
"vue": "^3.5.43",
|
|
50
|
-
"vue-i18n": "^11.4.
|
|
50
|
+
"vue-i18n": "^11.4.13",
|
|
51
51
|
"vue-router": "^5.3.1"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
@@ -60,13 +60,13 @@
|
|
|
60
60
|
"@vitejs/plugin-vue-jsx": "^5.1.6",
|
|
61
61
|
"@vue/tsconfig": "^0.9.1",
|
|
62
62
|
"consola": "^3.4.2",
|
|
63
|
-
"hono": "^4.13.
|
|
63
|
+
"hono": "^4.13.13",
|
|
64
64
|
"tailwindcss": "^4.3.3",
|
|
65
65
|
"typescript": "~6.0.3",
|
|
66
|
-
"vite": "^8.3.
|
|
66
|
+
"vite": "^8.3.3",
|
|
67
67
|
"vite-plugin-vue-devtools": "^8.2.1",
|
|
68
68
|
"vite-tsconfig-paths": "^6.1.1",
|
|
69
|
-
"vue-tsc": "3.3.
|
|
69
|
+
"vue-tsc": "3.3.12",
|
|
70
70
|
"wrangler": "^4.135.0",
|
|
71
71
|
"zod": "^4.6.5"
|
|
72
72
|
}
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"test:dev": "vitest"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"next": "16.
|
|
22
|
+
"next": "16.4.0",
|
|
23
23
|
"react": "^19.3.0",
|
|
24
24
|
"react-dom": "^19.3.0"
|
|
25
25
|
},
|
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
"@testing-library/react": "^16.3.3",
|
|
29
29
|
"@types/react": "^19.3.0",
|
|
30
30
|
"@types/react-dom": "^19.3.0",
|
|
31
|
-
"@vitejs/plugin-react": "^6.1.
|
|
32
|
-
"jsdom": "^30.1.
|
|
31
|
+
"@vitejs/plugin-react": "^6.1.2",
|
|
32
|
+
"jsdom": "^30.1.2",
|
|
33
33
|
"typescript": "~6.0.3",
|
|
34
34
|
"vitest": "~5.0.3"
|
|
35
35
|
}
|
|
@@ -4,10 +4,10 @@ This template adapts the static empty starter from [Cloudflare Nimbus](https://g
|
|
|
4
4
|
|
|
5
5
|
- Starter tag: `templates-v0.7.9`
|
|
6
6
|
- Starter commit: `aae348048a8c659f84c39696ee6b20c2ad2f5ae2`
|
|
7
|
-
- Nimbus package: `@cloudflare/nimbus-docs@0.
|
|
8
|
-
- Astro: `7.3.
|
|
7
|
+
- Nimbus package: `@cloudflare/nimbus-docs@0.16.0`
|
|
8
|
+
- Astro: `7.3.6`
|
|
9
9
|
|
|
10
|
-
Nimbus declares Astro `>=7.2.6 <8`; Astro requires Node `>=22.12.0`, so this workspace retains its stricter Node `>=22.13.0` baseline. Builds, Astro diagnostics and TypeScript checks were verified with the repository's TypeScript `6.0.3` and Vite `8.3.
|
|
10
|
+
Nimbus declares Astro `>=7.2.6 <8`; Astro requires Node `>=22.12.0`, so this workspace retains its stricter Node `>=22.13.0` baseline. Builds, Astro diagnostics and TypeScript checks were verified with the repository's TypeScript `6.0.3` and Vite `8.3.3` constraints. Resolved dependencies are recorded in the monorepo's root `pnpm-lock.yaml`; generated projects use their own root workspace lockfile.
|
|
11
11
|
|
|
12
12
|
Agent endpoint routes and the content-loading approach come from that starter. The bilingual layout, navigation, search interface, examples and workspace checks are repoctl adaptations. These files are maintained locally; generating a project never downloads the upstream starter.
|
|
13
13
|
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
"check:locales": "node scripts/check-locales.mjs"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@cloudflare/nimbus-docs": "0.
|
|
23
|
-
"astro": "7.3.
|
|
22
|
+
"@cloudflare/nimbus-docs": "0.16.0",
|
|
23
|
+
"astro": "7.3.6"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"@astrojs/check": "^0.9.10",
|
|
@@ -35,14 +35,14 @@
|
|
|
35
35
|
"@testing-library/react": "^16.3.3",
|
|
36
36
|
"@types/react": "^19.3.0",
|
|
37
37
|
"@types/react-dom": "^19.3.0",
|
|
38
|
-
"@vitejs/plugin-react": "^6.1.
|
|
39
|
-
"jsdom": "^30.1.
|
|
38
|
+
"@vitejs/plugin-react": "^6.1.2",
|
|
39
|
+
"jsdom": "^30.1.2",
|
|
40
40
|
"react": "^19.3.0",
|
|
41
41
|
"react-dom": "^19.3.0",
|
|
42
42
|
"tsd": "^0.33.0",
|
|
43
43
|
"typescript": "~6.0.3",
|
|
44
|
-
"vite": "^8.3.
|
|
45
|
-
"vite-plugin-dts": "^5.1.
|
|
44
|
+
"vite": "^8.3.3",
|
|
45
|
+
"vite-plugin-dts": "^5.1.2",
|
|
46
46
|
"vitest": "~5.0.3"
|
|
47
47
|
}
|
|
48
48
|
}
|
|
@@ -27,10 +27,10 @@
|
|
|
27
27
|
"@testing-library/react": "^16.3.3",
|
|
28
28
|
"@types/react": "^19.3.0",
|
|
29
29
|
"@types/react-dom": "^19.3.0",
|
|
30
|
-
"@vitejs/plugin-react": "^6.1.
|
|
31
|
-
"jsdom": "^30.1.
|
|
30
|
+
"@vitejs/plugin-react": "^6.1.2",
|
|
31
|
+
"jsdom": "^30.1.2",
|
|
32
32
|
"typescript": "~6.0.3",
|
|
33
|
-
"vite": "^8.3.
|
|
33
|
+
"vite": "^8.3.3",
|
|
34
34
|
"vitest": "~5.0.3"
|
|
35
35
|
}
|
|
36
36
|
}
|
|
@@ -42,12 +42,12 @@
|
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@tailwindcss/vite": "^4.3.3",
|
|
45
|
-
"mermaid": "^12.
|
|
45
|
+
"mermaid": "^12.1.0",
|
|
46
46
|
"tailwindcss": "^4.3.3",
|
|
47
47
|
"vitepress": "2.0.0-alpha.20",
|
|
48
48
|
"vitepress-plugin-llms": "^1.14.0",
|
|
49
49
|
"vitest": "~5.0.3",
|
|
50
|
-
"vue-tsc": "^3.3.
|
|
50
|
+
"vue-tsc": "^3.3.12",
|
|
51
51
|
"wrangler": "^4.135.0"
|
|
52
52
|
}
|
|
53
53
|
}
|
|
@@ -67,13 +67,29 @@ After changing the mapping, preview `repo upgrade --dry-run --json` and apply th
|
|
|
67
67
|
|
|
68
68
|
- Missing intent: add a changeset and rerun the plan.
|
|
69
69
|
- Fixed group mismatch: inspect the package relationships before editing versions.
|
|
70
|
-
- Registry authentication failure:
|
|
70
|
+
- Registry authentication failure in CI: run the OIDC audit below from the publishing workflow and inspect npm package settings.
|
|
71
|
+
|
|
72
|
+
## Audit npm trusted publishing
|
|
73
|
+
|
|
74
|
+
Choose `oidc-audit` when manually dispatching the managed Release workflow, or run this in your existing GitHub-hosted publishing job:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
pnpm exec repo release ci --mode oidc-audit
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The job needs `id-token: write`, Node 24 and the same repository, workflow file and environment as actual publishing. A different diagnostic workflow has a different identity. The managed workflow uses a separate audit job with only `contents: read` and `id-token: write`, disables install lifecycle scripts and skips GitHub App credentials and release quality checks. Only the repoctl source workspace builds its tooling closure; consumer workflows use the installed CLI. Custom workflows should use the same isolation and install with `pnpm install --frozen-lockfile --ignore-scripts`.
|
|
81
|
+
|
|
82
|
+
The command independently routes before release configuration and checks every versioned public child package against the official npm registry, including packages already published. It requests short-lived exchange credentials but never uploads packages, changes versions/intents, runs hooks, writes progress files, creates tags/Releases or saves tokens. `source-sha`, `dry-run`, `package` and `version` recovery inputs must be empty. JSON includes `schemaVersion: 1`, safe identity fields, each package's HTTP status/message and `ok`; failures complete the whole package report before exiting with code 1. `auditReleaseOidc({ cwd, env?, fetch? })` exposes the same report without printing it; callers must check `ok`.
|
|
83
|
+
|
|
84
|
+
An npm HTTP 404 or `OIDC token exchange error - package not found` does not by itself distinguish a missing package, mismatched trust or expired configuration. Check the npm package's trusted publisher status and compare repository, workflow and environment with the safe identity report. Never paste JWTs or exchange tokens into logs or support requests.
|
|
85
|
+
|
|
86
|
+
Under [npm's initial validation policy](https://github.blog/changelog/2026-10-02-unvalidated-npm-trusted-publishing-configurations-now-expire/), configurations without a first successful publish expire after 48 hours. If the npm page explicitly shows `Expired`, delete and recreate that package's trusted publisher, then complete the first publish within 48 hours. Editing an expired configuration does not reset it. Existing configuration, successful exchange and successful first publish are separate evidence; an audit does not reset or satisfy this clock. After the first successful publish, that initial 48-hour limit no longer applies. Use OIDC/provenance for publication and keep npm token fallbacks out of publishing jobs.
|
|
71
87
|
|
|
72
88
|
## Partial publication and registry visibility
|
|
73
89
|
|
|
74
90
|
The publisher attempts uploads at most three times, waiting 20 and 40 seconds before refreshing registry state and selecting retry packages. An exact version with explicit upload acceptance is never uploaded again during that invocation, even if `npm view` cannot find it yet. Ordinary permission errors and 404 responses without transient-failure evidence fail immediately. Conflicts require read-only registry confirmation.
|
|
75
91
|
|
|
76
|
-
Accepted uploads must become queryable before post-publish hooks, Git tags, GitHub Releases, or prerelease pushes proceed. Visibility checks query pending versions every 10 seconds for up to
|
|
92
|
+
Upload acceptance means npm received the version; registry queries can still take several minutes to show it. Accepted uploads must become queryable before post-publish hooks, Git tags, GitHub Releases, or prerelease pushes proceed. Visibility checks query pending versions every 10 seconds for up to 15 minutes. A timeout exits unsuccessfully and lists pending versions while preserving the acceptance evidence.
|
|
77
93
|
|
|
78
94
|
Two files remain in the workspace root:
|
|
79
95
|
|
|
@@ -82,6 +98,8 @@ Two files remain in the workspace root:
|
|
|
82
98
|
|
|
83
99
|
The managed Release workflow uploads both files as `npm-publish-progress-<run_id>-<run_attempt>` on success or failure, retained for 14 days. Missing reports are ignored. After upgrading repoctl, run `repo upgrade` to refresh managed workflows; custom workflows can add the same upload step.
|
|
84
100
|
|
|
101
|
+
After a visibility timeout, keep the durable checkpoint on `repoctl-release-state` and resume with `repo release ci --mode publish --source-sha <full-release-line-commit-sha>`, previewing with `--dry-run` first. Recovery uses the original prepared versions and saved acceptance evidence to confirm visibility and finish missing metadata without uploading accepted versions again.
|
|
102
|
+
|
|
85
103
|
## Recovery across runners
|
|
86
104
|
|
|
87
105
|
`repo release ci --mode=publish` tracks release targets separately from new npm uploads. Before uploading, the built-in GitHub client writes exact versions, original commits, accepted-upload evidence, metadata progress, and individual hook states to the repository's `repoctl-release-state` branch. The key includes repository, dist-tag, and candidate versions. Writes compare the file SHA to reject concurrent changes. Keep this branch, grant `contents: write`, and serialize all workflows that publish the same packages.
|
|
@@ -105,7 +123,7 @@ Dry-run queries remote state and shows versions, original commits, npm stage, mi
|
|
|
105
123
|
|
|
106
124
|
Hook script names must be unique; retain the original script set when recovering. Each hook is checkpointed as `running` before execution and `complete` after success. Optional failures become `ignored`. Unknown non-idempotent outcomes require manual review. Set `idempotent: true` on an `afterPublish` hook only when repeated execution is safe. After verifying external completion, `REPO_RELEASE_ACKNOWLEDGE_HOOKS=script-name` acknowledges it without execution (comma-separated for multiple scripts).
|
|
107
125
|
|
|
108
|
-
If a runner disappears during upload before responses are persisted, recovery performs read-only visibility confirmation for up to
|
|
126
|
+
If a runner disappears during upload before responses are persisted, recovery performs read-only visibility confirmation for up to 15 minutes. It fails with evidence if versions remain unknown, rather than blindly uploading again. After manually verifying that a version was never uploaded, use the existing exact `publish-unpublished` entry, then rerun the original target set to finish its hooks. Arbitrary external hooks cannot be guaranteed exactly-once.
|
|
109
127
|
|
|
110
128
|
Legacy injected `GitHubOperations` adapters retain their previous behavior. Recovery-capable adapters must implement `readReleaseState`, `writeReleaseState`, `listReleases`, and `ensureTag`; `readTagTarget` is recommended. Enforce revision comparison on writes and throw on query errors. A local summary is not a remote checkpoint.
|
|
111
129
|
|
|
@@ -127,6 +145,8 @@ The managed Release workflow exposes the same `source-sha` input for `publish` a
|
|
|
127
145
|
|
|
128
146
|
Recovery preserves GitHub's workflow environment for trusted publishing and provenance: its signed identity refers to the workflow run's commit. The isolated checkout, release checkpoint, Git tags, and Release targets refer to `source-sha`. Do not overwrite `GITHUB_SHA` to recover an older source; npm rejects provenance that disagrees with the signed workflow identity.
|
|
129
147
|
|
|
148
|
+
Validation scripts (`qualityScripts` and `hooks.verify`) do not inherit control inputs for the current release, such as its mode or recovery source. They retain ordinary CI and authentication environment variables. Other lifecycle hooks keep their release context.
|
|
149
|
+
|
|
130
150
|
## PR and nightly snapshots
|
|
131
151
|
|
|
132
152
|
Use a snapshot for downstream validation before a stable release. Commit the source first and preview the complete set of public workspace packages:
|
|
@@ -73,7 +73,7 @@ Release PR 以所选分支为 base。主正式线保留 `release/pnpm-version`
|
|
|
73
73
|
|
|
74
74
|
发布器最多尝试上传 3 次,重试前分别等待 20、40 秒并重新查询 registry。明确上传成功的精确版本不会再次上传,即使此时 `npm view` 暂不可查询。普通权限错误和没有瞬时故障依据的 404 会直接失败;冲突只能通过只读对账确认,不能当作成功。
|
|
75
75
|
|
|
76
|
-
|
|
76
|
+
上传已接收表示 npm 已收到该版本,registry 查询仍可能延迟数分钟才能看到它。已接收上传的版本需要确认可查询后,才会执行后置 hooks、Git tag 和 GitHub Release。确认期间每 10 秒查询待确认版本,最多等待 15 分钟;超时会非零退出并列出待确认版本,同时保留上传已接收的证据。
|
|
77
77
|
|
|
78
78
|
工作区根目录保留两份文件:
|
|
79
79
|
|
|
@@ -82,6 +82,8 @@ Release PR 以所选分支为 base。主正式线保留 `release/pnpm-version`
|
|
|
82
82
|
|
|
83
83
|
受管 Release 工作流会在发布成功或失败后上传 `npm-publish-progress-<run_id>-<run_attempt>` artifact,保留 14 天;没有清单时跳过上传。现有项目升级 repoctl 后运行 `repo upgrade` 更新受管工作流;自定义工作流可自行添加相同上传步骤。
|
|
84
84
|
|
|
85
|
+
可见性确认超时后,保留 `repoctl-release-state` 分支中的持久化检查点,使用 `repo release ci --mode publish --source-sha <完整的发布线提交-SHA>` 恢复,并先加 `--dry-run` 预演。恢复会读取原提交准备的版本和已保存的接收证据,继续确认可见性并补齐缺失元数据,不重复上传已接收的版本。
|
|
86
|
+
|
|
85
87
|
## 跨 runner 恢复与完成判定
|
|
86
88
|
|
|
87
89
|
`repo release ci --mode=publish` 不再把本轮 npm 上传列表当作发布目标。内置 GitHub 客户端在首次上传前,将精确包版本、原提交、npm 接收证据、元数据和逐个 hook 状态写入同仓库的 `repoctl-release-state` 分支。记录键包含仓库、dist-tag 和候选版本集合,写入采用文件 SHA 比较并交换。分支需要 `contents: write` 权限,并应保留;不要删除或手动修改检查点。受管工作流仍须保持发布串行,其他自定义工作流也应避免重叠发布。
|
|
@@ -111,7 +113,7 @@ const hook = { script: 'publish:extension', idempotent: true }
|
|
|
111
113
|
|
|
112
114
|
如果外部系统已确认脚本成功,可显式设置 `REPO_RELEASE_ACKNOWLEDGE_HOOKS=publish:extension` 后恢复;多个脚本用逗号分隔。该操作表示人工确认完成,不会再次执行脚本。确认失败或未知时,不应使用此开关。
|
|
113
115
|
|
|
114
|
-
如果 runner 在上传期间消失,检查点可能只有 `running`,而响应尚未持久化。恢复会先进行最多
|
|
116
|
+
如果 runner 在上传期间消失,检查点可能只有 `running`,而响应尚未持久化。恢复会先进行最多 15 分钟的只读可见性确认;仍不能确认时失败,保留证据,不盲目重传。真正未上传的版本经人工核实后,可用已有 `publish-unpublished` 精确恢复入口,再重跑原发布目标完成其 hook。对任意外部 hook 不承诺 exactly-once。
|
|
115
117
|
|
|
116
118
|
程序化注入的旧 `GitHubOperations` adapter 保留原行为;要启用跨 runner 恢复,需要实现 `readReleaseState`、`writeReleaseState`、`listReleases`、`ensureTag`,并建议提供 `readTagTarget`。写入必须校验 revision,查询错误必须抛出。仅有本地 summary 不能代替远端检查点。
|
|
117
119
|
|
|
@@ -133,6 +135,24 @@ repo release ci --mode prepare
|
|
|
133
135
|
|
|
134
136
|
恢复保留 GitHub 工作流环境,供可信发布和 provenance 使用:签名身份对应运行工作流的提交;独立检出的源码、发布检查点、Git tag 和 Release 目标则对应 `source-sha`。不要通过覆盖 `GITHUB_SHA` 恢复旧源码,npm 会拒绝与工作流签名身份不一致的 provenance。
|
|
135
137
|
|
|
138
|
+
验证脚本(`qualityScripts` 和 `hooks.verify`)不继承本次发布的控制参数,例如发布模式或恢复来源;普通 CI 与认证环境变量仍会保留。其他生命周期 hook 继续使用原有发布上下文。
|
|
139
|
+
|
|
140
|
+
## 核验 npm trusted publishing
|
|
141
|
+
|
|
142
|
+
在受管 Release 工作流的手动调度中选择 `oidc-audit`,或者在现有的 GitHub-hosted 发布 job 中运行:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
pnpm exec repo release ci --mode oidc-audit
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
job 需要 `id-token: write` 和 Node 24,并使用实际发布时的仓库、工作流文件及 environment。另建诊断工作流会改变身份。受管工作流使用独立的核验 job,只授予 `contents: read` 和 `id-token: write`,关闭安装 lifecycle scripts,跳过 GitHub App 令牌及发布质量检查。只有 repoctl 源码仓库构建工具依赖闭包;消费方直接使用已安装的 CLI。自定义工作流也应隔离这些步骤,使用 `pnpm install --frozen-lockfile --ignore-scripts` 安装。
|
|
149
|
+
|
|
150
|
+
命令在加载发布配置前独立路由,向官方 npm registry 逐个核验有版本号的公开子包,包含已发布的包。它只申请短时交换凭据,不上传包、不修改版本或 intent、不运行 hooks、不写进度文件、不创建 tag/Release,也不保存 token。`source-sha`、`dry-run`、`package` 和 `version` 恢复输入必须为空。JSON 包含 `schemaVersion: 1`、允许展示的身份字段、每包 HTTP 状态及 npm 错误信息、整体 `ok`;即使某包失败也会继续完成全部包报告,最后以退出码 1 失败。程序化 API `auditReleaseOidc({ cwd, env?, fetch? })` 返回同一报告而不打印;调用者须检查 `ok`。
|
|
151
|
+
|
|
152
|
+
HTTP 404 或 `OIDC token exchange error - package not found` 本身无法区分包不存在、信任声明不匹配或配置过期。核对 npm 包设置里的 trusted publisher 状态,以及报告中的仓库、工作流和 environment。不要把 JWT 或交换 token 复制到日志或求助信息。
|
|
153
|
+
|
|
154
|
+
根据 [npm 首次发布验证策略](https://github.blog/changelog/2026-10-02-unvalidated-npm-trusted-publishing-configurations-now-expire/),创建后 48 小时内没有首次成功发布的配置会过期。只有 npm 页面明确显示 `Expired` 时,才按过期处理:删除并重建该包的配置,在 48 小时内完成首次发布;单纯编辑不会重置它。“配置存在”“交换成功”“首次成功发布”是不同证据;核验不能重置或完成这个时限。首次成功发布后不再受初始 48 小时限制。实际发布继续使用 OIDC/provenance,不在发布 job 增加 npm token 兜底。
|
|
155
|
+
|
|
136
156
|
## 下一步
|
|
137
157
|
|
|
138
158
|
阅读[发包与变更日志](/zh/learn/monorepo/publish),再查看[报告与输出](/zh/tasks/reports)了解 CI 产物。
|
|
@@ -62,10 +62,10 @@
|
|
|
62
62
|
"@vitejs/plugin-vue": "^6.0.9",
|
|
63
63
|
"@vue/test-utils": "^2.5.1",
|
|
64
64
|
"@vue/tsconfig": "^0.9.1",
|
|
65
|
-
"jsdom": "^30.1.
|
|
66
|
-
"vite": "^8.3.
|
|
67
|
-
"vite-plugin-dts": "^5.1.
|
|
65
|
+
"jsdom": "^30.1.2",
|
|
66
|
+
"vite": "^8.3.3",
|
|
67
|
+
"vite-plugin-dts": "^5.1.2",
|
|
68
68
|
"vue": "^3.5.43",
|
|
69
|
-
"vue-tsc": "^3.3.
|
|
69
|
+
"vue-tsc": "^3.3.12"
|
|
70
70
|
}
|
|
71
71
|
}
|