release-skill 0.1.3 → 0.1.5
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 +2 -2
- package/.codex-plugin/plugin.json +3 -3
- package/CHANGELOG.md +56 -0
- package/INSTALL.md +69 -32
- package/INSTALL.zh-CN.md +64 -26
- package/README.md +111 -37
- package/README.zh-CN.md +95 -28
- package/adapters/claude/.claude-plugin/marketplace.json +1 -1
- package/adapters/claude/.claude-plugin/plugin.json +1 -1
- package/adapters/claude/bin/release-skill.bundle.mjs +79371 -0
- package/adapters/claude/bin/release-skill.mjs +34 -0
- package/adapters/claude/native/safe-write/binding.gyp +40 -0
- package/adapters/claude/native/safe-write/prebuilds/darwin-arm64/safe_write.node +0 -0
- package/adapters/claude/native/safe-write/prebuilds.json +24 -0
- package/adapters/claude/native/safe-write/src/safe_write.cc +2032 -0
- package/adapters/claude/schemas/.render-manifest.json +37 -0
- package/adapters/claude/schemas/approval-record.schema.json +115 -0
- package/adapters/claude/schemas/artifact-lock.schema.json +111 -0
- package/adapters/claude/schemas/artifact-plan.schema.json +52 -0
- package/adapters/claude/schemas/artifact-policy.schema.json +76 -0
- package/adapters/claude/schemas/evidence-event.schema.json +89 -0
- package/adapters/claude/schemas/release-plan.schema.json +860 -0
- package/adapters/claude/schemas/release-project.schema.json +759 -0
- package/adapters/claude/schemas/release-run.schema.json +342 -0
- package/adapters/claude/skills/release-assess/SKILL.md +5 -6
- package/adapters/claude/skills/release-help/SKILL.md +11 -18
- package/adapters/claude/skills/release-prepare/SKILL.md +6 -6
- package/adapters/claude/skills/release-publish/SKILL.md +1 -4
- package/adapters/claude/skills/release-reconcile/SKILL.md +5 -5
- package/adapters/claude/skills/release-setup/SKILL.md +64 -80
- package/adapters/claude/skills/release-verify/SKILL.md +4 -7
- package/adapters/codex/.codex-plugin/plugin.json +2 -2
- package/adapters/codex/bin/release-skill.bundle.mjs +79371 -0
- package/adapters/codex/bin/release-skill.mjs +34 -0
- package/adapters/codex/native/safe-write/binding.gyp +40 -0
- package/adapters/codex/native/safe-write/prebuilds/darwin-arm64/safe_write.node +0 -0
- package/adapters/codex/native/safe-write/prebuilds.json +24 -0
- package/adapters/codex/native/safe-write/src/safe_write.cc +2032 -0
- package/adapters/codex/schemas/.render-manifest.json +37 -0
- package/adapters/codex/schemas/approval-record.schema.json +115 -0
- package/adapters/codex/schemas/artifact-lock.schema.json +111 -0
- package/adapters/codex/schemas/artifact-plan.schema.json +52 -0
- package/adapters/codex/schemas/artifact-policy.schema.json +76 -0
- package/adapters/codex/schemas/evidence-event.schema.json +89 -0
- package/adapters/codex/schemas/release-plan.schema.json +860 -0
- package/adapters/codex/schemas/release-project.schema.json +759 -0
- package/adapters/codex/schemas/release-run.schema.json +342 -0
- package/adapters/codex/skills/release-assess/SKILL.md +12 -6
- package/adapters/codex/skills/release-help/SKILL.md +18 -18
- package/adapters/codex/skills/release-prepare/SKILL.md +13 -6
- package/adapters/codex/skills/release-publish/SKILL.md +8 -4
- package/adapters/codex/skills/release-reconcile/SKILL.md +12 -5
- package/adapters/codex/skills/release-setup/SKILL.md +71 -80
- package/adapters/codex/skills/release-verify/SKILL.md +11 -7
- package/bin/release-skill-cli.mjs +807 -0
- package/bin/release-skill.bundle.mjs +79371 -0
- package/bin/release-skill.mjs +23 -788
- package/package.json +6 -2
- package/references/02-project-config.md +2 -2
- package/schemas/release-plan.schema.json +7 -1
- package/schemas/release-project.schema.json +31 -0
- package/scripts/build-bundle.mjs +133 -0
- package/skills/release-assess/SKILL.md +5 -6
- package/skills/release-help/SKILL.md +11 -18
- package/skills/release-prepare/SKILL.md +6 -6
- package/skills/release-publish/SKILL.md +1 -4
- package/skills/release-reconcile/SKILL.md +5 -5
- package/skills/release-setup/SKILL.md +64 -80
- package/skills/release-verify/SKILL.md +4 -7
- package/skills-src/release-assess/SKILL.md +5 -6
- package/skills-src/release-help/SKILL.md +11 -18
- package/skills-src/release-prepare/SKILL.md +6 -6
- package/skills-src/release-publish/SKILL.md +1 -4
- package/skills-src/release-reconcile/SKILL.md +5 -5
- package/skills-src/release-setup/SKILL.md +64 -80
- package/skills-src/release-verify/SKILL.md +4 -7
- package/src/adapters/npm.mjs +5 -13
- package/src/adapters/plugin-marketplace.mjs +137 -34
- package/src/artifacts/policy.mjs +4 -7
- package/src/artifacts/safe-fs-backend-internal.mjs +69 -21
- package/src/commands/prepare.mjs +30 -1
- package/src/commands/publish.mjs +1 -0
- package/src/commands/reconcile.mjs +4 -1
- package/src/commands/setup.mjs +667 -28
- package/src/commands/verify.mjs +4 -1
- package/src/core/approval.mjs +4 -6
- package/src/core/config.mjs +8 -8
- package/src/core/pkg-root.mjs +22 -0
- package/src/core/plan.mjs +68 -5
- package/src/core/run.mjs +4 -4
- package/src/core/trusted-resource.mjs +96 -0
- package/src/docs/version-gate.mjs +164 -0
- package/src/producers/build-adapters.mjs +512 -55
- package/src/snapshot/frozen.mjs +133 -3
- package/src/snapshot/public-map.mjs +7 -4
- package/src/snapshot/scan.mjs +2 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "release-skill",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
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"
|
|
7
7
|
},
|
|
8
8
|
"license": "MIT",
|
|
9
|
-
"skills": "./skills/"
|
|
9
|
+
"skills": "./adapters/claude/skills/"
|
|
10
10
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "release-skill",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
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"
|
|
7
7
|
},
|
|
8
8
|
"license": "MIT",
|
|
9
|
-
"skills": "./skills/",
|
|
9
|
+
"skills": "./adapters/codex/skills/",
|
|
10
10
|
"interface": {
|
|
11
11
|
"displayName": "Release Skill",
|
|
12
12
|
"shortDescription": "Safe preparation and frozen GitHub/npm publishing",
|
|
@@ -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.5.",
|
|
23
23
|
"Help me understand the release workflow."
|
|
24
24
|
]
|
|
25
25
|
}
|
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,62 @@
|
|
|
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.5] - 2026-07-21
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
|
|
10
|
+
- **Explicit marketplace install timeout (`timeoutMs`)**: Claude and Codex
|
|
11
|
+
plugin marketplace distributions now accept an optional `timeoutMs` integer
|
|
12
|
+
field (range 30,000--900,000 ms; default 300,000 ms). The resolved value is
|
|
13
|
+
frozen into each marketplace install action's `parameters.timeoutMs` during
|
|
14
|
+
`prepare`, making it part of the plan digest, approval binding, and plan
|
|
15
|
+
integrity. The `plugin-marketplace` adapter's marketplace add, plugin install,
|
|
16
|
+
and plugin list commands all use the same frozen timeout, replacing the
|
|
17
|
+
previous hardcoded 30-second limit that caused `PARTIAL` failures on real
|
|
18
|
+
network installations requiring 40--105 seconds.
|
|
19
|
+
- **Old plan backward compatibility**: plans created before v0.1.5 that lack
|
|
20
|
+
`parameters.timeoutMs` on marketplace install actions default to 300,000 ms,
|
|
21
|
+
so existing `PARTIAL` runs can be reconciled without upgrading the plan.
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- **Marketplace consumer install timeout**: v0.1.4 production releases hit
|
|
26
|
+
`PARTIAL` because Claude Code and Codex plugin marketplace add commands
|
|
27
|
+
required 40--105 seconds on real networks, while the adapter hardcoded a
|
|
28
|
+
30-second subprocess timeout. The timeout is now explicitly configurable per
|
|
29
|
+
distribution and verified through injected-executor tests. Invalid values
|
|
30
|
+
(non-integer, non-finite, out-of-range) fail closed rather than being
|
|
31
|
+
silently clamped.
|
|
32
|
+
|
|
33
|
+
## [0.1.4] - 2026-07-19
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
|
|
37
|
+
- **Docs version hard gate**: the English and Chinese README and INSTALL each
|
|
38
|
+
carry a machine-readable `release-skill:release-version` marker that must
|
|
39
|
+
equal the `package.json` version, and the CHANGELOG must carry a formal
|
|
40
|
+
heading for the current version. Any drift fails closed in
|
|
41
|
+
`pnpm test:release` before prepare. A release freezes only the current
|
|
42
|
+
truth: human docs are never auto-refreshed and must be updated, reviewed,
|
|
43
|
+
and approved first.
|
|
44
|
+
- **Auditable frozen commit timestamps**: production `prepare` samples the
|
|
45
|
+
plan freeze time once, validates it before any Git write, and binds it to
|
|
46
|
+
`GIT_AUTHOR_DATE`/`GIT_COMMITTER_DATE` and each unit's
|
|
47
|
+
`frozenSnapshot.commitTimestamp` (schema-required); plans missing the field
|
|
48
|
+
are rejected instead of silently rebuilt.
|
|
49
|
+
|
|
50
|
+
### Fixed
|
|
51
|
+
|
|
52
|
+
- **Self-contained installed CLI smoke**: the v0.1.3 self-release selected
|
|
53
|
+
`help --json`, which correctly treats Git as a required environment
|
|
54
|
+
dependency, while npm smoke intentionally exposes only the Node runtime.
|
|
55
|
+
The CLI now supports `--version --json`, and self-release verification uses
|
|
56
|
+
that dependency-free entry to bind the installed CLI name and exact version
|
|
57
|
+
without widening the isolated process `PATH`.
|
|
58
|
+
- Added a real subprocess regression that runs the installed-style version
|
|
59
|
+
entry with the Node-only `PATH` and proves an unrelated injected path is not
|
|
60
|
+
inherited.
|
|
61
|
+
|
|
6
62
|
## [0.1.3] - 2026-07-19
|
|
7
63
|
|
|
8
64
|
> `0.1.2` was an internal release candidate and was never published to npm or
|
package/INSTALL.md
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[简体中文](INSTALL.zh-CN.md)
|
|
4
4
|
|
|
5
|
+
<!-- release-skill:release-version: 0.1.5 -->
|
|
5
6
|
## Prerequisites
|
|
6
7
|
|
|
7
8
|
- Node.js 22.0.0 or later
|
|
@@ -9,8 +10,9 @@
|
|
|
9
10
|
|
|
10
11
|
## Install from npm (recommended)
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
A public version is complete only after its immutable production plan has been
|
|
14
|
+
approved, published, and reached `VERIFIED`. For a newer source checkout, use
|
|
15
|
+
the npm path only after `npm view release-skill version` returns that exact
|
|
14
16
|
version; before then, use the source checkout instructions below.
|
|
15
17
|
|
|
16
18
|
```bash
|
|
@@ -63,22 +65,71 @@ instructions above; do not mix the two entry paths in one run.
|
|
|
63
65
|
"${CLI[@]}" help
|
|
64
66
|
```
|
|
65
67
|
|
|
66
|
-
If `.release-skill/project.yaml` is absent,
|
|
67
|
-
|
|
68
|
+
If `.release-skill/project.yaml` is absent, keep the full read-only report in a
|
|
69
|
+
temporary file and inspect only its deterministic `compactSummary`:
|
|
68
70
|
|
|
69
71
|
```bash
|
|
70
|
-
|
|
72
|
+
PROJECT=/path/to/your/project
|
|
73
|
+
SETUP_SESSION="$(mktemp -d "${TMPDIR:-/tmp}/release-setup.XXXXXX")"
|
|
74
|
+
REPORT="$SETUP_SESSION/discovery.json"
|
|
75
|
+
ANSWERS="$SETUP_SESSION/answers.json"
|
|
76
|
+
BOUND_REPORT="$SETUP_SESSION/bound.json"
|
|
77
|
+
printf 'SETUP_SESSION=%s\nPROJECT=%s\n' "$SETUP_SESSION" "$PROJECT"
|
|
78
|
+
|
|
79
|
+
"${CLI[@]}" setup --root "$PROJECT" --json > "$REPORT" || test "$?" -eq 2
|
|
80
|
+
node -e 'const fs=require("node:fs");const r=JSON.parse(fs.readFileSync(process.argv[1],"utf8"));if(!r.compactSummary){console.error("compactSummary missing");process.exit(2)}process.stdout.write(JSON.stringify(r.compactSummary,null,2)+"\n")' "$REPORT"
|
|
71
81
|
```
|
|
72
82
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
83
|
+
The summary is a review view, not authorization; `setupDigest` binds the full
|
|
84
|
+
facts, candidates, and answers. If `proposalConflicts` is non-empty, a human
|
|
85
|
+
must correct the conflicting repository/mapping authority and rerun setup.
|
|
86
|
+
Do not guess. With no conflicts, mechanically extract the proposal:
|
|
76
87
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
answers
|
|
88
|
+
```bash
|
|
89
|
+
SETUP_SESSION='/session-directory-absolute-path-printed-above'
|
|
90
|
+
PROJECT='/project-absolute-path-printed-above'
|
|
91
|
+
REPORT="$SETUP_SESSION/discovery.json"
|
|
92
|
+
ANSWERS="$SETUP_SESSION/answers.json"
|
|
93
|
+
BOUND_REPORT="$SETUP_SESSION/bound.json"
|
|
94
|
+
node -e 'const fs=require("node:fs");const r=JSON.parse(fs.readFileSync(process.argv[1],"utf8"));if((r.proposalConflicts??[]).length){console.error("proposal conflicts require human resolution");process.exit(2)}if(!r.recommendedAnswers){console.error("recommendedAnswers missing");process.exit(2)}fs.writeFileSync(process.argv[2],JSON.stringify(r.recommendedAnswers,null,2)+"\n",{flag:"wx",mode:0o600})' "$REPORT" "$ANSWERS"
|
|
95
|
+
"${CLI[@]}" setup --root "$PROJECT" --answers "$ANSWERS" --json > "$BOUND_REPORT"
|
|
96
|
+
node -e 'const fs=require("node:fs");const r=JSON.parse(fs.readFileSync(process.argv[1],"utf8"));if(!r.compactSummary||!r.setupDigest){console.error("bound setup report incomplete");process.exit(2)}process.stdout.write(JSON.stringify({compactSummary:r.compactSummary,setupDigest:r.setupDigest},null,2)+"\n")' "$BOUND_REPORT"
|
|
97
|
+
printf 'SETUP_SESSION=%s\nPROJECT=%s\n' "$SETUP_SESSION" "$PROJECT"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
After one explicit human confirmation of the bound summary and exact digest,
|
|
101
|
+
create once with that confirmed digest literal. The result must be
|
|
102
|
+
`CONFIG_CREATED`; a second setup must be `ALREADY_CONFIGURED`, then run assess.
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
SETUP_SESSION=<session-directory-absolute-path-printed-above>
|
|
106
|
+
PROJECT=<project-absolute-path-printed-above>
|
|
107
|
+
ANSWERS="$SETUP_SESSION/answers.json"
|
|
108
|
+
CREATED_REPORT="$SETUP_SESSION/created.json"
|
|
109
|
+
POST_REPORT="$SETUP_SESSION/post-setup.json"
|
|
110
|
+
ASSESS_REPORT="$SETUP_SESSION/assess.json"
|
|
111
|
+
"${CLI[@]}" setup --root "$PROJECT" --answers "$ANSWERS" \
|
|
112
|
+
--write --confirm-setup <confirmed-setupDigest> --json > "$CREATED_REPORT"
|
|
113
|
+
"${CLI[@]}" setup --root "$PROJECT" --json > "$POST_REPORT"
|
|
114
|
+
set +e
|
|
115
|
+
"${CLI[@]}" assess --root "$PROJECT" --offline --json > "$ASSESS_REPORT"
|
|
116
|
+
ASSESS_EXIT=$?
|
|
117
|
+
set -e
|
|
118
|
+
[ "$ASSESS_EXIT" -eq 0 ] || [ "$ASSESS_EXIT" -eq 1 ] || exit "$ASSESS_EXIT"
|
|
119
|
+
node -e 'const fs=require("node:fs");const [c,p,a]=process.argv.slice(1).map(x=>JSON.parse(fs.readFileSync(x,"utf8")));if(c.status!=="CONFIG_CREATED"||p.status!=="ALREADY_CONFIGURED"||!["ASSESSED","NEEDS_INPUT","BLOCKED"].includes(a.status)){process.exit(2)}process.stdout.write(JSON.stringify({created:c.status,postSetup:p.status,assessment:{status:a.status,summary:a.summary,gapCount:(a.gaps??[]).length,blockingCodes:(a.gaps??[]).filter(g=>g.severity==="error").map(g=>g.code)}},null,2)+"\n")' "$CREATED_REPORT" "$POST_REPORT" "$ASSESS_REPORT"
|
|
120
|
+
node -e 'require("node:fs").rmSync(process.argv[1],{recursive:true,force:false})' "$SETUP_SESSION"
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Indirect interpreter/package-manager scripts are `SIDE_EFFECTS_UNPROVEN` and
|
|
124
|
+
remain unselected. Register a project-specific hook/gate only through a reviewed
|
|
125
|
+
incremental edit: edit `projectConfig.hooks`, or edit `verificationGates` and
|
|
126
|
+
add the same id to `selectedGateIds`, then rerun the bound dry-run. Human files use `mode: preserve`; explicit cross-unit shared
|
|
127
|
+
sources use `sourceScope: workspace`.
|
|
128
|
+
|
|
129
|
+
### Advanced schema reference—not the first-run path
|
|
130
|
+
|
|
131
|
+
The following wrapper documents the schema. Do not hand-write it during normal
|
|
132
|
+
setup; use the mechanically extracted `recommendedAnswers`.
|
|
82
133
|
|
|
83
134
|
```json
|
|
84
135
|
{
|
|
@@ -116,25 +167,11 @@ answers, then create the configuration exactly once:
|
|
|
116
167
|
}
|
|
117
168
|
```
|
|
118
169
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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
|
-
```
|
|
170
|
+
This wrapper is reference data only. Normal setup uses the machine proposal;
|
|
171
|
+
`mode: none` is valid only when no public version exists. When a reviewed gate
|
|
172
|
+
is added incrementally, its id must exactly match `selectedGateIds`, and a
|
|
173
|
+
snapshot gate plus its dependencies must be present in `publicFiles`. See the
|
|
174
|
+
[README setup section](README.md#first-use-deterministic-setup-without-loading-the-full-report).
|
|
138
175
|
|
|
139
176
|
An existing config is never regenerated or overwritten. A project with no
|
|
140
177
|
discoverable GitHub/npm channel reports `LOCAL_ONLY_DETECTED` rather than
|
package/INSTALL.zh-CN.md
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[English](INSTALL.md)
|
|
4
4
|
|
|
5
|
+
<!-- release-skill:release-version: 0.1.5 -->
|
|
5
6
|
## 前置条件
|
|
6
7
|
|
|
7
8
|
- Node.js 22.0.0 或更高版本
|
|
@@ -9,9 +10,9 @@
|
|
|
9
10
|
|
|
10
11
|
## 从 npm 安装(推荐)
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
`npm view release-skill version` 返回该精确版本后才使用 npm
|
|
14
|
-
|
|
13
|
+
公开版本只有在不可变生产计划经过批准、发布并达到 `VERIFIED` 后才算完整。对于更新的
|
|
14
|
+
源码检出,只有当 `npm view release-skill version` 返回该精确版本后才使用 npm 安装;
|
|
15
|
+
在此之前请使用下文的源码检出方式。
|
|
15
16
|
|
|
16
17
|
```bash
|
|
17
18
|
npm install -g release-skill
|
|
@@ -61,18 +62,67 @@ CLI=(node "$RELEASE_SKILL_HOME/packages/release-skill/bin/release-skill.mjs")
|
|
|
61
62
|
"${CLI[@]}" help
|
|
62
63
|
```
|
|
63
64
|
|
|
64
|
-
如果项目尚无 `.release-skill/project.yaml
|
|
65
|
+
如果项目尚无 `.release-skill/project.yaml`,把完整只读报告写入临时文件,只查看其中
|
|
66
|
+
确定性的 `compactSummary`(紧凑摘要):
|
|
65
67
|
|
|
66
68
|
```bash
|
|
67
|
-
|
|
69
|
+
PROJECT=/path/to/your/project
|
|
70
|
+
SETUP_SESSION="$(mktemp -d "${TMPDIR:-/tmp}/release-setup.XXXXXX")"
|
|
71
|
+
REPORT="$SETUP_SESSION/discovery.json"
|
|
72
|
+
ANSWERS="$SETUP_SESSION/answers.json"
|
|
73
|
+
BOUND_REPORT="$SETUP_SESSION/bound.json"
|
|
74
|
+
printf 'SETUP_SESSION=%s\nPROJECT=%s\n' "$SETUP_SESSION" "$PROJECT"
|
|
75
|
+
|
|
76
|
+
"${CLI[@]}" setup --root "$PROJECT" --json > "$REPORT" || test "$?" -eq 2
|
|
77
|
+
node -e 'const fs=require("node:fs");const r=JSON.parse(fs.readFileSync(process.argv[1],"utf8"));if(!r.compactSummary){console.error("compactSummary missing");process.exit(2)}process.stdout.write(JSON.stringify(r.compactSummary,null,2)+"\n")' "$REPORT"
|
|
68
78
|
```
|
|
69
79
|
|
|
70
|
-
`
|
|
71
|
-
|
|
80
|
+
紧凑摘要只是审阅视图,不是授权;`setupDigest` 仍绑定完整事实、候选和 answers。若
|
|
81
|
+
`proposalConflicts` 非空,必须由人工修正冲突的仓库/映射权威事实后重跑 setup,不能
|
|
82
|
+
猜测选边。没有冲突时,机械提取机器提案:
|
|
72
83
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
84
|
+
```bash
|
|
85
|
+
SETUP_SESSION='/上一步打印的会话目录绝对路径'
|
|
86
|
+
PROJECT='/上一步打印的项目绝对路径'
|
|
87
|
+
REPORT="$SETUP_SESSION/discovery.json"
|
|
88
|
+
ANSWERS="$SETUP_SESSION/answers.json"
|
|
89
|
+
BOUND_REPORT="$SETUP_SESSION/bound.json"
|
|
90
|
+
node -e 'const fs=require("node:fs");const r=JSON.parse(fs.readFileSync(process.argv[1],"utf8"));if((r.proposalConflicts??[]).length){console.error("proposal conflicts require human resolution");process.exit(2)}if(!r.recommendedAnswers){console.error("recommendedAnswers missing");process.exit(2)}fs.writeFileSync(process.argv[2],JSON.stringify(r.recommendedAnswers,null,2)+"\n",{flag:"wx",mode:0o600})' "$REPORT" "$ANSWERS"
|
|
91
|
+
"${CLI[@]}" setup --root "$PROJECT" --answers "$ANSWERS" --json > "$BOUND_REPORT"
|
|
92
|
+
node -e 'const fs=require("node:fs");const r=JSON.parse(fs.readFileSync(process.argv[1],"utf8"));if(!r.compactSummary||!r.setupDigest){console.error("bound setup report incomplete");process.exit(2)}process.stdout.write(JSON.stringify({compactSummary:r.compactSummary,setupDigest:r.setupDigest},null,2)+"\n")' "$BOUND_REPORT"
|
|
93
|
+
printf 'SETUP_SESSION=%s\nPROJECT=%s\n' "$SETUP_SESSION" "$PROJECT"
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
人工只确认一次绑定摘要和精确摘要值,然后使用已确认字面量首次创建。结果必须是
|
|
97
|
+
`CONFIG_CREATED`;第二次 setup 必须是 `ALREADY_CONFIGURED`,随后运行 assess。
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
SETUP_SESSION=<上一步打印的会话目录绝对路径>
|
|
101
|
+
PROJECT=<上一步打印的项目绝对路径>
|
|
102
|
+
ANSWERS="$SETUP_SESSION/answers.json"
|
|
103
|
+
CREATED_REPORT="$SETUP_SESSION/created.json"
|
|
104
|
+
POST_REPORT="$SETUP_SESSION/post-setup.json"
|
|
105
|
+
ASSESS_REPORT="$SETUP_SESSION/assess.json"
|
|
106
|
+
"${CLI[@]}" setup --root "$PROJECT" --answers "$ANSWERS" \
|
|
107
|
+
--write --confirm-setup <已确认的 setupDigest> --json > "$CREATED_REPORT"
|
|
108
|
+
"${CLI[@]}" setup --root "$PROJECT" --json > "$POST_REPORT"
|
|
109
|
+
set +e
|
|
110
|
+
"${CLI[@]}" assess --root "$PROJECT" --offline --json > "$ASSESS_REPORT"
|
|
111
|
+
ASSESS_EXIT=$?
|
|
112
|
+
set -e
|
|
113
|
+
[ "$ASSESS_EXIT" -eq 0 ] || [ "$ASSESS_EXIT" -eq 1 ] || exit "$ASSESS_EXIT"
|
|
114
|
+
node -e 'const fs=require("node:fs");const [c,p,a]=process.argv.slice(1).map(x=>JSON.parse(fs.readFileSync(x,"utf8")));if(c.status!=="CONFIG_CREATED"||p.status!=="ALREADY_CONFIGURED"||!["ASSESSED","NEEDS_INPUT","BLOCKED"].includes(a.status)){process.exit(2)}process.stdout.write(JSON.stringify({created:c.status,postSetup:p.status,assessment:{status:a.status,summary:a.summary,gapCount:(a.gaps??[]).length,blockingCodes:(a.gaps??[]).filter(g=>g.severity==="error").map(g=>g.code)}},null,2)+"\n")' "$CREATED_REPORT" "$POST_REPORT" "$ASSESS_REPORT"
|
|
115
|
+
node -e 'require("node:fs").rmSync(process.argv[1],{recursive:true,force:false})' "$SETUP_SESSION"
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
解释器/包管理器间接脚本以 `SIDE_EFFECTS_UNPROVEN` 排除且默认不选。项目特有 hook/gate
|
|
119
|
+
只能经人工审阅后增量注册:hook 编辑 `projectConfig.hooks`;gate 编辑
|
|
120
|
+
`verificationGates` 并将同一 id 加入 `selectedGateIds`,然后重跑绑定 dry-run。人工文件使用 `mode: preserve`;显式跨单元共享源使用
|
|
121
|
+
`sourceScope: workspace`。
|
|
122
|
+
|
|
123
|
+
### 进阶 schema 参考——不是首次运行主路径
|
|
124
|
+
|
|
125
|
+
下面的外壳只说明 schema。正常 setup 不应手写,而应机械提取 `recommendedAnswers`。
|
|
76
126
|
|
|
77
127
|
```json
|
|
78
128
|
{
|
|
@@ -110,22 +160,10 @@ dry-run(只读试运行),取得同时绑定当前事实与人工答案的
|
|
|
110
160
|
}
|
|
111
161
|
```
|
|
112
162
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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
|
-
```
|
|
163
|
+
这个外壳仅供参考。正常 setup 必须使用机器提案;只有确认不存在历史公开版本时才可
|
|
164
|
+
使用 `mode: none`。人工增量加入 gate 时,其 id 必须与 `selectedGateIds` 精确一致,
|
|
165
|
+
snapshot gate 及其依赖必须存在于 `publicFiles`。详见
|
|
166
|
+
[README 首次接入章节](README.zh-CN.md#首次接入不加载完整报告的确定性流程)。
|
|
129
167
|
|
|
130
168
|
已有配置永远不会被重新生成或覆盖。无法发现 GitHub/npm 渠道的项目返回
|
|
131
169
|
`LOCAL_ONLY_DETECTED`,不会冒充生产就绪。
|
package/README.md
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[简体中文](README.zh-CN.md) · Installation: [English](INSTALL.md) / [简体中文](INSTALL.zh-CN.md)
|
|
4
4
|
|
|
5
|
+
<!-- release-skill:release-version: 0.1.5 -->
|
|
5
6
|
Release preparation for Claude Code and Codex, with human-edited files kept intact.
|
|
6
7
|
|
|
7
8
|
release-skill helps a maintainer answer three questions: what will be released,
|
|
@@ -10,21 +11,25 @@ reviewed artifacts first and publishes those same artifacts later; it does not
|
|
|
10
11
|
regenerate a README or re-pack the live workspace at the last step.
|
|
11
12
|
|
|
12
13
|
<!-- release-skill:capability:external-write-boundary -->
|
|
13
|
-
> **Current boundary:** v0.1.1 completed a real production release
|
|
14
|
-
> npm
|
|
15
|
-
>
|
|
16
|
-
>
|
|
17
|
-
>
|
|
18
|
-
>
|
|
19
|
-
>
|
|
20
|
-
>
|
|
21
|
-
>
|
|
22
|
-
>
|
|
23
|
-
>
|
|
14
|
+
> **Current boundary:** v0.1.5 is the current release. v0.1.1 completed a real production release
|
|
15
|
+
> to GitHub and npm — the first production-verified milestone — followed by
|
|
16
|
+
> exact npm installation and Claude/Codex consumer installation verification
|
|
17
|
+
> from the frozen Git ref; "current release" and "first production-verified
|
|
18
|
+
> milestone" are two distinct facts and must not be conflated. The same
|
|
19
|
+
> workflow also has a local production-equivalent protocol suite using the
|
|
20
|
+
> real release-skill CLI and frozen artifacts, local bare Git remotes, and
|
|
21
|
+
> protocol fakes for `gh`, `npm`, Claude, and Codex. The suite does not
|
|
22
|
+
> provide OS-level network isolation, and it does not prove that another
|
|
23
|
+
> project's credentials, permissions, rate limits, or eventual-consistency
|
|
24
|
+
> behavior will match this release. Treat each project's first production run
|
|
25
|
+
> as a monitored canary. `prepare --online` observes bound previous-public
|
|
26
|
+
> baselines and fails closed on drift; remote uniqueness checks run during
|
|
27
|
+
> publish global preflight.
|
|
24
28
|
|
|
25
29
|
<!-- release-skill:capability:safe-first-command -->
|
|
26
|
-
> **v0.1.1
|
|
27
|
-
>
|
|
30
|
+
> **Production path verified since the v0.1.1 milestone; v0.1.5 is the current
|
|
31
|
+
> release.** The npm-installed CLI is the supported user entry. Source checkout
|
|
32
|
+
> is the development/contributor fallback.
|
|
28
33
|
>
|
|
29
34
|
> **Start here:**
|
|
30
35
|
> - npm install: `npm install -g release-skill` → `release-skill help`
|
|
@@ -55,6 +60,13 @@ slogans, examples, prose, formatting, and later human edits.
|
|
|
55
60
|
intervention; the tool does not force or overwrite them.
|
|
56
61
|
- Only files listed in `publicFiles` are copied. Add translated READMEs, images,
|
|
57
62
|
demos, and linked documents explicitly when they belong in the release.
|
|
63
|
+
- A release freezes only the current truth: `prepare` never refreshes or
|
|
64
|
+
rewrites human docs. Maintainers update README, INSTALL, and CHANGELOG first
|
|
65
|
+
— including the machine-readable `release-skill:release-version` markers,
|
|
66
|
+
which must equal the `package.json` version, and the formal CHANGELOG
|
|
67
|
+
heading for the current version — then prepare, review, and approve. A
|
|
68
|
+
pre-release gate fails closed when any doc version marker or the CHANGELOG
|
|
69
|
+
current-version entry drifts.
|
|
58
70
|
|
|
59
71
|
This is the preservation contract: **copy current truth, freeze reviewed
|
|
60
72
|
truth, and never rewrite human truth.**
|
|
@@ -104,26 +116,81 @@ First keep local plans, approvals, and frozen artifacts out of Git:
|
|
|
104
116
|
!.release-skill/project.yaml
|
|
105
117
|
```
|
|
106
118
|
|
|
107
|
-
### First use:
|
|
119
|
+
### First use: deterministic setup without loading the full report
|
|
108
120
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
automatically selects or executes a script:
|
|
121
|
+
Setup is read-only by default. Keep its potentially large report in temporary
|
|
122
|
+
files; show the user or Agent only the deterministic `compactSummary` review
|
|
123
|
+
view. The summary does not replace authorization: `setupDigest` still binds the
|
|
124
|
+
complete facts, candidates, and answers.
|
|
114
125
|
|
|
115
126
|
```bash
|
|
116
|
-
|
|
127
|
+
PROJECT=/absolute/path/to/my-project
|
|
128
|
+
SETUP_SESSION="$(mktemp -d "${TMPDIR:-/tmp}/release-setup.XXXXXX")"
|
|
129
|
+
REPORT="$SETUP_SESSION/discovery.json"
|
|
130
|
+
ANSWERS="$SETUP_SESSION/answers.json"
|
|
131
|
+
BOUND_REPORT="$SETUP_SESSION/bound.json"
|
|
132
|
+
printf 'SETUP_SESSION=%s\nPROJECT=%s\n' "$SETUP_SESSION" "$PROJECT"
|
|
133
|
+
|
|
134
|
+
release-skill setup --root "$PROJECT" --json > "$REPORT" || test "$?" -eq 2
|
|
135
|
+
node -e 'const fs=require("node:fs");const r=JSON.parse(fs.readFileSync(process.argv[1],"utf8"));if(!r.compactSummary){console.error("compactSummary missing");process.exit(2)}process.stdout.write(JSON.stringify(r.compactSummary,null,2)+"\n")' "$REPORT"
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
`NEEDS_INPUT` and `LOCAL_ONLY_DETECTED` intentionally exit with code 2. If
|
|
139
|
+
`proposalConflicts` is non-empty—including `PUBLIC_REPO_AUTHORITY_CONFLICT` or
|
|
140
|
+
a public-file mapping conflict—stop and let a human correct the conflicting
|
|
141
|
+
repository or mapping authority, then rerun setup. Do not guess a winner.
|
|
142
|
+
|
|
143
|
+
With no conflicts, copy the machine proposal mechanically. The Agent must not
|
|
144
|
+
rewrite or transcribe it:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
SETUP_SESSION='/session-directory-absolute-path-printed-above'
|
|
148
|
+
PROJECT='/project-absolute-path-printed-above'
|
|
149
|
+
REPORT="$SETUP_SESSION/discovery.json"
|
|
150
|
+
ANSWERS="$SETUP_SESSION/answers.json"
|
|
151
|
+
BOUND_REPORT="$SETUP_SESSION/bound.json"
|
|
152
|
+
node -e 'const fs=require("node:fs");const r=JSON.parse(fs.readFileSync(process.argv[1],"utf8"));if((r.proposalConflicts??[]).length){console.error("proposal conflicts require human resolution");process.exit(2)}if(!r.recommendedAnswers){console.error("recommendedAnswers missing");process.exit(2)}fs.writeFileSync(process.argv[2],JSON.stringify(r.recommendedAnswers,null,2)+"\n",{flag:"wx",mode:0o600})' "$REPORT" "$ANSWERS"
|
|
153
|
+
|
|
154
|
+
release-skill setup --root "$PROJECT" --answers "$ANSWERS" --json > "$BOUND_REPORT"
|
|
155
|
+
node -e 'const fs=require("node:fs");const r=JSON.parse(fs.readFileSync(process.argv[1],"utf8"));if(!r.compactSummary||!r.setupDigest){console.error("bound setup report incomplete");process.exit(2)}process.stdout.write(JSON.stringify({compactSummary:r.compactSummary,setupDigest:r.setupDigest},null,2)+"\n")' "$BOUND_REPORT"
|
|
156
|
+
printf 'SETUP_SESSION=%s\nPROJECT=%s\n' "$SETUP_SESSION" "$PROJECT"
|
|
117
157
|
```
|
|
118
158
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
`status` instead of treating every nonzero setup result as an internal failure.
|
|
159
|
+
Review that bound summary and exact digest once. After explicit human
|
|
160
|
+
confirmation, use the confirmed digest literal to create the configuration:
|
|
122
161
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
162
|
+
```bash
|
|
163
|
+
SETUP_SESSION=<session-directory-absolute-path-printed-above>
|
|
164
|
+
PROJECT=<project-absolute-path-printed-above>
|
|
165
|
+
ANSWERS="$SETUP_SESSION/answers.json"
|
|
166
|
+
CREATED_REPORT="$SETUP_SESSION/created.json"
|
|
167
|
+
POST_REPORT="$SETUP_SESSION/post-setup.json"
|
|
168
|
+
ASSESS_REPORT="$SETUP_SESSION/assess.json"
|
|
169
|
+
release-skill setup --root "$PROJECT" --answers "$ANSWERS" \
|
|
170
|
+
--write --confirm-setup <confirmed-setupDigest> --json > "$CREATED_REPORT"
|
|
171
|
+
release-skill setup --root "$PROJECT" --json > "$POST_REPORT"
|
|
172
|
+
set +e
|
|
173
|
+
release-skill assess --root "$PROJECT" --offline --json > "$ASSESS_REPORT"
|
|
174
|
+
ASSESS_EXIT=$?
|
|
175
|
+
set -e
|
|
176
|
+
[ "$ASSESS_EXIT" -eq 0 ] || [ "$ASSESS_EXIT" -eq 1 ] || exit "$ASSESS_EXIT"
|
|
177
|
+
node -e 'const fs=require("node:fs");const [c,p,a]=process.argv.slice(1).map(x=>JSON.parse(fs.readFileSync(x,"utf8")));if(c.status!=="CONFIG_CREATED"||p.status!=="ALREADY_CONFIGURED"||!["ASSESSED","NEEDS_INPUT","BLOCKED"].includes(a.status)){process.exit(2)}process.stdout.write(JSON.stringify({created:c.status,postSetup:p.status,assessment:{status:a.status,summary:a.summary,gapCount:(a.gaps??[]).length,blockingCodes:(a.gaps??[]).filter(g=>g.severity==="error").map(g=>g.code)}},null,2)+"\n")' "$CREATED_REPORT" "$POST_REPORT" "$ASSESS_REPORT"
|
|
178
|
+
node -e 'require("node:fs").rmSync(process.argv[1],{recursive:true,force:false})' "$SETUP_SESSION"
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
The write must return `CONFIG_CREATED`; the next setup must return
|
|
182
|
+
`ALREADY_CONFIGURED`. Existing configuration is never regenerated—make only
|
|
183
|
+
reviewed incremental edits. Discovered interpreter/package-manager scripts are
|
|
184
|
+
`SIDE_EFFECTS_UNPROVEN` and are not selected automatically. Add a project-specific
|
|
185
|
+
hook or gate only after human review: edit `projectConfig.hooks`, or edit
|
|
186
|
+
`verificationGates` and add the same id to `selectedGateIds`, then rerun the
|
|
187
|
+
bound dry-run. Keep human files at `mode: preserve`, and
|
|
188
|
+
use `sourceScope: workspace` only for explicit cross-unit shared sources.
|
|
189
|
+
|
|
190
|
+
#### Advanced schema reference—not the first-use path
|
|
191
|
+
|
|
192
|
+
The wrapper below illustrates the schema only. Do not hand-write it during the
|
|
193
|
+
normal setup path; mechanically extract `recommendedAnswers` as shown above.
|
|
127
194
|
|
|
128
195
|
```json
|
|
129
196
|
{
|
|
@@ -161,15 +228,12 @@ again with those answers, review the new `setupDigest`, then create the config:
|
|
|
161
228
|
}
|
|
162
229
|
```
|
|
163
230
|
|
|
164
|
-
This is a
|
|
165
|
-
|
|
166
|
-
reviewed facts from your project; use `mode: none` only when no public version
|
|
167
|
-
exists.
|
|
231
|
+
This is a schema reference, not an onboarding template. Normal setup must use
|
|
232
|
+
the machine proposal. `mode: none` is valid only when no public version exists.
|
|
168
233
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
`my-project-script-test`:
|
|
234
|
+
The following reference shows the exact relationship between a manually
|
|
235
|
+
reviewed gate and `selectedGateIds`. Apply that relationship only as an
|
|
236
|
+
incremental edit to the extracted machine proposal:
|
|
173
237
|
|
|
174
238
|
```json
|
|
175
239
|
{
|
|
@@ -407,8 +471,8 @@ publication. The source checkout remains the development/contributor fallback.
|
|
|
407
471
|
```bash
|
|
408
472
|
"${CLI[@]}" setup --root "$PROJECT" --json
|
|
409
473
|
```
|
|
410
|
-
|
|
411
|
-
skip this step when configuration
|
|
474
|
+
Follow the mechanical `compactSummary` and `recommendedAnswers` path above;
|
|
475
|
+
confirm the bound `setupDigest` once, and skip this step when configuration exists.
|
|
412
476
|
3. **Readiness assessment (read-only):**
|
|
413
477
|
```bash
|
|
414
478
|
"${CLI[@]}" assess --root "$PROJECT" --offline --json
|
|
@@ -562,10 +626,12 @@ releaseUnits:
|
|
|
562
626
|
plugin: my-plugin
|
|
563
627
|
marketplace: my-plugin
|
|
564
628
|
entrySkill: my-plugin-help
|
|
629
|
+
timeoutMs: 300000 # optional; range 30000-900000; default 300000
|
|
565
630
|
- type: codex-plugin
|
|
566
631
|
plugin: my-plugin
|
|
567
632
|
marketplace: my-plugin
|
|
568
633
|
entrySkill: my-plugin-help
|
|
634
|
+
timeoutMs: 300000 # optional; range 30000-900000; default 300000
|
|
569
635
|
publicFiles:
|
|
570
636
|
- from: packages/plugin/.claude-plugin/plugin.json
|
|
571
637
|
to: .claude-plugin/plugin.json
|
|
@@ -612,6 +678,14 @@ the entry Skill, and all required public files. A CLI smoke (`smokeBin`) is
|
|
|
612
678
|
optional for plugin units and only applies when the published npm package
|
|
613
679
|
exposes a CLI binary.
|
|
614
680
|
|
|
681
|
+
Plugin distributions may declare `timeoutMs` (range 30,000--900,000 ms; default
|
|
682
|
+
300,000 ms). This sets the subprocess timeout for the marketplace add, plugin
|
|
683
|
+
install, and plugin list commands. On real networks these commands can take
|
|
684
|
+
40--105 seconds; the default 300-second timeout avoids false `PARTIAL` failures.
|
|
685
|
+
The resolved value is frozen into the plan and approved along with all other
|
|
686
|
+
action parameters. Old plans without `timeoutMs` default to 300,000 ms at
|
|
687
|
+
execution time for backward compatibility.
|
|
688
|
+
|
|
615
689
|
### PARTIAL recovery and reconcile
|
|
616
690
|
|
|
617
691
|
When `publish` succeeds at some checkpoints but fails at others, the run enters
|