release-skill 0.1.1 → 0.1.3
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +2 -2
- package/CHANGELOG.md +60 -0
- package/INSTALL.md +179 -5
- package/INSTALL.zh-CN.md +320 -0
- package/README.md +347 -67
- package/README.zh-CN.md +318 -59
- package/adapters/claude/.claude-plugin/marketplace.json +1 -1
- package/adapters/claude/.claude-plugin/plugin.json +1 -1
- package/adapters/claude/skills/release-help/SKILL.md +7 -4
- package/adapters/claude/skills/release-prepare/SKILL.md +11 -1
- package/adapters/claude/skills/release-publish/SKILL.md +6 -3
- package/adapters/claude/skills/release-reconcile/SKILL.md +1 -1
- package/adapters/claude/skills/release-setup/SKILL.md +111 -0
- package/adapters/claude/skills/release-verify/SKILL.md +5 -2
- package/adapters/codex/.codex-plugin/plugin.json +2 -2
- package/adapters/codex/skills/release-help/SKILL.md +7 -4
- package/adapters/codex/skills/release-prepare/SKILL.md +11 -1
- package/adapters/codex/skills/release-publish/SKILL.md +6 -3
- package/adapters/codex/skills/release-reconcile/SKILL.md +1 -1
- package/adapters/codex/skills/release-setup/SKILL.md +111 -0
- package/adapters/codex/skills/release-verify/SKILL.md +5 -2
- package/bin/release-skill.mjs +65 -9
- package/native/safe-write/prebuilds/darwin-arm64/safe_write.node +0 -0
- package/native/safe-write/prebuilds.json +22 -2
- package/native/safe-write/src/safe_write.cc +11 -2
- package/package.json +3 -1
- package/references/02-project-config.md +54 -3
- package/references/05-evidence-and-errors.md +6 -2
- package/schemas/release-plan.schema.json +550 -65
- package/schemas/release-project.schema.json +398 -29
- package/schemas/release-run.schema.json +165 -18
- package/skills/release-help/SKILL.md +7 -4
- package/skills/release-prepare/SKILL.md +11 -1
- package/skills/release-publish/SKILL.md +6 -3
- package/skills/release-reconcile/SKILL.md +1 -1
- package/skills/release-setup/SKILL.md +111 -0
- package/skills/release-verify/SKILL.md +5 -2
- package/skills-src/release-help/SKILL.md +7 -4
- package/skills-src/release-prepare/SKILL.md +11 -1
- package/skills-src/release-publish/SKILL.md +6 -3
- package/skills-src/release-reconcile/SKILL.md +1 -1
- package/skills-src/release-setup/SKILL.md +111 -0
- package/skills-src/release-verify/SKILL.md +5 -2
- package/src/adapters/contract.mjs +3 -0
- package/src/adapters/git-github.mjs +84 -2
- package/src/adapters/plugin-marketplace.mjs +65 -21
- package/src/adapters/push-snapshot.mjs +84 -17
- package/src/commands/prepare.mjs +223 -20
- package/src/commands/publish.mjs +45 -0
- package/src/commands/reconcile.mjs +152 -0
- package/src/commands/setup.mjs +886 -0
- package/src/commands/verify.mjs +122 -26
- package/src/core/config.mjs +34 -0
- package/src/core/errors.mjs +4 -0
- package/src/core/plan.mjs +123 -0
- package/src/core/previous-public-baseline.mjs +21 -1
- package/src/core/verification-gates.mjs +451 -0
- package/src/snapshot/frozen.mjs +89 -5
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "release-skill",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Safe preparation and frozen GitHub/npm production publishing with full happy end verification",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "release-skill contributors"
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
],
|
|
20
20
|
"defaultPrompt": [
|
|
21
21
|
"Assess this project for release readiness.",
|
|
22
|
-
"Prepare a release plan for version 0.1.
|
|
22
|
+
"Prepare a release plan for version 0.1.3.",
|
|
23
23
|
"Help me understand the release workflow."
|
|
24
24
|
]
|
|
25
25
|
}
|
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,66 @@
|
|
|
3
3
|
All notable changes to the `release-skill` plugin will be documented in this
|
|
4
4
|
file. The format is based on [Keep a Changelog](https://keepachangelog.com/).
|
|
5
5
|
|
|
6
|
+
## [0.1.3] - 2026-07-19
|
|
7
|
+
|
|
8
|
+
> `0.1.2` was an internal release candidate and was never published to npm or
|
|
9
|
+
> GitHub Releases. Its fixes are included here; `0.1.3` is the next public
|
|
10
|
+
> release after `0.1.1`.
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Create-once first-use setup**: `release-skill setup` performs deterministic,
|
|
15
|
+
read-only discovery of packages, plugin manifests, Git remotes, legacy
|
|
16
|
+
`public-release.json`, public-file hints, and project quality scripts. It
|
|
17
|
+
reports `NEEDS_INPUT` or `LOCAL_ONLY_DETECTED` honestly and writes only an
|
|
18
|
+
absent `.release-skill/project.yaml` after answers and the exact
|
|
19
|
+
`setupDigest` are confirmed.
|
|
20
|
+
- **Discoverable `release-setup` skill**: Claude and Codex adapters now guide
|
|
21
|
+
users through candidate review, explicit gate selection, fact-drift handling,
|
|
22
|
+
and the safe handoff to `release-assess` without regenerating human content.
|
|
23
|
+
- **Project verification gates**: `snapshot-verify` runs selected commands in a
|
|
24
|
+
disposable writable copy of the frozen public snapshot;
|
|
25
|
+
`consumer-verify` runs after an exact isolated npm/Claude/Codex installation.
|
|
26
|
+
Gate definitions, exact execution-input digests, and bounded output digests
|
|
27
|
+
are frozen into plan/run evidence.
|
|
28
|
+
- **Identity-bound create-once setup**: the final facts/answers digest and
|
|
29
|
+
config bytes are bound immediately before a directory-handle-relative,
|
|
30
|
+
no-follow create. v0.1.3 ships a digest-registered `darwin-arm64` prebuild;
|
|
31
|
+
unsupported platforms fail closed instead of using pathname writes.
|
|
32
|
+
- **Explicit production branch strategies**: projects can create an immutable
|
|
33
|
+
release branch, fast-forward an existing branch from an exact bound baseline,
|
|
34
|
+
or initialize an absent standard branch and make a separately approved,
|
|
35
|
+
observable, reconcilable default-branch change.
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
|
|
39
|
+
- Existing `public-release.json` snapshot commands are surfaced only as
|
|
40
|
+
migration candidates. Discovery never grants execution authority; gate and
|
|
41
|
+
legacy-hook side effects still require separate explicit acknowledgements.
|
|
42
|
+
- Compatibility configurations for artifact-graph, flow-architect, loop-agent,
|
|
43
|
+
and agent-method-registry now bind real tag/channel/baseline semantics and
|
|
44
|
+
project-owned verification behavior. glaf4-test is represented as local-only
|
|
45
|
+
instead of receiving an invented remote channel.
|
|
46
|
+
- README and installation guidance now begin with safe setup, explain the three
|
|
47
|
+
branch strategies, and distinguish pre-freeze hooks from frozen-snapshot and
|
|
48
|
+
installed-consumer gates.
|
|
49
|
+
|
|
50
|
+
### Fixed
|
|
51
|
+
|
|
52
|
+
- **GitHub CLI Release-missing plain text compatibility**: `gh release view`
|
|
53
|
+
returns plain text `release not found` when the target release does not
|
|
54
|
+
exist; the previous implementation only recognized an HTTP 404 exit code.
|
|
55
|
+
The adapter now maps that specific plain text to a missing-release
|
|
56
|
+
decision without misclassifying `repository not found` or permission
|
|
57
|
+
errors as a target release absence.
|
|
58
|
+
- **Plugin consumer install verification transport semantics**: frozen
|
|
59
|
+
snapshots are sealed as read-only, but Git and plugin installation
|
|
60
|
+
transport restores owner write permission on extraction. Verification
|
|
61
|
+
now normalizes ordinary write permission from transport semantics and
|
|
62
|
+
continues to strictly verify path, type, content, size, and executable
|
|
63
|
+
intent. The frozen source digest is still compared against the plan and
|
|
64
|
+
must not be back-filled from observed results.
|
|
65
|
+
|
|
6
66
|
## [0.1.1] - 2026-07-18
|
|
7
67
|
|
|
8
68
|
### Fixed
|
package/INSTALL.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Installation Guide
|
|
2
2
|
|
|
3
|
+
[简体中文](INSTALL.zh-CN.md)
|
|
4
|
+
|
|
3
5
|
## Prerequisites
|
|
4
6
|
|
|
5
7
|
- Node.js 22.0.0 or later
|
|
@@ -7,9 +9,9 @@
|
|
|
7
9
|
|
|
8
10
|
## Install from npm (recommended)
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
only after `npm view release-skill version` returns
|
|
12
|
-
|
|
12
|
+
v0.1.1 is published and verified. For a newer source candidate such as v0.1.3,
|
|
13
|
+
use the npm path only after `npm view release-skill version` returns that exact
|
|
14
|
+
version; before then, use the source checkout instructions below.
|
|
13
15
|
|
|
14
16
|
```bash
|
|
15
17
|
npm install -g release-skill
|
|
@@ -61,7 +63,89 @@ instructions above; do not mix the two entry paths in one run.
|
|
|
61
63
|
"${CLI[@]}" help
|
|
62
64
|
```
|
|
63
65
|
|
|
64
|
-
|
|
66
|
+
If `.release-skill/project.yaml` is absent, discover first-use facts and
|
|
67
|
+
candidates without writing files:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
"${CLI[@]}" setup --root /path/to/your/project --json
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
`NEEDS_INPUT` and `LOCAL_ONLY_DETECTED` intentionally return exit code 2. They
|
|
74
|
+
are decision states, not an internal crash; automation should inspect the JSON
|
|
75
|
+
`status`.
|
|
76
|
+
|
|
77
|
+
Review release units, legacy `public-release.json` migration hints, tags,
|
|
78
|
+
branch strategies, previous-public-baseline decisions, and gate candidates.
|
|
79
|
+
Setup never executes a discovered script automatically. Provide a complete
|
|
80
|
+
answers JSON, dry-run again to obtain the digest that binds current facts and
|
|
81
|
+
answers, then create the configuration exactly once:
|
|
82
|
+
|
|
83
|
+
```json
|
|
84
|
+
{
|
|
85
|
+
"projectConfig": {
|
|
86
|
+
"apiVersion": "release-skill/v1",
|
|
87
|
+
"kind": "ReleaseProject",
|
|
88
|
+
"project": { "name": "my-project", "defaultBranch": "main" },
|
|
89
|
+
"releaseUnits": [{
|
|
90
|
+
"id": "my-project",
|
|
91
|
+
"source": ".",
|
|
92
|
+
"publicRepo": "owner/my-project",
|
|
93
|
+
"version": { "source": "package.json", "tagTemplate": "v{version}" },
|
|
94
|
+
"distributions": [{
|
|
95
|
+
"type": "npm",
|
|
96
|
+
"package": "my-project",
|
|
97
|
+
"access": "public",
|
|
98
|
+
"provenance": false,
|
|
99
|
+
"tag": "latest",
|
|
100
|
+
"registry": "https://registry.npmjs.org",
|
|
101
|
+
"publisher": "my-npm-username"
|
|
102
|
+
}],
|
|
103
|
+
"publicFiles": [
|
|
104
|
+
{ "from": "README.md", "to": "README.md", "mode": "preserve" },
|
|
105
|
+
{ "from": "package.json", "to": "package.json", "mode": "preserve" }
|
|
106
|
+
],
|
|
107
|
+
"requiredPublicFiles": ["README.md", "package.json"],
|
|
108
|
+
"previousPublicBaseline": { "mode": "none" },
|
|
109
|
+
"production": {
|
|
110
|
+
"branchTemplate": "release/{tag}",
|
|
111
|
+
"branchStrategy": "create-release-branch"
|
|
112
|
+
}
|
|
113
|
+
}]
|
|
114
|
+
},
|
|
115
|
+
"selectedGateIds": []
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
The wrapper is complete, but its values are examples. Replace every repository,
|
|
120
|
+
channel, baseline, and public-file decision with reviewed project facts; use
|
|
121
|
+
`mode: none` only when no public version exists.
|
|
122
|
+
|
|
123
|
+
When selecting a reported gate, add the complete gate definition to
|
|
124
|
+
`projectConfig.verificationGates` and copy its id into `selectedGateIds`. The
|
|
125
|
+
id must come from the current `gateCandidates`. A snapshot-gate command and all
|
|
126
|
+
of its dependencies must be present in `publicFiles`; it cannot see tests,
|
|
127
|
+
development dependencies, or `node_modules` that exist only in the parent
|
|
128
|
+
workspace. The full [README setup section](README.md#first-use-discover-then-let-a-human-finalize)
|
|
129
|
+
contains complete no-gate and one-gate answers examples.
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
"${CLI[@]}" setup --root /path/to/your/project \
|
|
133
|
+
--answers /path/to/setup-answers.json --json
|
|
134
|
+
"${CLI[@]}" setup --root /path/to/your/project \
|
|
135
|
+
--answers /path/to/setup-answers.json \
|
|
136
|
+
--write --confirm-setup <setupDigest> --json
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
An existing config is never regenerated or overwritten. A project with no
|
|
140
|
+
discoverable GitHub/npm channel reports `LOCAL_ONLY_DETECTED` rather than
|
|
141
|
+
claiming production readiness.
|
|
142
|
+
|
|
143
|
+
The automatic create-once write uses the digest-registered `darwin-arm64`
|
|
144
|
+
native prebuild shipped in v0.1.3. Other platforms fail closed with
|
|
145
|
+
`SAFE_WRITE_UNAVAILABLE`; keep the dry-run report and create the reviewed file
|
|
146
|
+
manually instead of enabling an unsafe pathname fallback.
|
|
147
|
+
|
|
148
|
+
After the config exists, check release readiness:
|
|
65
149
|
|
|
66
150
|
```bash
|
|
67
151
|
"${CLI[@]}" assess --root /path/to/your/project --offline --json
|
|
@@ -139,12 +223,100 @@ hooks:
|
|
|
139
223
|
build:
|
|
140
224
|
command: [npm, run, build]
|
|
141
225
|
test:
|
|
142
|
-
command:
|
|
226
|
+
command:
|
|
227
|
+
- node
|
|
228
|
+
- -e
|
|
229
|
+
- "const p=require('./package.json'); if (!p.name) process.exit(1)"
|
|
143
230
|
```
|
|
144
231
|
|
|
145
232
|
See the [full README](README.md) for hook parameter constraints and safety
|
|
146
233
|
requirements.
|
|
147
234
|
|
|
235
|
+
### Advanced: verification gates (optional)
|
|
236
|
+
|
|
237
|
+
Use a `snapshot-verify` gate for checks that should run against a disposable
|
|
238
|
+
writable copy of the frozen public snapshot. Use `consumer-verify` for commands
|
|
239
|
+
that must run from an exact isolated npm/Claude/Codex installation root. Gate
|
|
240
|
+
commands are executable arrays, not shell strings, and must declare unit,
|
|
241
|
+
distribution when applicable, cwd, timeout, and environment allowlist.
|
|
242
|
+
|
|
243
|
+
```yaml
|
|
244
|
+
verificationGates:
|
|
245
|
+
- id: package-contract
|
|
246
|
+
phase: snapshot-verify
|
|
247
|
+
scope: { unit: my-project }
|
|
248
|
+
command: [node, -e, "const p=require('./package.json');if(!p.name)process.exit(1)"]
|
|
249
|
+
cwd: .
|
|
250
|
+
timeoutMs: 30000
|
|
251
|
+
envAllowlist: []
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
This self-contained example reads only a mapped public file. A replacement
|
|
255
|
+
script and every dependency it needs must exist in the frozen public snapshot;
|
|
256
|
+
the gate cannot borrow tests, development dependencies, or `node_modules` from
|
|
257
|
+
the parent workspace.
|
|
258
|
+
|
|
259
|
+
Prepare and verify require `--acknowledge-gate-side-effects` whenever their
|
|
260
|
+
planned phase contains gates. Hooks and gates are project processes without a
|
|
261
|
+
network sandbox; release-skill limits their inputs and evidence but cannot
|
|
262
|
+
guarantee that a custom command will not modify files or access the network.
|
|
263
|
+
Never register Git push, tag, default-branch changes, GitHub Releases, or npm
|
|
264
|
+
publish as a hook/gate; those are controlled plan actions.
|
|
265
|
+
|
|
266
|
+
### Production branch strategy
|
|
267
|
+
|
|
268
|
+
Every production unit selects one explicit strategy:
|
|
269
|
+
|
|
270
|
+
- `create-release-branch` creates an absent immutable release branch;
|
|
271
|
+
- `advance-existing-branch` fast-forwards an existing branch from the exact
|
|
272
|
+
bound public baseline using an ordinary non-force push;
|
|
273
|
+
- `initialize-default-branch` creates an absent standard branch and may add an
|
|
274
|
+
explicit default-branch action only when `setAsDefaultBranch` and
|
|
275
|
+
`expectedCurrentDefaultBranch` are both reviewed.
|
|
276
|
+
|
|
277
|
+
Remote drift, a non-fast-forward update, or an unexpected default branch stops
|
|
278
|
+
for human intervention. No strategy overwrites remote history. Create-only refs
|
|
279
|
+
use `--force-with-lease=<ref>:` solely as an atomic absence assertion; advancing
|
|
280
|
+
an existing branch uses an ordinary non-force push.
|
|
281
|
+
|
|
282
|
+
```yaml
|
|
283
|
+
# create-release-branch: target must be absent
|
|
284
|
+
previousPublicBaseline: { mode: none } # true first public release only
|
|
285
|
+
production:
|
|
286
|
+
branchTemplate: release/{tag}
|
|
287
|
+
branchStrategy: create-release-branch
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
```yaml
|
|
291
|
+
# advance-existing-branch: ref must exactly equal refs/heads/<target>
|
|
292
|
+
previousPublicBaseline:
|
|
293
|
+
mode: bound
|
|
294
|
+
repo: owner/my-project
|
|
295
|
+
ref: refs/heads/main
|
|
296
|
+
commit: 0123456789abcdef0123456789abcdef01234567
|
|
297
|
+
production:
|
|
298
|
+
branchTemplate: main
|
|
299
|
+
branchStrategy: advance-existing-branch
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
```yaml
|
|
303
|
+
# initialize-default-branch: main must be absent; current default must match
|
|
304
|
+
previousPublicBaseline:
|
|
305
|
+
mode: bound
|
|
306
|
+
repo: owner/my-project
|
|
307
|
+
ref: refs/heads/old-public-branch
|
|
308
|
+
commit: 0123456789abcdef0123456789abcdef01234567
|
|
309
|
+
production:
|
|
310
|
+
branchTemplate: main
|
|
311
|
+
branchStrategy: initialize-default-branch
|
|
312
|
+
setAsDefaultBranch: true
|
|
313
|
+
expectedCurrentDefaultBranch: old-public-branch
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
The last two strategies require online production prepare. Any mismatch stops
|
|
317
|
+
for review; update the human-owned config only after inspecting real remote
|
|
318
|
+
state, and never force-push or weaken the baseline.
|
|
319
|
+
|
|
148
320
|
## Protect Human-Owned Content
|
|
149
321
|
|
|
150
322
|
README text, slogans, examples, layout, and other manually curated source files
|
|
@@ -167,6 +339,8 @@ When an existing public copy has drifted, choose explicitly:
|
|
|
167
339
|
## Next Steps
|
|
168
340
|
|
|
169
341
|
- Read the [full README](README.md) for the complete workflow guide.
|
|
342
|
+
- Run `"${CLI[@]}" setup --root <your-project> --json` when the project has no
|
|
343
|
+
configuration; keep its default dry-run behavior until human decisions are complete.
|
|
170
344
|
- Run `"${CLI[@]}" assess --root <your-project> --offline` to evaluate your project's release readiness.
|
|
171
345
|
- Run `"${CLI[@]}" prepare --root <your-project> --offline` (release-skill pipeline writes
|
|
172
346
|
locally only; user-configured hooks may perform remote operations) to generate
|
package/INSTALL.zh-CN.md
ADDED
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
# 安装指南
|
|
2
|
+
|
|
3
|
+
[English](INSTALL.md)
|
|
4
|
+
|
|
5
|
+
## 前置条件
|
|
6
|
+
|
|
7
|
+
- Node.js 22.0.0 或更高版本
|
|
8
|
+
- Git 2.30 或更高版本
|
|
9
|
+
|
|
10
|
+
## 从 npm 安装(推荐)
|
|
11
|
+
|
|
12
|
+
v0.1.1 已公开发布并完成验证。对于 v0.1.3 这样的更新源码候选,只有当
|
|
13
|
+
`npm view release-skill version` 返回该精确版本后才使用 npm 安装;在此之前请使用
|
|
14
|
+
下文的源码检出方式。
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install -g release-skill
|
|
18
|
+
CLI=(release-skill)
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
也可以不安装,直接运行:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npx release-skill help
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
验证安装:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
release-skill --version
|
|
31
|
+
release-skill help
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
输出中应包含版本号和可用命令列表。
|
|
35
|
+
|
|
36
|
+
## 开发安装(本地源码)
|
|
37
|
+
|
|
38
|
+
用于开发或尚未公开发布的源码候选:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
export RELEASE_SKILL_HOME=/absolute/path/to/release-skill
|
|
42
|
+
cd "$RELEASE_SKILL_HOME"
|
|
43
|
+
npm exec --yes pnpm@10.17.1 -- install --frozen-lockfile
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
通过以下数组调用命令行工具:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
CLI=(node "$RELEASE_SKILL_HOME/packages/release-skill/bin/release-skill.mjs")
|
|
50
|
+
"${CLI[@]}" help
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
当 `npm view release-skill version` 已确认目标版本公开并安装后,等价的 npm 入口是
|
|
54
|
+
`CLI=(release-skill)`。同一次运行不要混用 npm 与源码入口。
|
|
55
|
+
|
|
56
|
+
## 首次运行
|
|
57
|
+
|
|
58
|
+
最安全的首条命令始终是 `help`。它完全在本地运行,不写入文件:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
"${CLI[@]}" help
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
如果项目尚无 `.release-skill/project.yaml`,先只读发现事实和候选:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
"${CLI[@]}" setup --root /path/to/your/project --json
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
`NEEDS_INPUT` 和 `LOCAL_ONLY_DETECTED` 按设计返回退出码 2。它们表示待人工决策,不是
|
|
71
|
+
内部崩溃;自动化应读取 JSON 的 `status`。
|
|
72
|
+
|
|
73
|
+
人工审阅发布单元、旧 `public-release.json` 迁移提示、tag、分支策略、前序公开基线
|
|
74
|
+
和 gate 候选。setup 不会自动执行发现到的脚本。建立完整 answers JSON,再运行一次
|
|
75
|
+
dry-run(只读试运行),取得同时绑定当前事实与人工答案的摘要,然后只创建一次配置:
|
|
76
|
+
|
|
77
|
+
```json
|
|
78
|
+
{
|
|
79
|
+
"projectConfig": {
|
|
80
|
+
"apiVersion": "release-skill/v1",
|
|
81
|
+
"kind": "ReleaseProject",
|
|
82
|
+
"project": { "name": "my-project", "defaultBranch": "main" },
|
|
83
|
+
"releaseUnits": [{
|
|
84
|
+
"id": "my-project",
|
|
85
|
+
"source": ".",
|
|
86
|
+
"publicRepo": "owner/my-project",
|
|
87
|
+
"version": { "source": "package.json", "tagTemplate": "v{version}" },
|
|
88
|
+
"distributions": [{
|
|
89
|
+
"type": "npm",
|
|
90
|
+
"package": "my-project",
|
|
91
|
+
"access": "public",
|
|
92
|
+
"provenance": false,
|
|
93
|
+
"tag": "latest",
|
|
94
|
+
"registry": "https://registry.npmjs.org",
|
|
95
|
+
"publisher": "my-npm-username"
|
|
96
|
+
}],
|
|
97
|
+
"publicFiles": [
|
|
98
|
+
{ "from": "README.md", "to": "README.md", "mode": "preserve" },
|
|
99
|
+
{ "from": "package.json", "to": "package.json", "mode": "preserve" }
|
|
100
|
+
],
|
|
101
|
+
"requiredPublicFiles": ["README.md", "package.json"],
|
|
102
|
+
"previousPublicBaseline": { "mode": "none" },
|
|
103
|
+
"production": {
|
|
104
|
+
"branchTemplate": "release/{tag}",
|
|
105
|
+
"branchStrategy": "create-release-branch"
|
|
106
|
+
}
|
|
107
|
+
}]
|
|
108
|
+
},
|
|
109
|
+
"selectedGateIds": []
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
这个外壳完整,但其中的值只是示例。仓库、渠道、基线与公开文件都必须替换为本项目
|
|
114
|
+
经审阅的事实;只有确认不存在历史公开版本时才可使用 `mode: none`。
|
|
115
|
+
|
|
116
|
+
选择已报告的 gate 时,把完整定义加入 `projectConfig.verificationGates`,并把同一 id
|
|
117
|
+
复制进 `selectedGateIds`。id 必须来自当前 `gateCandidates`。snapshot gate 命令及
|
|
118
|
+
全部依赖必须包含在 `publicFiles`;它看不到仅存在于父工作空间的测试、开发依赖或
|
|
119
|
+
`node_modules`。完整的无 gate 与单 gate answers 示例见
|
|
120
|
+
[README 首次接入章节](README.zh-CN.md#首次接入先发现再由人工定稿)。
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
"${CLI[@]}" setup --root /path/to/your/project \
|
|
124
|
+
--answers /path/to/setup-answers.json --json
|
|
125
|
+
"${CLI[@]}" setup --root /path/to/your/project \
|
|
126
|
+
--answers /path/to/setup-answers.json \
|
|
127
|
+
--write --confirm-setup <setupDigest> --json
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
已有配置永远不会被重新生成或覆盖。无法发现 GitHub/npm 渠道的项目返回
|
|
131
|
+
`LOCAL_ONLY_DETECTED`,不会冒充生产就绪。
|
|
132
|
+
|
|
133
|
+
自动 create-once 写入使用 v0.1.3 随包提供、带摘要登记的 `darwin-arm64` 原生预构建。
|
|
134
|
+
其他平台以 `SAFE_WRITE_UNAVAILABLE` 失败关闭;此时保留只读报告,由人工首次创建经审阅
|
|
135
|
+
的文件,不得启用不安全的路径写入兜底。
|
|
136
|
+
|
|
137
|
+
配置存在后,检查发布就绪度:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
"${CLI[@]}" assess --root /path/to/your/project --offline --json
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
该命令只读地检查项目结构、配置、文档和供应链;未显式传入 `--output` 时不写报告,
|
|
144
|
+
也不运行项目 hook。
|
|
145
|
+
|
|
146
|
+
`prepare` 不同:它在目标项目的 `.release-skill/` 下写入发布工件,并可能运行已配置
|
|
147
|
+
hook。hook 是无沙箱的任意进程,可能写到项目外、访问凭据、使用网络或执行远端写入。
|
|
148
|
+
授予 `--acknowledge-hook-side-effects` 前必须审阅可执行文件、参数和工作目录。
|
|
149
|
+
|
|
150
|
+
Git 仓库应保留人工配置,同时忽略生成的权威文件和证据:
|
|
151
|
+
|
|
152
|
+
```gitignore
|
|
153
|
+
.release-skill/*
|
|
154
|
+
!.release-skill/project.yaml
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## 项目配置
|
|
158
|
+
|
|
159
|
+
在项目根目录创建 `.release-skill/project.yaml`。以下是单包项目的最小示例:
|
|
160
|
+
|
|
161
|
+
```yaml
|
|
162
|
+
apiVersion: release-skill/v1
|
|
163
|
+
kind: ReleaseProject
|
|
164
|
+
|
|
165
|
+
project:
|
|
166
|
+
name: my-project
|
|
167
|
+
defaultBranch: main
|
|
168
|
+
|
|
169
|
+
releaseUnits:
|
|
170
|
+
- id: my-project
|
|
171
|
+
source: .
|
|
172
|
+
publicRepo: owner/my-project
|
|
173
|
+
version:
|
|
174
|
+
source: package.json
|
|
175
|
+
tagTemplate: v{version}
|
|
176
|
+
distributions:
|
|
177
|
+
- type: npm
|
|
178
|
+
package: my-project
|
|
179
|
+
access: public
|
|
180
|
+
provenance: false
|
|
181
|
+
tag: latest
|
|
182
|
+
registry: https://registry.npmjs.org
|
|
183
|
+
publisher: my-npm-username
|
|
184
|
+
publicFiles:
|
|
185
|
+
- from: README.md
|
|
186
|
+
to: README.md
|
|
187
|
+
mode: preserve
|
|
188
|
+
- from: package.json
|
|
189
|
+
to: package.json
|
|
190
|
+
mode: preserve
|
|
191
|
+
- from: LICENSE
|
|
192
|
+
to: LICENSE
|
|
193
|
+
mode: preserve
|
|
194
|
+
requiredPublicFiles: [README.md, package.json, LICENSE]
|
|
195
|
+
previousPublicBaseline:
|
|
196
|
+
mode: none # 仅限已确认不存在历史公开版本
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### 进阶:hook(可选)
|
|
200
|
+
|
|
201
|
+
hook 是可选的任意本地进程。prepare 使用 hook 时必须显式授予
|
|
202
|
+
`--acknowledge-hook-side-effects`:
|
|
203
|
+
|
|
204
|
+
```yaml
|
|
205
|
+
hooks:
|
|
206
|
+
build:
|
|
207
|
+
command: [npm, run, build]
|
|
208
|
+
test:
|
|
209
|
+
command:
|
|
210
|
+
- node
|
|
211
|
+
- -e
|
|
212
|
+
- "const p=require('./package.json'); if (!p.name) process.exit(1)"
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
参数约束和安全要求见[完整 README](README.zh-CN.md)。
|
|
216
|
+
|
|
217
|
+
### 进阶:验证 gate(可选)
|
|
218
|
+
|
|
219
|
+
`snapshot-verify` 用于冻结公开快照的一次性可写副本;`consumer-verify` 用于精确且
|
|
220
|
+
隔离安装后的 npm/Claude/Codex 根目录。gate 使用可执行文件数组而不是 shell 字符串,
|
|
221
|
+
并声明 unit、必要时的 distribution、cwd、超时和环境变量白名单。
|
|
222
|
+
|
|
223
|
+
```yaml
|
|
224
|
+
verificationGates:
|
|
225
|
+
- id: package-contract
|
|
226
|
+
phase: snapshot-verify
|
|
227
|
+
scope: { unit: my-project }
|
|
228
|
+
command: [node, -e, "const p=require('./package.json');if(!p.name)process.exit(1)"]
|
|
229
|
+
cwd: .
|
|
230
|
+
timeoutMs: 30000
|
|
231
|
+
envAllowlist: []
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
这个自包含示例只读取已映射的公开文件。若替换成项目脚本,该脚本及全部依赖必须
|
|
235
|
+
存在于冻结公开快照;gate 不能借用父工作空间中的测试、开发依赖或 `node_modules`。
|
|
236
|
+
|
|
237
|
+
当计划的当前阶段包含 gate 时,prepare 或 verify 必须传入
|
|
238
|
+
`--acknowledge-gate-side-effects`。hook/gate 都是无网络沙箱的项目进程;
|
|
239
|
+
release-skill 约束其输入与证据,但无法保证自定义命令不修改文件或不访问网络。
|
|
240
|
+
禁止把 Git push、tag、默认分支修改、GitHub Release 或 npm publish 注册为
|
|
241
|
+
hook/gate,它们只能由受控的计划动作完成。
|
|
242
|
+
|
|
243
|
+
### 生产分支策略
|
|
244
|
+
|
|
245
|
+
每个生产发布单元显式选择一种策略:
|
|
246
|
+
|
|
247
|
+
- `create-release-branch`:创建此前不存在且不可变的 release 分支;
|
|
248
|
+
- `advance-existing-branch`:从精确绑定的公开基线用普通非 force push 快进已有分支;
|
|
249
|
+
- `initialize-default-branch`:创建不存在的标准分支;只有同时审阅
|
|
250
|
+
`setAsDefaultBranch` 与 `expectedCurrentDefaultBranch` 后,计划才可增加显式默认分支动作。
|
|
251
|
+
|
|
252
|
+
远端漂移、非快进或默认分支不符合预期时必须停止并由人工介入。所有策略都禁止覆盖
|
|
253
|
+
远端历史。新建 ref 仅使用 `--force-with-lease=<ref>:` 作为“目标必须不存在”的原子
|
|
254
|
+
断言;推进已有分支使用普通非 force push。
|
|
255
|
+
|
|
256
|
+
```yaml
|
|
257
|
+
# create-release-branch:目标分支必须不存在
|
|
258
|
+
previousPublicBaseline: { mode: none } # 仅限真正的首次公开发布
|
|
259
|
+
production:
|
|
260
|
+
branchTemplate: release/{tag}
|
|
261
|
+
branchStrategy: create-release-branch
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
```yaml
|
|
265
|
+
# advance-existing-branch:ref 必须精确等于 refs/heads/<目标分支>
|
|
266
|
+
previousPublicBaseline:
|
|
267
|
+
mode: bound
|
|
268
|
+
repo: owner/my-project
|
|
269
|
+
ref: refs/heads/main
|
|
270
|
+
commit: 0123456789abcdef0123456789abcdef01234567
|
|
271
|
+
production:
|
|
272
|
+
branchTemplate: main
|
|
273
|
+
branchStrategy: advance-existing-branch
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
```yaml
|
|
277
|
+
# initialize-default-branch:main 必须不存在,当前默认分支必须符合预期
|
|
278
|
+
previousPublicBaseline:
|
|
279
|
+
mode: bound
|
|
280
|
+
repo: owner/my-project
|
|
281
|
+
ref: refs/heads/old-public-branch
|
|
282
|
+
commit: 0123456789abcdef0123456789abcdef01234567
|
|
283
|
+
production:
|
|
284
|
+
branchTemplate: main
|
|
285
|
+
branchStrategy: initialize-default-branch
|
|
286
|
+
setAsDefaultBranch: true
|
|
287
|
+
expectedCurrentDefaultBranch: old-public-branch
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
后两种策略必须在线执行 production prepare。任何不一致都应停止并审阅;只有检查
|
|
291
|
+
真实远端状态后才能人工更新权威配置,禁止 force push 或弱化基线。
|
|
292
|
+
|
|
293
|
+
## 保护人工维护内容
|
|
294
|
+
|
|
295
|
+
README 文案、slogan、示例、排版及其他人工源文件始终是权威。release-skill 只按
|
|
296
|
+
`publicFiles` 映射做快照,不重新生成或覆盖源 README。每次人工编辑后重新 prepare,
|
|
297
|
+
并批准新的不可变计划;不得编辑冻结快照或复用旧批准绕过变化。
|
|
298
|
+
|
|
299
|
+
如果已有公开副本发生漂移,显式选择:
|
|
300
|
+
|
|
301
|
+
- **merge(合并)**:比较真实远端内容,把接受的改动合并回人工源文件,然后把
|
|
302
|
+
`previousPublicBaseline` 绑定到精确不可变的 `repo`/`ref`/`commit`,再 prepare;
|
|
303
|
+
- **adopt(采纳)**:接受远端为新的事实来源,先带回人工源文件,再更新同一基线绑定;
|
|
304
|
+
- **reject(拒绝)**:停止并调查。不得改成 `mode: none` 绕过漂移或唯一性检查。
|
|
305
|
+
|
|
306
|
+
## 下一步
|
|
307
|
+
|
|
308
|
+
- 阅读[完整中文 README](README.zh-CN.md)了解整个工作流。
|
|
309
|
+
- 缺少配置时运行 `"${CLI[@]}" setup --root <your-project> --json`,在人工决策完成前
|
|
310
|
+
保持默认 dry-run。
|
|
311
|
+
- 运行 `"${CLI[@]}" assess --root <your-project> --offline` 检查发布就绪度。
|
|
312
|
+
- 运行 `"${CLI[@]}" prepare --root <your-project> --offline` 生成发布计划;
|
|
313
|
+
release-skill 自身只做本地写入,但项目 hook 可能执行远端操作。
|
|
314
|
+
- 生产前为每个 unit 配置 `previousPublicBaseline`。已有公开版本必须使用
|
|
315
|
+
`mode: bound`,绑定精确 `repo`、`ref` 和 `commit`,再运行
|
|
316
|
+
`"${CLI[@]}" prepare --root <your-project> --online --production`。默认观察器只证明
|
|
317
|
+
ref 到 commit 的映射,不下载远端内容;目标 branch/tag/Release/npm 唯一性由
|
|
318
|
+
publish 全局预检在任何 execute 前检查。
|
|
319
|
+
- 生产命令只使用 `prepare --json` 返回的不可变 `planPath`,以及 `approve --json`
|
|
320
|
+
返回的不可变 `approvalPath`。可变的 latest 别名不能作为生产权威。
|