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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
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
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
"schemas/",
|
|
28
28
|
"native/",
|
|
29
29
|
"!native/safe-write/build/",
|
|
30
|
+
"scripts/build-bundle.mjs",
|
|
30
31
|
"README.md",
|
|
31
32
|
"README.zh-CN.md",
|
|
32
33
|
"CHANGELOG.md",
|
|
@@ -39,7 +40,7 @@
|
|
|
39
40
|
"SECURITY.md"
|
|
40
41
|
],
|
|
41
42
|
"scripts": {
|
|
42
|
-
"build": "node --check src/**/*.mjs",
|
|
43
|
+
"build": "node --check src/**/*.mjs && node scripts/build-bundle.mjs",
|
|
43
44
|
"test": "node --test test/*.test.mjs",
|
|
44
45
|
"test:no-dogfood": "node --test $(ls test/*.test.mjs | grep -v -E 'dogfood|artifacts-safe-fs-native-seam')",
|
|
45
46
|
"typecheck": "node --check src/**/*.mjs bin/*.mjs",
|
|
@@ -47,6 +48,8 @@
|
|
|
47
48
|
"sync:skills:check": "node scripts/sync-skills.mjs --check",
|
|
48
49
|
"build:adapters": "node scripts/build-adapters.mjs",
|
|
49
50
|
"build:adapters:check": "node scripts/build-adapters.mjs --check",
|
|
51
|
+
"build:bundle": "node scripts/build-bundle.mjs",
|
|
52
|
+
"build:bundle:check": "node scripts/build-bundle.mjs --check",
|
|
50
53
|
"native:build": "node-gyp rebuild --directory native/safe-write",
|
|
51
54
|
"native:package-current": "node scripts/package-native-prebuild.mjs",
|
|
52
55
|
"native:build:test": "GYP_DEFINES='test_seam=1' node-gyp rebuild --directory native/safe-write",
|
|
@@ -60,6 +63,7 @@
|
|
|
60
63
|
"yaml": "2.9.0"
|
|
61
64
|
},
|
|
62
65
|
"devDependencies": {
|
|
66
|
+
"esbuild": "0.25.8",
|
|
63
67
|
"node-gyp": "12.3.0"
|
|
64
68
|
},
|
|
65
69
|
"engines": {
|
|
@@ -77,7 +77,7 @@ policy: # 可选,安全策略
|
|
|
77
77
|
|
|
78
78
|
## 3. 公开源码镜像与分发包
|
|
79
79
|
|
|
80
|
-
`releaseUnits[].publicFiles` 定义 GitHub 公开源码镜像的显式、闭世界 allowlist。每个映射都必须可审阅;未列出的文件不会因为目录扫描、模板重生成或历史惯例而被自动加入。`releaseUnits[].requiredPublicFiles` 只约束同一发布单元,不能借用其他单元的目标路径。
|
|
80
|
+
`releaseUnits[].publicFiles` 定义 GitHub 公开源码镜像的显式、闭世界 allowlist。每个映射都必须可审阅;未列出的文件不会因为目录扫描、模板重生成或历史惯例而被自动加入。`sourceScope` 默认为 `unit`,此时 `from` 必须位于 `releaseUnits[].source` 内;只有历史共享许可证、公共文档或工作流等明确的工作空间级来源才可写 `sourceScope: workspace`,其路径仍必须受工作空间根目录的词法、realpath 和无符号链接校验约束。`releaseUnits[].requiredPublicFiles` 只约束同一发布单元,不能借用其他单元的目标路径。
|
|
81
81
|
|
|
82
82
|
公开源码镜像与 distribution pack 是两条不同边界:前者决定公开仓库快照,后者由 npm `files`、插件 manifest 等渠道合同决定安装内容。发布前必须分别冻结、比较并验证两条边界;distribution pack 中的必需路径必须由该发布单元的公开映射覆盖。
|
|
83
83
|
|
|
@@ -166,7 +166,7 @@ gate 与 legacy hook 都是无网络沙箱的本地进程,必须显式确认
|
|
|
166
166
|
|
|
167
167
|
### 4.2 首次接入 setup
|
|
168
168
|
|
|
169
|
-
`release-skill setup --root <path> --json` 默认只读,扫描工作区、包与插件 manifest
|
|
169
|
+
`release-skill setup --root <path> --json` 默认只读,扫描工作区、包与插件 manifest、逐单元 Git 权威、旧版 `public-release.json` 和脚本,输出候选、完整 `recommendedAnswers`、结构化冲突/假设和 `setupDigest`。旧配置只作为不可信迁移事实,其中的 `snapshotCommands` 只成为未授权 gate 候选;它不会把脚本存在解释成用户选择,也不会读取 README 中的自然语言作为命令。报告可能包含大量精确映射,Agent 应先把完整 JSON 落到系统临时文件,只读取紧凑摘要,并机械提取 `recommendedAnswers`,不得在上下文中重新生成。
|
|
170
170
|
|
|
171
171
|
写入要求人工提供完整 answers JSON,再次 dry-run,并使用同一摘要执行 `--write --confirm-setup <setupDigest>`。写入只允许首次原子创建 `.release-skill/project.yaml`;已有配置返回 `ALREADY_CONFIGURED`/`CONFIG_EXISTS`,由人工增量编辑。事实漂移返回 `SETUP_DIGEST_MISMATCH`。没有远端渠道的项目返回 `LOCAL_ONLY_DETECTED`,不得宣称 production-ready。
|
|
172
172
|
|
|
@@ -210,7 +210,8 @@
|
|
|
210
210
|
"branch",
|
|
211
211
|
"branchStrategy",
|
|
212
212
|
"commit",
|
|
213
|
-
"tree"
|
|
213
|
+
"tree",
|
|
214
|
+
"commitTimestamp"
|
|
214
215
|
],
|
|
215
216
|
"additionalProperties": false,
|
|
216
217
|
"properties": {
|
|
@@ -238,6 +239,11 @@
|
|
|
238
239
|
"type": "string",
|
|
239
240
|
"pattern": "^[a-f0-9]{40,64}$"
|
|
240
241
|
},
|
|
242
|
+
"commitTimestamp": {
|
|
243
|
+
"type": "string",
|
|
244
|
+
"pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\+00:00$",
|
|
245
|
+
"description": "Plan freeze timestamp sampled exactly once during production prepare, in canonical UTC second precision. Written verbatim to GIT_AUTHOR_DATE and GIT_COMMITTER_DATE of the frozen release commit, so it always equals the commit's %aI and %cI byte-for-byte, and must equal the plan's createdAt."
|
|
246
|
+
},
|
|
241
247
|
"parentCommit": {
|
|
242
248
|
"type": "string",
|
|
243
249
|
"pattern": "^[a-f0-9]{40,64}$"
|
|
@@ -200,6 +200,12 @@
|
|
|
200
200
|
},
|
|
201
201
|
"smokeExpectedJson": {
|
|
202
202
|
"type": "object"
|
|
203
|
+
},
|
|
204
|
+
"timeoutMs": {
|
|
205
|
+
"type": "integer",
|
|
206
|
+
"minimum": 30000,
|
|
207
|
+
"maximum": 900000,
|
|
208
|
+
"description": "Timeout in milliseconds for plugin marketplace install commands. Only valid for claude-plugin and codex-plugin distributions."
|
|
203
209
|
}
|
|
204
210
|
},
|
|
205
211
|
"allOf": [
|
|
@@ -219,6 +225,23 @@
|
|
|
219
225
|
]
|
|
220
226
|
}
|
|
221
227
|
},
|
|
228
|
+
{
|
|
229
|
+
"if": {
|
|
230
|
+
"required": [
|
|
231
|
+
"timeoutMs"
|
|
232
|
+
]
|
|
233
|
+
},
|
|
234
|
+
"then": {
|
|
235
|
+
"properties": {
|
|
236
|
+
"type": {
|
|
237
|
+
"enum": [
|
|
238
|
+
"claude-plugin",
|
|
239
|
+
"codex-plugin"
|
|
240
|
+
]
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
},
|
|
222
245
|
{
|
|
223
246
|
"if": {
|
|
224
247
|
"properties": {
|
|
@@ -287,6 +310,14 @@
|
|
|
287
310
|
],
|
|
288
311
|
"additionalProperties": false,
|
|
289
312
|
"properties": {
|
|
313
|
+
"sourceScope": {
|
|
314
|
+
"type": "string",
|
|
315
|
+
"enum": [
|
|
316
|
+
"unit",
|
|
317
|
+
"workspace"
|
|
318
|
+
],
|
|
319
|
+
"default": "unit"
|
|
320
|
+
},
|
|
290
321
|
"from": {
|
|
291
322
|
"type": "string",
|
|
292
323
|
"minLength": 1,
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* build-bundle.mjs
|
|
4
|
+
*
|
|
5
|
+
* Deterministic CLI bundle for self-contained plugin execution.
|
|
6
|
+
* Bundles bin/release-skill.mjs + all npm dependencies into a single
|
|
7
|
+
* ESM file that runs without node_modules.
|
|
8
|
+
*
|
|
9
|
+
* Schemas and native addons remain external (loaded at runtime from
|
|
10
|
+
* the plugin root via PKG_ROOT).
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* node scripts/build-bundle.mjs # build mode
|
|
14
|
+
* node scripts/build-bundle.mjs --check # check-only mode (exit 1 on drift)
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
18
|
+
import { dirname, join } from 'node:path';
|
|
19
|
+
import { createHash } from 'node:crypto';
|
|
20
|
+
|
|
21
|
+
const CHECK_MODE = process.argv.includes('--check');
|
|
22
|
+
|
|
23
|
+
const SCRIPT_DIR = dirname(new URL(import.meta.url).pathname);
|
|
24
|
+
const PKG_ROOT = join(SCRIPT_DIR, '..');
|
|
25
|
+
const ENTRY = join(PKG_ROOT, 'bin', 'release-skill-cli.mjs');
|
|
26
|
+
const OUTFILE = join(PKG_ROOT, 'bin', 'release-skill.bundle.mjs');
|
|
27
|
+
|
|
28
|
+
// Banner: compute PKG_ROOT deterministically from the bundle's own path.
|
|
29
|
+
// No env-var override — callers cannot hijack schema/native resolution.
|
|
30
|
+
// Uses import.meta.url only — process.argv[1] is not a reliable resource root.
|
|
31
|
+
const BANNER = `\
|
|
32
|
+
// --- release-skill bundle (deterministic build) ---
|
|
33
|
+
// Compute package root from the bundle's own file location (import.meta.url).
|
|
34
|
+
// The bundle lives at <PKG_ROOT>/bin/release-skill.bundle.mjs, so go up one level.
|
|
35
|
+
import { fileURLToPath as __bundleFileURLToPath } from 'node:url';
|
|
36
|
+
import { dirname as __bundleDirname, resolve as __bundleResolve } from 'node:path';
|
|
37
|
+
import { createRequire as __bundleCreateRequire } from 'node:module';
|
|
38
|
+
const __bundlePkgRoot = __bundleResolve(__bundleDirname(__bundleFileURLToPath(import.meta.url)), '..');
|
|
39
|
+
// Provide a real require() for CJS packages bundled into ESM (e.g. yaml, ajv).
|
|
40
|
+
const __bundleRealRequire = __bundleCreateRequire(import.meta.url);
|
|
41
|
+
`;
|
|
42
|
+
|
|
43
|
+
// Pattern to replace esbuild's broken __require shim with a real require().
|
|
44
|
+
const REQUIRE_SHIM_PATTERN = /var __require = \/\* @__PURE__ \*\/ \(\(x\) => typeof require !== "undefined" \? require : typeof Proxy !== "undefined" \? new Proxy\(x, \{[\s\S]*?\}\) : x\)\(function\(x\) \{[\s\S]*?\}\);/;
|
|
45
|
+
|
|
46
|
+
const REQUIRE_SHIM_REPLACEMENT = `var __require = __bundleRealRequire;`;
|
|
47
|
+
|
|
48
|
+
async function buildBundle() {
|
|
49
|
+
// Dynamic import so the script works even if esbuild is not yet installed.
|
|
50
|
+
let esbuild;
|
|
51
|
+
try {
|
|
52
|
+
esbuild = await import('esbuild');
|
|
53
|
+
} catch {
|
|
54
|
+
console.error('Error: esbuild not installed. Run: npm install');
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const result = await esbuild.build({
|
|
59
|
+
entryPoints: [ENTRY],
|
|
60
|
+
absWorkingDir: PKG_ROOT,
|
|
61
|
+
bundle: true,
|
|
62
|
+
format: 'esm',
|
|
63
|
+
platform: 'node',
|
|
64
|
+
target: 'node22',
|
|
65
|
+
outfile: OUTFILE,
|
|
66
|
+
banner: { js: BANNER },
|
|
67
|
+
// External: Node.js builtins, native addon loader, and the native addon itself.
|
|
68
|
+
external: [
|
|
69
|
+
'node:*',
|
|
70
|
+
'*/safe_write.node',
|
|
71
|
+
'*.node',
|
|
72
|
+
],
|
|
73
|
+
// Keep names for stack traces; deterministic across runs for same input.
|
|
74
|
+
keepNames: true,
|
|
75
|
+
// No minification — preserve readable output for debugging.
|
|
76
|
+
minify: false,
|
|
77
|
+
// Sourcemap not needed for production bundle.
|
|
78
|
+
sourcemap: false,
|
|
79
|
+
// Tree-shake unused code.
|
|
80
|
+
treeShaking: true,
|
|
81
|
+
// Write to outfile.
|
|
82
|
+
write: false,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
let content = result.outputFiles[0].text;
|
|
86
|
+
|
|
87
|
+
// Replace esbuild's broken __require shim with a real require().
|
|
88
|
+
if (REQUIRE_SHIM_PATTERN.test(content)) {
|
|
89
|
+
content = content.replace(REQUIRE_SHIM_PATTERN, REQUIRE_SHIM_REPLACEMENT);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Generated dependency comments may contain editor-authored trailing spaces.
|
|
93
|
+
// Normalize them so committed bundles pass repository whitespace checks.
|
|
94
|
+
content = content.replace(/[ \t]+$/gm, '');
|
|
95
|
+
|
|
96
|
+
return content;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async function main() {
|
|
100
|
+
const content = await buildBundle();
|
|
101
|
+
|
|
102
|
+
if (CHECK_MODE) {
|
|
103
|
+
let existing;
|
|
104
|
+
try {
|
|
105
|
+
existing = await readFile(OUTFILE, 'utf-8');
|
|
106
|
+
} catch {
|
|
107
|
+
console.error('Bundle drift: output file does not exist.');
|
|
108
|
+
process.exit(1);
|
|
109
|
+
}
|
|
110
|
+
if (existing !== content) {
|
|
111
|
+
console.error('Bundle drift: output differs from expected.');
|
|
112
|
+
const existingHash = createHash('sha256').update(existing).digest('hex');
|
|
113
|
+
const expectedHash = createHash('sha256').update(content).digest('hex');
|
|
114
|
+
console.error(` existing: sha256:${existingHash}`);
|
|
115
|
+
console.error(` expected: sha256:${expectedHash}`);
|
|
116
|
+
process.exit(1);
|
|
117
|
+
}
|
|
118
|
+
console.log('Bundle in sync.');
|
|
119
|
+
process.exit(0);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
await mkdir(dirname(OUTFILE), { recursive: true });
|
|
123
|
+
await writeFile(OUTFILE, content, 'utf-8');
|
|
124
|
+
const hash = createHash('sha256').update(content).digest('hex');
|
|
125
|
+
console.log(`Bundle written: ${OUTFILE}`);
|
|
126
|
+
console.log(` sha256:${hash}`);
|
|
127
|
+
console.log(` size: ${content.length} bytes`);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
main().catch((err) => {
|
|
131
|
+
console.error(`build-bundle failed: ${err.message}`);
|
|
132
|
+
process.exit(1);
|
|
133
|
+
});
|
|
@@ -23,16 +23,15 @@ description: Identify project topology and evaluate gaps in public documentation
|
|
|
23
23
|
|
|
24
24
|
## 正向执行路径
|
|
25
25
|
|
|
26
|
-
1.
|
|
27
|
-
2.
|
|
28
|
-
3.
|
|
29
|
-
4.
|
|
30
|
-
5. 若 `NEEDS_INPUT`,根据报告补充配置后重跑,使用最新输出作为唯一证据
|
|
26
|
+
1. 使用插件根相对路径运行 CLI:`node "${CLAUDE_PLUGIN_ROOT}/bin/release-skill.mjs" assess --root <path> --offline --json`
|
|
27
|
+
2. 检查 exit code:0 = 成功,非 0 = 根据错误码处理
|
|
28
|
+
3. 读取 JSON 报告中的 `status` 字段(`ASSESSED` / `NEEDS_INPUT` / `BLOCKED`)
|
|
29
|
+
4. 若 `NEEDS_INPUT`,根据报告补充配置后重跑,使用最新输出作为唯一证据
|
|
31
30
|
|
|
32
31
|
## 确定性脚本调用
|
|
33
32
|
|
|
34
33
|
```bash
|
|
35
|
-
"${
|
|
34
|
+
node "${CLAUDE_PLUGIN_ROOT}/bin/release-skill.mjs" assess --root <path> --offline --json
|
|
36
35
|
# 输出到文件: 加 --output <report-path>
|
|
37
36
|
```
|
|
38
37
|
|
|
@@ -23,25 +23,18 @@ description: "Discoverable entry point for release-skill: dependency and environ
|
|
|
23
23
|
|
|
24
24
|
## 正向执行路径
|
|
25
25
|
|
|
26
|
-
1.
|
|
27
|
-
2.
|
|
28
|
-
3.
|
|
29
|
-
4.
|
|
30
|
-
5. 默认在审阅本地计划和快照后停止;只有用户明确要求且完成摘要审批时才路由到 `release-publish`
|
|
26
|
+
1. 使用插件根相对路径运行 CLI:`node "${CLAUDE_PLUGIN_ROOT}/bin/release-skill.mjs" help --json`
|
|
27
|
+
2. 检查 `readiness.localPreparation`;需要生产发布时再检查 `readiness.productionPublish`
|
|
28
|
+
3. 若环境就绪且缺少 `.release-skill/project.yaml`,先路由 `release-setup`;配置已存在才运行 `release-assess`
|
|
29
|
+
4. 默认在审阅本地计划和快照后停止;只有用户明确要求且完成摘要审批时才路由到 `release-publish`
|
|
31
30
|
|
|
32
31
|
## 确定性脚本调用
|
|
33
32
|
|
|
34
33
|
```bash
|
|
35
|
-
#
|
|
36
|
-
release-skill help --json
|
|
37
|
-
release-skill setup --root <path> --json
|
|
38
|
-
release-skill assess --root <path> --offline --json
|
|
39
|
-
|
|
40
|
-
# 从源码 checkout 运行
|
|
41
|
-
RELEASE_SKILL_HOME=/path/to/release-skill
|
|
42
|
-
node "$RELEASE_SKILL_HOME/packages/release-skill/bin/release-skill.mjs" help --json
|
|
43
|
-
node "$RELEASE_SKILL_HOME/packages/release-skill/bin/release-skill.mjs" setup --root <path> --json
|
|
44
|
-
node "$RELEASE_SKILL_HOME/packages/release-skill/bin/release-skill.mjs" assess --root <path> --offline --json
|
|
34
|
+
# 从插件根运行(自包含 bundle,无需 node_modules)
|
|
35
|
+
node "${CLAUDE_PLUGIN_ROOT}/bin/release-skill.mjs" help --json
|
|
36
|
+
node "${CLAUDE_PLUGIN_ROOT}/bin/release-skill.mjs" setup --root <path> --json
|
|
37
|
+
node "${CLAUDE_PLUGIN_ROOT}/bin/release-skill.mjs" assess --root <path> --offline --json
|
|
45
38
|
```
|
|
46
39
|
|
|
47
40
|
## 故障路由
|
|
@@ -53,11 +46,11 @@ node "$RELEASE_SKILL_HOME/packages/release-skill/bin/release-skill.mjs" assess -
|
|
|
53
46
|
| pnpm 未安装 | 不影响本地准备;仅出现在 recommendations 中 |
|
|
54
47
|
| npm/gh 未安装 | 本地准备仍可就绪,但 `readiness.productionPublish.status` 为 `NOT_READY` |
|
|
55
48
|
| npm/gh 已安装 | 生产状态仍为 `AUTH_CHECK_REQUIRED`;发布前验证 `gh auth`、Git HTTPS credential 和 npm auth |
|
|
56
|
-
| CLI 入口不存在 |
|
|
49
|
+
| CLI 入口不存在 | 确认 `${CLAUDE_PLUGIN_ROOT}/bin/release-skill.mjs` 存在;不存在时重新安装插件 |
|
|
57
50
|
| 项目配置不存在 | 路由 `release-setup`,默认只读;不得直接生成或覆盖 README/配置 |
|
|
58
|
-
| assess 失败 | 运行 `node "$
|
|
51
|
+
| assess 失败 | 运行 `node "${CLAUDE_PLUGIN_ROOT}/bin/release-skill.mjs" assess --offline --json` 获取详情 |
|
|
59
52
|
| 请求生产发布 | 已有公开版本先调用 `release-prepare --online --production` 观察 bound 基线;人工审阅后再路由 `release-publish` |
|
|
60
53
|
|
|
61
54
|
## 后续引导
|
|
62
55
|
|
|
63
|
-
本地准备就绪后下一步运行 `release-assess
|
|
56
|
+
本地准备就绪后下一步运行 `release-assess`:`node "${CLAUDE_PLUGIN_ROOT}/bin/release-skill.mjs" assess`。生产发布还要求 npm、gh 可用,并在发布前另行完成认证检查。
|
|
@@ -25,8 +25,8 @@ description: Freeze an immutable release plan with local configuration, document
|
|
|
25
25
|
|
|
26
26
|
## 正向执行路径
|
|
27
27
|
|
|
28
|
-
1.
|
|
29
|
-
2. 运行
|
|
28
|
+
1. 使用插件根相对路径运行 CLI:`CLI="node ${CLAUDE_PLUGIN_ROOT}/bin/release-skill.mjs"`
|
|
29
|
+
2. 运行 `${CLI} prepare --root <path> --offline --json`
|
|
30
30
|
3. 若遇到 hook/gate 授权门失败,分别展示命令和风险,获取授权后只增加实际需要的 `--acknowledge-hook-side-effects` / `--acknowledge-gate-side-effects`
|
|
31
31
|
4. 检查 exit code 0,读取 JSON 返回的 immutable `planPath=plans/<planDigest>.json`,再从该文件读取 `status`、`units`、`externalActions`
|
|
32
32
|
5. 向用户展示 targetVersion、externalActions、planDigest 和 planPath;后续 approve/publish 只能使用该 immutable planPath,等待确认后再 approve
|
|
@@ -48,13 +48,13 @@ prepare 后若人工继续修改 README 或任何源文件,应保留修改并
|
|
|
48
48
|
## 确定性脚本调用
|
|
49
49
|
|
|
50
50
|
```bash
|
|
51
|
-
"${
|
|
51
|
+
node "${CLAUDE_PLUGIN_ROOT}/bin/release-skill.mjs" prepare --root <path> --offline --json
|
|
52
52
|
# 生产 happy end:bound 基线必须 online;远端目标唯一性仍由 publish 全局预检
|
|
53
|
-
"${
|
|
53
|
+
node "${CLAUDE_PLUGIN_ROOT}/bin/release-skill.mjs" prepare --root <path> --online --production --json
|
|
54
54
|
# 项目含 hook 时需显式授权:
|
|
55
|
-
"${
|
|
55
|
+
node "${CLAUDE_PLUGIN_ROOT}/bin/release-skill.mjs" prepare --root <path> --offline --acknowledge-hook-side-effects --json
|
|
56
56
|
# 项目含 snapshot gate 时另行显式授权:
|
|
57
|
-
"${
|
|
57
|
+
node "${CLAUDE_PLUGIN_ROOT}/bin/release-skill.mjs" prepare --root <path> --offline --acknowledge-gate-side-effects --json
|
|
58
58
|
```
|
|
59
59
|
|
|
60
60
|
## 执行顺序
|
|
@@ -31,13 +31,10 @@ description: 从已批准且摘要确认的生产计划发布冻结 Git branch/t
|
|
|
31
31
|
## 确定性执行
|
|
32
32
|
|
|
33
33
|
```bash
|
|
34
|
-
"${
|
|
34
|
+
node "${CLAUDE_PLUGIN_ROOT}/bin/release-skill.mjs" publish --root <path> --plan <plan-path> \
|
|
35
35
|
--approval <approval-path> --confirm-production <planDigest> --json
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
`CLI` 必须复用 `release-help` 已解析的入口:registry 已有受支持版本且 PATH 可用时
|
|
39
|
-
为 `CLI=(release-skill)`;否则为源码 checkout 的 node 数组。
|
|
40
|
-
|
|
41
38
|
执行顺序:全局只读预检 → 配置的公开分支(按三种 `branchStrategy` 执行)→ 必要时
|
|
42
39
|
单独切换默认分支 → tag → npm tarball →
|
|
43
40
|
GitHub Release → Claude/Codex marketplace 隔离安装。每步 execute 后立即 observe;
|
|
@@ -29,8 +29,8 @@ marketplace 隔离消费者 checkpoint,但只恢复到 `PUBLISHED`;最终 np
|
|
|
29
29
|
|
|
30
30
|
## 正向执行路径
|
|
31
31
|
|
|
32
|
-
1.
|
|
33
|
-
2. 运行 `"${
|
|
32
|
+
1. 使用插件根相对路径运行 CLI,确认有 `--run` 路径(必需),且源 run 状态为 `PARTIAL`
|
|
33
|
+
2. 运行 `node "${CLAUDE_PLUGIN_ROOT}/bin/release-skill.mjs" reconcile --root <path> --plan <plan-path> --run <run-path> --json`
|
|
34
34
|
3. 检查 exit code 和结构化状态:`PUBLISHED`(恢复完成,待 verify)/ `PARTIAL`(需重试)/ `BLOCKED`(需人工决策)
|
|
35
35
|
4. 若 PARTIAL 且需重试,加 `--approval`;生产计划还必须加 `--confirm-production <planDigest>`
|
|
36
36
|
|
|
@@ -38,11 +38,11 @@ marketplace 隔离消费者 checkpoint,但只恢复到 `PUBLISHED`;最终 np
|
|
|
38
38
|
|
|
39
39
|
```bash
|
|
40
40
|
# reconcile
|
|
41
|
-
"${
|
|
41
|
+
node "${CLAUDE_PLUGIN_ROOT}/bin/release-skill.mjs" reconcile --root <path> --plan <plan-path> --run <run-path> --json
|
|
42
42
|
# verify
|
|
43
|
-
"${
|
|
43
|
+
node "${CLAUDE_PLUGIN_ROOT}/bin/release-skill.mjs" verify --root <path> --plan <plan-path> --run <reconcile-run-path> --json
|
|
44
44
|
# 重试(需 --approval)
|
|
45
|
-
"${
|
|
45
|
+
node "${CLAUDE_PLUGIN_ROOT}/bin/release-skill.mjs" reconcile --root <path> --plan <plan-path> --run <run-path> --approval <approval-path> --confirm-production <planDigest> --json
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
## 幂等跳过逻辑
|
|
@@ -1,111 +1,95 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: release-setup
|
|
3
|
-
description: "首次接入 release-skill
|
|
3
|
+
description: "首次接入 release-skill:只读发现发布单元与个性化验证候选,机械提取提案,经人工确认 setupDigest 后仅首次创建配置"
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# release-setup
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## 适用场景
|
|
9
9
|
|
|
10
|
-
项目尚无 `.release-skill/project.yaml
|
|
10
|
+
项目尚无 `.release-skill/project.yaml`,或用户要求初始化、接入、校准发布规则时使用。配置已存在时只审计并路由到 `release-assess`,不得重新生成。
|
|
11
11
|
|
|
12
|
-
##
|
|
12
|
+
## 硬边界
|
|
13
13
|
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
- create-once
|
|
18
|
-
-
|
|
19
|
-
- 不猜测 `publicRepo`、tag、分支策略、前序公开基线、发行渠道或公开文件边界。无法唯一确定时保留 `NEEDS_INPUT`。
|
|
20
|
-
- 无 GitHub/npm 发布渠道时保留 `LOCAL_ONLY_DETECTED`;不得宣称 production-ready(生产就绪)。
|
|
14
|
+
- 默认只读。README、slogan、CHANGELOG、业务脚本和已有配置均为人工权威内容,不得重写或覆盖。
|
|
15
|
+
- 发现脚本不等于选择或授权。间接脚本以 `SIDE_EFFECTS_UNPROVEN` 排除;项目特有 hook/gate 只能人工增量注册。
|
|
16
|
+
- 仓库、公开文件等证据冲突时停止自动提案,交给人工修正权威事实后重新发现。
|
|
17
|
+
- 写入只允许 create-once(仅创建一次),必须同时提供 answers 与精确 `setupDigest`;无安全原生写入能力时失败关闭。
|
|
18
|
+
- Agent 的多次 shell 调用彼此独立;只能用首轮打印的会话目录绝对路径续接,不得假设变量仍存在。
|
|
21
19
|
|
|
22
|
-
##
|
|
20
|
+
## 首次接入
|
|
23
21
|
|
|
24
|
-
1.
|
|
25
|
-
2. 运行只读发现;`public-release.json` 仅作为旧配置迁移事实读取,其中的 `snapshotCommands` 只成为未授权候选:
|
|
22
|
+
1. 检查入口:
|
|
26
23
|
|
|
27
24
|
```bash
|
|
28
|
-
release-skill
|
|
25
|
+
node "${CLAUDE_PLUGIN_ROOT}/bin/release-skill.mjs" help --json
|
|
29
26
|
```
|
|
30
27
|
|
|
31
|
-
|
|
32
|
-
4. 与用户确认后创建一个人工审阅的 answers JSON:
|
|
33
|
-
|
|
34
|
-
```json
|
|
35
|
-
{
|
|
36
|
-
"projectConfig": {
|
|
37
|
-
"apiVersion": "release-skill/v1",
|
|
38
|
-
"kind": "ReleaseProject",
|
|
39
|
-
"project": { "name": "example-project", "defaultBranch": "main" },
|
|
40
|
-
"releaseUnits": [{
|
|
41
|
-
"id": "example-project",
|
|
42
|
-
"source": ".",
|
|
43
|
-
"publicRepo": "owner/example-project",
|
|
44
|
-
"version": { "source": "package.json", "tagTemplate": "v{version}" },
|
|
45
|
-
"distributions": [{
|
|
46
|
-
"type": "npm",
|
|
47
|
-
"package": "example-project",
|
|
48
|
-
"access": "public",
|
|
49
|
-
"provenance": false,
|
|
50
|
-
"tag": "latest",
|
|
51
|
-
"registry": "https://registry.npmjs.org",
|
|
52
|
-
"publisher": "owner"
|
|
53
|
-
}],
|
|
54
|
-
"publicFiles": [
|
|
55
|
-
{ "from": "README.md", "to": "README.md", "mode": "preserve" },
|
|
56
|
-
{ "from": "package.json", "to": "package.json", "mode": "preserve" }
|
|
57
|
-
],
|
|
58
|
-
"requiredPublicFiles": ["README.md", "package.json"],
|
|
59
|
-
"previousPublicBaseline": { "mode": "none" },
|
|
60
|
-
"production": {
|
|
61
|
-
"branchTemplate": "release/{tag}",
|
|
62
|
-
"branchStrategy": "create-release-branch"
|
|
63
|
-
}
|
|
64
|
-
}]
|
|
65
|
-
},
|
|
66
|
-
"selectedGateIds": []
|
|
67
|
-
}
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
示例只展示可进入生产 prepare 的完整 schema 形状,所有仓库、渠道、基线、分支策略和公开文件值都必须替换为本项目经人工确认的事实。`selectedGateIds` 必须与 `projectConfig.verificationGates[].id` 精确一致,并且每个 id 都必须来自本次 dry-run 的 `gateCandidates`。不要把未选择候选写入配置。
|
|
71
|
-
|
|
72
|
-
5. 带 answers 再运行 dry-run,得到绑定“当前项目事实 + 人工答案”的 `setupDigest`:
|
|
28
|
+
2. 只读发现并机械提取提案。完整报告仅写入临时会话目录;不要设置 `trap EXIT`,确认前必须保留会话文件:
|
|
73
29
|
|
|
74
30
|
```bash
|
|
75
|
-
|
|
31
|
+
set -eu
|
|
32
|
+
PROJECT=<项目绝对路径>
|
|
33
|
+
SETUP_SESSION="$(mktemp -d "${TMPDIR:-/tmp}/release-setup.XXXXXX")"
|
|
34
|
+
REPORT="$SETUP_SESSION/discovery.json"
|
|
35
|
+
ANSWERS="$SETUP_SESSION/answers.json"
|
|
36
|
+
printf 'SETUP_SESSION=%s\nPROJECT=%s\n' "$SETUP_SESSION" "$PROJECT"
|
|
37
|
+
set +e
|
|
38
|
+
node "${CLAUDE_PLUGIN_ROOT}/bin/release-skill.mjs" setup --root "$PROJECT" --json > "$REPORT"
|
|
39
|
+
SETUP_STATUS=$?
|
|
40
|
+
set -e
|
|
41
|
+
[ "$SETUP_STATUS" -eq 0 ] || [ "$SETUP_STATUS" -eq 2 ] || exit "$SETUP_STATUS"
|
|
42
|
+
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"
|
|
43
|
+
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"
|
|
76
44
|
```
|
|
77
45
|
|
|
78
|
-
|
|
46
|
+
若 `proposalConflicts` 非空,暂停,让用户修正仓库/映射权威事实,删除本会话目录后从第 2 步重跑,不得猜测选边。无冲突时可人工增量编辑 `answers.json`:hook 写入 `recommendedAnswers.projectConfig.hooks` 对应的 `projectConfig.hooks`;gate 写入 `verificationGates`,并把同一 id 加入 `selectedGateIds`。人工文件保持 `mode: preserve`,跨单元共享源使用 `sourceScope: workspace`。
|
|
47
|
+
|
|
48
|
+
3. 使用上一步打印的两个绝对字面量重新赋值,运行绑定 dry-run;任何人工编辑后都必须重跑本步:
|
|
79
49
|
|
|
80
50
|
```bash
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
51
|
+
set -eu
|
|
52
|
+
SETUP_SESSION=<上一步打印的会话目录绝对路径>
|
|
53
|
+
PROJECT=<上一步打印的项目绝对路径>
|
|
54
|
+
ANSWERS="$SETUP_SESSION/answers.json"
|
|
55
|
+
BOUND_REPORT="$SETUP_SESSION/bound.json"
|
|
56
|
+
node "${CLAUDE_PLUGIN_ROOT}/bin/release-skill.mjs" setup --root "$PROJECT" --answers "$ANSWERS" --json > "$BOUND_REPORT"
|
|
57
|
+
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"
|
|
58
|
+
printf 'SETUP_SESSION=%s\nPROJECT=%s\n' "$SETUP_SESSION" "$PROJECT"
|
|
86
59
|
```
|
|
87
60
|
|
|
88
|
-
|
|
61
|
+
只向用户展示绑定摘要、配置差异和精确 `setupDigest`,取得一次明确确认。
|
|
89
62
|
|
|
90
|
-
|
|
63
|
+
4. 确认后用原会话与已确认摘要首次创建。三个完整报告均重定向到文件,固定提取器成功后才清理会话目录:
|
|
91
64
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
65
|
+
```bash
|
|
66
|
+
set -eu
|
|
67
|
+
SETUP_SESSION=<已确认会话目录的绝对路径>
|
|
68
|
+
PROJECT=<已确认项目的绝对路径>
|
|
69
|
+
CONFIRMED_SETUP_DIGEST=<用户确认的精确 setupDigest>
|
|
70
|
+
ANSWERS="$SETUP_SESSION/answers.json"
|
|
71
|
+
CREATED_REPORT="$SETUP_SESSION/created.json"
|
|
72
|
+
POST_REPORT="$SETUP_SESSION/post-setup.json"
|
|
73
|
+
ASSESS_REPORT="$SETUP_SESSION/assess.json"
|
|
74
|
+
node "${CLAUDE_PLUGIN_ROOT}/bin/release-skill.mjs" setup --root "$PROJECT" --answers "$ANSWERS" --write --confirm-setup "$CONFIRMED_SETUP_DIGEST" --json > "$CREATED_REPORT"
|
|
75
|
+
node "${CLAUDE_PLUGIN_ROOT}/bin/release-skill.mjs" setup --root "$PROJECT" --json > "$POST_REPORT"
|
|
76
|
+
set +e
|
|
77
|
+
node "${CLAUDE_PLUGIN_ROOT}/bin/release-skill.mjs" assess --root "$PROJECT" --offline --json > "$ASSESS_REPORT"
|
|
78
|
+
ASSESS_EXIT=$?
|
|
79
|
+
set -e
|
|
80
|
+
[ "$ASSESS_EXIT" -eq 0 ] || [ "$ASSESS_EXIT" -eq 1 ] || exit "$ASSESS_EXIT"
|
|
81
|
+
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"){console.error("setup lifecycle verification failed");process.exit(2)}if(!["ASSESSED","NEEDS_INPUT","BLOCKED"].includes(a.status)){console.error("assessment report invalid");process.exit(2)}const blocking=(a.gaps??[]).filter(g=>g.severity==="error").map(({code,scope,message})=>({code,scope,message}));process.stdout.write(JSON.stringify({created:{status:c.status,compactSummary:c.compactSummary},postSetup:{status:p.status,compactSummary:p.compactSummary},assessment:{status:a.status,summary:a.summary,gapCount:(a.gaps??[]).length,blockingGaps:blocking}},null,2)+"\n")' "$CREATED_REPORT" "$POST_REPORT" "$ASSESS_REPORT"
|
|
82
|
+
node -e 'require("node:fs").rmSync(process.argv[1],{recursive:true,force:false})' "$SETUP_SESSION"
|
|
83
|
+
```
|
|
97
84
|
|
|
98
85
|
## 故障路由
|
|
99
86
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
| `SETUP_DIGEST_MISMATCH` | 项目事实或 answers 已变化;重新 dry-run、审阅并确认新摘要 |
|
|
106
|
-
| `CONFIG_INVALID` | 修复 answers 中完整 `projectConfig`,再 dry-run |
|
|
107
|
-
| `SAFE_WRITE_UNAVAILABLE` | 保留只读报告,由人工首次创建经审阅的配置;不得覆盖已有文件或启用普通路径兜底 |
|
|
87
|
+
- `NEEDS_INPUT`:审阅紧凑摘要;有冲突先修正权威事实并重跑。
|
|
88
|
+
- `LOCAL_ONLY_DETECTED`:只能建立本地配置,由用户决定是否创建远端渠道。
|
|
89
|
+
- `ALREADY_CONFIGURED` / `CONFIG_EXISTS`:不覆盖,转 `release-assess`。
|
|
90
|
+
- `SETUP_DIGEST_MISMATCH`:事实或 answers 已变化,重新只读发现与确认。
|
|
91
|
+
- `SAFE_WRITE_UNAVAILABLE`:保留只读报告,不启用普通路径写入兜底。
|
|
108
92
|
|
|
109
93
|
## 完成标准
|
|
110
94
|
|
|
111
|
-
|
|
95
|
+
完整报告未进入 Agent 上下文;跨 shell 只靠显式会话路径续接;无冲突提案由机器机械提取;写入仅创建一次且摘要精确匹配;创建后状态和 assess 只输出紧凑结果;人工文件保持原字节。
|
|
@@ -28,20 +28,17 @@ verify 只接受 `PUBLISHED` 状态的源 run;`VERIFIED` 是终态,不会再
|
|
|
28
28
|
## 正向执行路径
|
|
29
29
|
|
|
30
30
|
1. 确认有 `--run` 路径(必需),且源 run 状态为 PUBLISHED
|
|
31
|
-
2.
|
|
31
|
+
2. 使用插件根相对路径运行 CLI;若存在 consumer gate 或 npm `smokeBin`,先逐项审阅并增加 `--acknowledge-gate-side-effects`
|
|
32
32
|
3. 检查 exit code 和结构化状态:`VERIFIED`(全部通过)/ 失败(具体错误)
|
|
33
33
|
4. 只有 `VERIFIED` 才是 happy end
|
|
34
34
|
|
|
35
35
|
## 确定性脚本调用
|
|
36
36
|
|
|
37
37
|
```bash
|
|
38
|
-
#
|
|
39
|
-
"${
|
|
38
|
+
# 从插件根运行
|
|
39
|
+
node "${CLAUDE_PLUGIN_ROOT}/bin/release-skill.mjs" verify --root <path> --plan <plan-path> --run <run-path> --json
|
|
40
40
|
# 计划含 consumer gate 或 smokeBin 时:
|
|
41
|
-
"${
|
|
42
|
-
|
|
43
|
-
# 从源码运行
|
|
44
|
-
node "$RELEASE_SKILL_HOME/packages/release-skill/bin/release-skill.mjs" verify --root <path> --plan <plan-path> --run <run-path> --json
|
|
41
|
+
node "${CLAUDE_PLUGIN_ROOT}/bin/release-skill.mjs" verify --root <path> --plan <plan-path> --run <run-path> --acknowledge-gate-side-effects --json
|
|
45
42
|
```
|
|
46
43
|
|
|
47
44
|
## 验证步骤
|