release-skill 0.1.9 → 0.1.10
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/.kimi-plugin/plugin.json +1 -1
- package/CHANGELOG.md +34 -0
- package/INSTALL.md +4 -4
- package/INSTALL.zh-CN.md +4 -4
- package/README.md +28 -28
- package/README.zh-CN.md +21 -19
- 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 +23 -5
- package/adapters/codex/.codex-plugin/plugin.json +2 -2
- package/adapters/codex/bin/release-skill.bundle.mjs +23 -5
- package/adapters/kimi/.kimi-plugin/plugin.json +1 -1
- package/adapters/kimi/bin/release-skill.bundle.mjs +23 -5
- package/bin/release-skill.bundle.mjs +23 -5
- package/package.json +1 -1
- package/src/adapters/plugin-marketplace.mjs +10 -4
- package/src/core/baseline.mjs +11 -0
- package/src/snapshot/frozen.mjs +29 -5
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "release-skill",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.10",
|
|
4
4
|
"description": "Safe preparation and frozen GitHub/npm production publishing with full happy end verification",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "广州市风荷科技有限公司"
|
|
@@ -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.10.",
|
|
23
23
|
"Help me understand the release workflow."
|
|
24
24
|
]
|
|
25
25
|
}
|
package/.kimi-plugin/plugin.json
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
<!-- release-skill:changelog:start version=0.1.10 locale=en baseline=sha256:ec4dbf3f44f1295d9af20e0fbf1ced4341d9b65d0c93598104e228244e33fa2b -->
|
|
4
|
+
## [0.1.10] - 2026-07-24
|
|
5
|
+
|
|
6
|
+
v0.1.10 fixes the codex marketplace install verification failure caused by the codex CLI materializing a `.codex-plugin/migrated-command-skills/` subtree (commands migrated to skill format) in the plugin install root at install time. That consumer-owned transport metadata is now exempted alongside the root `.git` checkout, and the frozen snapshot exclusion list supports multi-segment relative path prefixes while single-segment root-only behavior is unchanged. The sealed snapshot digest, release plan schema, and prepare-side freezing are unchanged, so already-frozen plans reconcile without re-approval. The npm package name (`release-skill`), publishing identity (`publisher: mzdbxqh`), public repository (`ifoohoo/release-skill`), and corporate maintainer remain unchanged.
|
|
7
|
+
|
|
8
|
+
### Fixed
|
|
9
|
+
|
|
10
|
+
- **Codex `migrated-command-skills` transport exemption**: the codex CLI
|
|
11
|
+
converts plugin `commands/` into skill format at install time and writes the
|
|
12
|
+
result under `.codex-plugin/migrated-command-skills/` in the install root.
|
|
13
|
+
That consumer-owned subtree is not part of the published payload, so the
|
|
14
|
+
whole-tree comparison failed every real codex marketplace install; the
|
|
15
|
+
codex consumer transport exemptions widen from `['.git']` to
|
|
16
|
+
`['.git', '.codex-plugin/migrated-command-skills']`. Claude (`.in_use`) and
|
|
17
|
+
Kimi (`.git`) exemptions are unchanged, and the exemption deliberately
|
|
18
|
+
never widens to `.codex-plugin/*` or arbitrary extra files. Verified
|
|
19
|
+
against a real flow-architect install: the installed tree is byte-identical
|
|
20
|
+
to the frozen snapshot except for the migrated-command-skills directory.
|
|
21
|
+
Already-frozen plans reconcile unchanged because the sealed digest, plan
|
|
22
|
+
schema, and prepare-side freezing are untouched.
|
|
23
|
+
- **Multi-segment snapshot exclusions, fail-closed**:
|
|
24
|
+
`computeFrozenSnapshot`'s `excludeRootEntries` now accepts multi-segment
|
|
25
|
+
relative path prefixes naming an exact excluded subtree (required for the
|
|
26
|
+
`.codex-plugin/migrated-command-skills` exemption); single-segment entries
|
|
27
|
+
keep the historical root-only matching. Malformed entries (non-string,
|
|
28
|
+
absolute, `..`, backslash) fail closed: a bad exclusion list is a caller
|
|
29
|
+
bug, not transport metadata.
|
|
30
|
+
- **Regression coverage**: new protocol-level tests cover the root-layout
|
|
31
|
+
codex execute→observe→verify cycle with the CLI-generated
|
|
32
|
+
migrated-command-skills tree present, including byte-tamper and extra-file
|
|
33
|
+
negatives that must still fail closed.
|
|
34
|
+
<!-- release-skill:changelog:end version=0.1.10 locale=en -->
|
|
35
|
+
|
|
36
|
+
|
|
3
37
|
<!-- release-skill:changelog:start version=0.1.9 locale=en baseline=sha256:409f940c03e2d6fd41d33659b246b3d4b622918b4ac5a3a711d83aa09740ef11 -->
|
|
4
38
|
## [0.1.9] - 2026-07-23
|
|
5
39
|
|
package/INSTALL.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[简体中文](INSTALL.zh-CN.md)
|
|
4
4
|
|
|
5
|
-
<!-- release-skill:release-version: 0.1.
|
|
5
|
+
<!-- release-skill:release-version: 0.1.10 -->
|
|
6
6
|
## Prerequisites
|
|
7
7
|
|
|
8
8
|
- Node.js 22.0.0 or later
|
|
@@ -68,7 +68,7 @@ as a version-pinned **manual** install plus trusted observation/attestation:
|
|
|
68
68
|
default branch), confirm the trust prompt, then reload:
|
|
69
69
|
|
|
70
70
|
```
|
|
71
|
-
/plugins install https://github.com/ifoohoo/release-skill/releases/tag/release-skill-v0.1.
|
|
71
|
+
/plugins install https://github.com/ifoohoo/release-skill/releases/tag/release-skill-v0.1.10
|
|
72
72
|
/plugins reload
|
|
73
73
|
```
|
|
74
74
|
|
|
@@ -83,10 +83,10 @@ as a version-pinned **manual** install plus trusted observation/attestation:
|
|
|
83
83
|
{
|
|
84
84
|
"consumer": "kimi",
|
|
85
85
|
"plugin": "release-skill",
|
|
86
|
-
"version": "0.1.
|
|
86
|
+
"version": "0.1.10",
|
|
87
87
|
"entrySkill": "release-help",
|
|
88
88
|
"repo": "ifoohoo/release-skill",
|
|
89
|
-
"ref": "release-skill-v0.1.
|
|
89
|
+
"ref": "release-skill-v0.1.10",
|
|
90
90
|
"installPath": "<kimiCodeHome>/plugins/managed/release-skill",
|
|
91
91
|
"planDigest": "<64-hex frozen plan digest>",
|
|
92
92
|
"payloadDigest": "<64-hex frozen snapshot payload digest>",
|
package/INSTALL.zh-CN.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[English](INSTALL.md)
|
|
4
4
|
|
|
5
|
-
<!-- release-skill:release-version: 0.1.
|
|
5
|
+
<!-- release-skill:release-version: 0.1.10 -->
|
|
6
6
|
## 前置条件
|
|
7
7
|
|
|
8
8
|
- Node.js 22.0.0 或更高版本
|
|
@@ -62,7 +62,7 @@ release-skill 把 Kimi 安装建模为“版本钉死的手动安装 + 可信观
|
|
|
62
62
|
它会安装最新 release 或默认分支),确认信任提示后重新加载:
|
|
63
63
|
|
|
64
64
|
```
|
|
65
|
-
/plugins install https://github.com/ifoohoo/release-skill/releases/tag/release-skill-v0.1.
|
|
65
|
+
/plugins install https://github.com/ifoohoo/release-skill/releases/tag/release-skill-v0.1.10
|
|
66
66
|
/plugins reload
|
|
67
67
|
```
|
|
68
68
|
|
|
@@ -76,10 +76,10 @@ release-skill 把 Kimi 安装建模为“版本钉死的手动安装 + 可信观
|
|
|
76
76
|
{
|
|
77
77
|
"consumer": "kimi",
|
|
78
78
|
"plugin": "release-skill",
|
|
79
|
-
"version": "0.1.
|
|
79
|
+
"version": "0.1.10",
|
|
80
80
|
"entrySkill": "release-help",
|
|
81
81
|
"repo": "ifoohoo/release-skill",
|
|
82
|
-
"ref": "release-skill-v0.1.
|
|
82
|
+
"ref": "release-skill-v0.1.10",
|
|
83
83
|
"installPath": "<kimiCodeHome>/plugins/managed/release-skill",
|
|
84
84
|
"planDigest": "<64 位十六进制冻结计划摘要>",
|
|
85
85
|
"payloadDigest": "<64 位十六进制冻结快照载荷摘要>",
|
package/README.md
CHANGED
|
@@ -2,7 +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
|
+
<!-- release-skill:release-version: 0.1.10 -->
|
|
6
6
|
Release preparation for Claude Code, Codex, and Kimi Code, with human-edited files kept intact.
|
|
7
7
|
|
|
8
8
|
release-skill helps a maintainer answer three questions: what will be released,
|
|
@@ -11,41 +11,41 @@ reviewed artifacts first and publishes those same artifacts later; it does not
|
|
|
11
11
|
regenerate a README or re-pack the live workspace at the last step.
|
|
12
12
|
|
|
13
13
|
<!-- release-skill:managed:start id=latest-release -->
|
|
14
|
-
**0.1.
|
|
14
|
+
**0.1.10** (2026-07-24)
|
|
15
15
|
|
|
16
|
-
v0.1.
|
|
16
|
+
v0.1.10 fixes the codex marketplace install verification failure caused by the codex CLI materializing a `.codex-plugin/migrated-command-skills/` subtree (commands migrated to skill format) in the plugin install root at install time. That consumer-owned transport metadata is now exempted alongside the root `.git` checkout, and the frozen snapshot exclusion list supports multi-segment relative path prefixes while single-segment root-only behavior is unchanged. The sealed snapshot digest, release plan schema, and prepare-side freezing are unchanged, so already-frozen plans reconcile without re-approval. The npm package name (`release-skill`), publishing identity (`publisher: mzdbxqh`), public repository (`ifoohoo/release-skill`), and corporate maintainer remain unchanged.
|
|
17
17
|
|
|
18
18
|
**Fixed**
|
|
19
19
|
|
|
20
|
-
- **
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
20
|
+
- **Codex `migrated-command-skills` transport exemption**: the codex CLI
|
|
21
|
+
converts plugin `commands/` into skill format at install time and writes the
|
|
22
|
+
result under `.codex-plugin/migrated-command-skills/` in the install root.
|
|
23
|
+
That consumer-owned subtree is not part of the published payload, so the
|
|
24
|
+
whole-tree comparison failed every real codex marketplace install; the
|
|
25
|
+
codex consumer transport exemptions widen from `['.git']` to
|
|
26
|
+
`['.git', '.codex-plugin/migrated-command-skills']`. Claude (`.in_use`) and
|
|
27
|
+
Kimi (`.git`) exemptions are unchanged, and the exemption deliberately
|
|
28
|
+
never widens to `.codex-plugin/*` or arbitrary extra files. Verified
|
|
29
|
+
against a real flow-architect install: the installed tree is byte-identical
|
|
30
|
+
to the frozen snapshot except for the migrated-command-skills directory.
|
|
31
|
+
Already-frozen plans reconcile unchanged because the sealed digest, plan
|
|
30
32
|
schema, and prepare-side freezing are untouched.
|
|
31
|
-
- **
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
exemption
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
- **Regression coverage**: new protocol-level
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
name, empty source projection), root-layout claude with `.in_use`, and a
|
|
43
|
-
codex subdirectory variant.
|
|
33
|
+
- **Multi-segment snapshot exclusions, fail-closed**:
|
|
34
|
+
`computeFrozenSnapshot`'s `excludeRootEntries` now accepts multi-segment
|
|
35
|
+
relative path prefixes naming an exact excluded subtree (required for the
|
|
36
|
+
`.codex-plugin/migrated-command-skills` exemption); single-segment entries
|
|
37
|
+
keep the historical root-only matching. Malformed entries (non-string,
|
|
38
|
+
absolute, `..`, backslash) fail closed: a bad exclusion list is a caller
|
|
39
|
+
bug, not transport metadata.
|
|
40
|
+
- **Regression coverage**: new protocol-level tests cover the root-layout
|
|
41
|
+
codex execute→observe→verify cycle with the CLI-generated
|
|
42
|
+
migrated-command-skills tree present, including byte-tamper and extra-file
|
|
43
|
+
negatives that must still fail closed.
|
|
44
44
|
<!-- release-skill:managed:end id=latest-release -->
|
|
45
45
|
|
|
46
46
|
<!-- release-skill:capability:external-write-boundary -->
|
|
47
|
-
> **Current boundary:** v0.1.
|
|
48
|
-
> published status before the
|
|
47
|
+
> **Current boundary:** v0.1.10 is the current release (v0.1.9 previously held
|
|
48
|
+
> published status before the codex migrated-command-skills fix was added).
|
|
49
49
|
> v0.1.1 completed a real production release to GitHub and npm — the first
|
|
50
50
|
> production-verified milestone — followed by
|
|
51
51
|
> exact npm installation and Claude/Codex consumer installation verification
|
package/README.zh-CN.md
CHANGED
|
@@ -2,37 +2,39 @@
|
|
|
2
2
|
|
|
3
3
|
[English](README.md) · 安装指南:[中文](INSTALL.zh-CN.md) / [English](INSTALL.md)
|
|
4
4
|
|
|
5
|
-
<!-- release-skill:release-version: 0.1.
|
|
5
|
+
<!-- release-skill:release-version: 0.1.10 -->
|
|
6
6
|
面向 Claude Code、Codex 和 Kimi Code 的发布准备工具,完整保留人工维护的文件内容。
|
|
7
7
|
|
|
8
8
|
release-skill 帮助维护者回答三个问题:准备发布什么、还有哪些检查未通过、最终发布的内容是什么。它先冻结并供人工审阅,再从同一份冻结产物发布,不会在最后一步重新生成 README、重新打包当前工作区或覆盖人工内容。
|
|
9
9
|
|
|
10
10
|
<!-- release-skill:managed:start id=latest-release -->
|
|
11
|
-
**0.1.
|
|
11
|
+
**0.1.10** (2026-07-24)
|
|
12
12
|
|
|
13
|
-
v0.1.
|
|
13
|
+
v0.1.10 修复 codex marketplace 安装校验失败:codex CLI 安装时会在插件安装根目录生成 `.codex-plugin/migrated-command-skills/` 子树(commands 迁移为 skill 格式的产物)。这部分消费者所有的传输元数据现在与根目录 `.git` 检出一样获得豁免;冻结快照排除清单扩展支持多段相对路径前缀,单段行为保持不变。密封快照摘要、发布计划 schema 与 prepare 冻结均未改动,已冻结计划无需重新审批即可 reconcile。npm 包名(`release-skill`)、发布身份(`publisher: mzdbxqh`)、公开仓库(`ifoohoo/release-skill`)与公司维护主体保持不变。
|
|
14
14
|
|
|
15
15
|
**修复**
|
|
16
16
|
|
|
17
|
-
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
17
|
+
- **Codex `migrated-command-skills` 传输豁免**:codex CLI 安装时会把插件
|
|
18
|
+
`commands/` 转换为 skill 格式并写入安装根目录的
|
|
19
|
+
`.codex-plugin/migrated-command-skills/`。该消费者所有的子树不属于已发布
|
|
20
|
+
载荷,导致整树比较在每次真实 codex marketplace 安装中失败;codex 消费者
|
|
21
|
+
传输豁免从 `['.git']` 扩为 `['.git', '.codex-plugin/migrated-command-skills']`。
|
|
22
|
+
Claude(`.in_use`)与 Kimi(`.git`)豁免不变,且豁免刻意不扩大为
|
|
23
|
+
`.codex-plugin/*` 或任意多余文件。flow-architect 真实安装实测验证:除
|
|
24
|
+
migrated-command-skills 目录外,安装内容与冻结快照逐字节一致。密封摘要、
|
|
25
|
+
计划 schema 与 prepare 冻结均未改动,已冻结计划可以不变地 reconcile 收口。
|
|
26
|
+
- **多段快照排除,失败关闭**:`computeFrozenSnapshot` 的
|
|
27
|
+
`excludeRootEntries` 现在接受多段相对路径前缀,命名一个精确排除的子树
|
|
28
|
+
(`.codex-plugin/migrated-command-skills` 豁免所必需);单段条目保持历史
|
|
29
|
+
的根直接子项匹配。畸形条目(非字符串、绝对路径、`..`、反斜杠)失败关闭:
|
|
30
|
+
错误的排除清单是调用方 bug,不是传输元数据。
|
|
31
|
+
- **回归覆盖**:新增协议级测试覆盖带 CLI 生成 migrated-command-skills 树的
|
|
32
|
+
根布局 codex execute→observe→verify 完整链路,包含必须仍然失败关闭的字节
|
|
33
|
+
篡改与多余文件负例。
|
|
32
34
|
<!-- release-skill:managed:end id=latest-release -->
|
|
33
35
|
|
|
34
36
|
<!-- release-skill:capability:external-write-boundary -->
|
|
35
|
-
> **当前边界:** v0.1.
|
|
37
|
+
> **当前边界:** v0.1.10 是当前发布版本(v0.1.9 曾处于已发布、待独立验证状态)。
|
|
36
38
|
> v0.1.1 已完成 GitHub 与 npm 的
|
|
37
39
|
> 真实生产发布,是首次生产验证的历史里程碑,并从冻结 Git ref 完成精确 npm
|
|
38
40
|
> 安装及 Claude/Codex 消费者安装验证;“当前发布版本”与“首次生产验证里程碑”
|
|
@@ -9,7 +9,7 @@ const __bundlePkgRoot = __bundleResolve(__bundleDirname(__bundleFileURLToPath(im
|
|
|
9
9
|
// Provide a real require() for CJS packages bundled into ESM (e.g. yaml, ajv).
|
|
10
10
|
const __bundleRealRequire = __bundleCreateRequire(import.meta.url);
|
|
11
11
|
// Package identity injected at build time — closure-independent --version probe.
|
|
12
|
-
const __bundlePkg = Object.freeze({"name":"release-skill","version":"0.1.
|
|
12
|
+
const __bundlePkg = Object.freeze({"name":"release-skill","version":"0.1.10"});
|
|
13
13
|
|
|
14
14
|
var __create = Object.create;
|
|
15
15
|
var __defProp = Object.defineProperty;
|
|
@@ -17816,7 +17816,8 @@ var init_baseline = __esm({
|
|
|
17816
17816
|
".release-skill/lock",
|
|
17817
17817
|
".release-skill/lock-audit",
|
|
17818
17818
|
".release-skill/runs",
|
|
17819
|
-
".release-skill/transactions"
|
|
17819
|
+
".release-skill/transactions",
|
|
17820
|
+
".release-skill/kimi-attestations"
|
|
17820
17821
|
];
|
|
17821
17822
|
RESERVED_CONTROL_PREFIXES = [
|
|
17822
17823
|
...CONTROL_PLANE_PREFIXES,
|
|
@@ -19013,14 +19014,30 @@ async function computeFrozenSnapshot(snapshotDir, { excludeRootEntries = [] } =
|
|
|
19013
19014
|
throw frozenError("frozen snapshot root must be a real directory");
|
|
19014
19015
|
}
|
|
19015
19016
|
const entries = [];
|
|
19016
|
-
const
|
|
19017
|
+
const excludedRootNames = /* @__PURE__ */ new Set();
|
|
19018
|
+
const excludedPathPrefixes = [];
|
|
19019
|
+
for (const entry of excludeRootEntries) {
|
|
19020
|
+
if (typeof entry !== "string") {
|
|
19021
|
+
throw frozenError("frozen snapshot exclusion entries must be strings");
|
|
19022
|
+
}
|
|
19023
|
+
const segments = entry.split("/").filter((segment) => segment !== "" && segment !== ".");
|
|
19024
|
+
if (segments.length === 0 || entry.startsWith("/") || entry.includes("\\") || segments.some((segment) => segment === "..")) {
|
|
19025
|
+
throw frozenError(`frozen snapshot exclusion entry is not a safe relative path: ${JSON.stringify(entry)}`);
|
|
19026
|
+
}
|
|
19027
|
+
if (segments.length === 1) {
|
|
19028
|
+
excludedRootNames.add(segments[0]);
|
|
19029
|
+
} else {
|
|
19030
|
+
excludedPathPrefixes.push(segments.join("/"));
|
|
19031
|
+
}
|
|
19032
|
+
}
|
|
19017
19033
|
async function walk(dir) {
|
|
19018
19034
|
const children = await readdir3(dir, { withFileTypes: true });
|
|
19019
19035
|
children.sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
19020
19036
|
for (const child of children) {
|
|
19021
|
-
if (dir === root &&
|
|
19037
|
+
if (dir === root && excludedRootNames.has(child.name)) continue;
|
|
19022
19038
|
const absolute = join3(dir, child.name);
|
|
19023
19039
|
const rel = relative7(root, absolute).split("\\").join("/");
|
|
19040
|
+
if (excludedPathPrefixes.some((prefix) => rel === prefix || rel.startsWith(`${prefix}/`))) continue;
|
|
19024
19041
|
const st = await lstat5(absolute);
|
|
19025
19042
|
if (st.isSymbolicLink()) {
|
|
19026
19043
|
throw frozenError(`frozen snapshot contains symlink: ${rel}`);
|
|
@@ -76932,7 +76949,8 @@ function transportPayload(entries) {
|
|
|
76932
76949
|
}
|
|
76933
76950
|
function consumerTransportExclusions(consumer) {
|
|
76934
76951
|
if (consumer === "claude") return [".in_use"];
|
|
76935
|
-
if (consumer === "codex"
|
|
76952
|
+
if (consumer === "codex") return [".git", ".codex-plugin/migrated-command-skills"];
|
|
76953
|
+
if (consumer === "kimi") return [".git"];
|
|
76936
76954
|
return [];
|
|
76937
76955
|
}
|
|
76938
76956
|
function extractDeclaredPluginSource(consumer, entry) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "release-skill",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.10",
|
|
4
4
|
"description": "Safe preparation and frozen GitHub/npm production publishing with full happy end verification",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "广州市风荷科技有限公司"
|
|
@@ -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.10.",
|
|
23
23
|
"Help me understand the release workflow."
|
|
24
24
|
]
|
|
25
25
|
}
|
|
@@ -9,7 +9,7 @@ const __bundlePkgRoot = __bundleResolve(__bundleDirname(__bundleFileURLToPath(im
|
|
|
9
9
|
// Provide a real require() for CJS packages bundled into ESM (e.g. yaml, ajv).
|
|
10
10
|
const __bundleRealRequire = __bundleCreateRequire(import.meta.url);
|
|
11
11
|
// Package identity injected at build time — closure-independent --version probe.
|
|
12
|
-
const __bundlePkg = Object.freeze({"name":"release-skill","version":"0.1.
|
|
12
|
+
const __bundlePkg = Object.freeze({"name":"release-skill","version":"0.1.10"});
|
|
13
13
|
|
|
14
14
|
var __create = Object.create;
|
|
15
15
|
var __defProp = Object.defineProperty;
|
|
@@ -17816,7 +17816,8 @@ var init_baseline = __esm({
|
|
|
17816
17816
|
".release-skill/lock",
|
|
17817
17817
|
".release-skill/lock-audit",
|
|
17818
17818
|
".release-skill/runs",
|
|
17819
|
-
".release-skill/transactions"
|
|
17819
|
+
".release-skill/transactions",
|
|
17820
|
+
".release-skill/kimi-attestations"
|
|
17820
17821
|
];
|
|
17821
17822
|
RESERVED_CONTROL_PREFIXES = [
|
|
17822
17823
|
...CONTROL_PLANE_PREFIXES,
|
|
@@ -19013,14 +19014,30 @@ async function computeFrozenSnapshot(snapshotDir, { excludeRootEntries = [] } =
|
|
|
19013
19014
|
throw frozenError("frozen snapshot root must be a real directory");
|
|
19014
19015
|
}
|
|
19015
19016
|
const entries = [];
|
|
19016
|
-
const
|
|
19017
|
+
const excludedRootNames = /* @__PURE__ */ new Set();
|
|
19018
|
+
const excludedPathPrefixes = [];
|
|
19019
|
+
for (const entry of excludeRootEntries) {
|
|
19020
|
+
if (typeof entry !== "string") {
|
|
19021
|
+
throw frozenError("frozen snapshot exclusion entries must be strings");
|
|
19022
|
+
}
|
|
19023
|
+
const segments = entry.split("/").filter((segment) => segment !== "" && segment !== ".");
|
|
19024
|
+
if (segments.length === 0 || entry.startsWith("/") || entry.includes("\\") || segments.some((segment) => segment === "..")) {
|
|
19025
|
+
throw frozenError(`frozen snapshot exclusion entry is not a safe relative path: ${JSON.stringify(entry)}`);
|
|
19026
|
+
}
|
|
19027
|
+
if (segments.length === 1) {
|
|
19028
|
+
excludedRootNames.add(segments[0]);
|
|
19029
|
+
} else {
|
|
19030
|
+
excludedPathPrefixes.push(segments.join("/"));
|
|
19031
|
+
}
|
|
19032
|
+
}
|
|
19017
19033
|
async function walk(dir) {
|
|
19018
19034
|
const children = await readdir3(dir, { withFileTypes: true });
|
|
19019
19035
|
children.sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
19020
19036
|
for (const child of children) {
|
|
19021
|
-
if (dir === root &&
|
|
19037
|
+
if (dir === root && excludedRootNames.has(child.name)) continue;
|
|
19022
19038
|
const absolute = join3(dir, child.name);
|
|
19023
19039
|
const rel = relative7(root, absolute).split("\\").join("/");
|
|
19040
|
+
if (excludedPathPrefixes.some((prefix) => rel === prefix || rel.startsWith(`${prefix}/`))) continue;
|
|
19024
19041
|
const st = await lstat5(absolute);
|
|
19025
19042
|
if (st.isSymbolicLink()) {
|
|
19026
19043
|
throw frozenError(`frozen snapshot contains symlink: ${rel}`);
|
|
@@ -76932,7 +76949,8 @@ function transportPayload(entries) {
|
|
|
76932
76949
|
}
|
|
76933
76950
|
function consumerTransportExclusions(consumer) {
|
|
76934
76951
|
if (consumer === "claude") return [".in_use"];
|
|
76935
|
-
if (consumer === "codex"
|
|
76952
|
+
if (consumer === "codex") return [".git", ".codex-plugin/migrated-command-skills"];
|
|
76953
|
+
if (consumer === "kimi") return [".git"];
|
|
76936
76954
|
return [];
|
|
76937
76955
|
}
|
|
76938
76956
|
function extractDeclaredPluginSource(consumer, entry) {
|
|
@@ -9,7 +9,7 @@ const __bundlePkgRoot = __bundleResolve(__bundleDirname(__bundleFileURLToPath(im
|
|
|
9
9
|
// Provide a real require() for CJS packages bundled into ESM (e.g. yaml, ajv).
|
|
10
10
|
const __bundleRealRequire = __bundleCreateRequire(import.meta.url);
|
|
11
11
|
// Package identity injected at build time — closure-independent --version probe.
|
|
12
|
-
const __bundlePkg = Object.freeze({"name":"release-skill","version":"0.1.
|
|
12
|
+
const __bundlePkg = Object.freeze({"name":"release-skill","version":"0.1.10"});
|
|
13
13
|
|
|
14
14
|
var __create = Object.create;
|
|
15
15
|
var __defProp = Object.defineProperty;
|
|
@@ -17816,7 +17816,8 @@ var init_baseline = __esm({
|
|
|
17816
17816
|
".release-skill/lock",
|
|
17817
17817
|
".release-skill/lock-audit",
|
|
17818
17818
|
".release-skill/runs",
|
|
17819
|
-
".release-skill/transactions"
|
|
17819
|
+
".release-skill/transactions",
|
|
17820
|
+
".release-skill/kimi-attestations"
|
|
17820
17821
|
];
|
|
17821
17822
|
RESERVED_CONTROL_PREFIXES = [
|
|
17822
17823
|
...CONTROL_PLANE_PREFIXES,
|
|
@@ -19013,14 +19014,30 @@ async function computeFrozenSnapshot(snapshotDir, { excludeRootEntries = [] } =
|
|
|
19013
19014
|
throw frozenError("frozen snapshot root must be a real directory");
|
|
19014
19015
|
}
|
|
19015
19016
|
const entries = [];
|
|
19016
|
-
const
|
|
19017
|
+
const excludedRootNames = /* @__PURE__ */ new Set();
|
|
19018
|
+
const excludedPathPrefixes = [];
|
|
19019
|
+
for (const entry of excludeRootEntries) {
|
|
19020
|
+
if (typeof entry !== "string") {
|
|
19021
|
+
throw frozenError("frozen snapshot exclusion entries must be strings");
|
|
19022
|
+
}
|
|
19023
|
+
const segments = entry.split("/").filter((segment) => segment !== "" && segment !== ".");
|
|
19024
|
+
if (segments.length === 0 || entry.startsWith("/") || entry.includes("\\") || segments.some((segment) => segment === "..")) {
|
|
19025
|
+
throw frozenError(`frozen snapshot exclusion entry is not a safe relative path: ${JSON.stringify(entry)}`);
|
|
19026
|
+
}
|
|
19027
|
+
if (segments.length === 1) {
|
|
19028
|
+
excludedRootNames.add(segments[0]);
|
|
19029
|
+
} else {
|
|
19030
|
+
excludedPathPrefixes.push(segments.join("/"));
|
|
19031
|
+
}
|
|
19032
|
+
}
|
|
19017
19033
|
async function walk(dir) {
|
|
19018
19034
|
const children = await readdir3(dir, { withFileTypes: true });
|
|
19019
19035
|
children.sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
19020
19036
|
for (const child of children) {
|
|
19021
|
-
if (dir === root &&
|
|
19037
|
+
if (dir === root && excludedRootNames.has(child.name)) continue;
|
|
19022
19038
|
const absolute = join3(dir, child.name);
|
|
19023
19039
|
const rel = relative7(root, absolute).split("\\").join("/");
|
|
19040
|
+
if (excludedPathPrefixes.some((prefix) => rel === prefix || rel.startsWith(`${prefix}/`))) continue;
|
|
19024
19041
|
const st = await lstat5(absolute);
|
|
19025
19042
|
if (st.isSymbolicLink()) {
|
|
19026
19043
|
throw frozenError(`frozen snapshot contains symlink: ${rel}`);
|
|
@@ -76932,7 +76949,8 @@ function transportPayload(entries) {
|
|
|
76932
76949
|
}
|
|
76933
76950
|
function consumerTransportExclusions(consumer) {
|
|
76934
76951
|
if (consumer === "claude") return [".in_use"];
|
|
76935
|
-
if (consumer === "codex"
|
|
76952
|
+
if (consumer === "codex") return [".git", ".codex-plugin/migrated-command-skills"];
|
|
76953
|
+
if (consumer === "kimi") return [".git"];
|
|
76936
76954
|
return [];
|
|
76937
76955
|
}
|
|
76938
76956
|
function extractDeclaredPluginSource(consumer, entry) {
|
|
@@ -9,7 +9,7 @@ const __bundlePkgRoot = __bundleResolve(__bundleDirname(__bundleFileURLToPath(im
|
|
|
9
9
|
// Provide a real require() for CJS packages bundled into ESM (e.g. yaml, ajv).
|
|
10
10
|
const __bundleRealRequire = __bundleCreateRequire(import.meta.url);
|
|
11
11
|
// Package identity injected at build time — closure-independent --version probe.
|
|
12
|
-
const __bundlePkg = Object.freeze({"name":"release-skill","version":"0.1.
|
|
12
|
+
const __bundlePkg = Object.freeze({"name":"release-skill","version":"0.1.10"});
|
|
13
13
|
|
|
14
14
|
var __create = Object.create;
|
|
15
15
|
var __defProp = Object.defineProperty;
|
|
@@ -17816,7 +17816,8 @@ var init_baseline = __esm({
|
|
|
17816
17816
|
".release-skill/lock",
|
|
17817
17817
|
".release-skill/lock-audit",
|
|
17818
17818
|
".release-skill/runs",
|
|
17819
|
-
".release-skill/transactions"
|
|
17819
|
+
".release-skill/transactions",
|
|
17820
|
+
".release-skill/kimi-attestations"
|
|
17820
17821
|
];
|
|
17821
17822
|
RESERVED_CONTROL_PREFIXES = [
|
|
17822
17823
|
...CONTROL_PLANE_PREFIXES,
|
|
@@ -19013,14 +19014,30 @@ async function computeFrozenSnapshot(snapshotDir, { excludeRootEntries = [] } =
|
|
|
19013
19014
|
throw frozenError("frozen snapshot root must be a real directory");
|
|
19014
19015
|
}
|
|
19015
19016
|
const entries = [];
|
|
19016
|
-
const
|
|
19017
|
+
const excludedRootNames = /* @__PURE__ */ new Set();
|
|
19018
|
+
const excludedPathPrefixes = [];
|
|
19019
|
+
for (const entry of excludeRootEntries) {
|
|
19020
|
+
if (typeof entry !== "string") {
|
|
19021
|
+
throw frozenError("frozen snapshot exclusion entries must be strings");
|
|
19022
|
+
}
|
|
19023
|
+
const segments = entry.split("/").filter((segment) => segment !== "" && segment !== ".");
|
|
19024
|
+
if (segments.length === 0 || entry.startsWith("/") || entry.includes("\\") || segments.some((segment) => segment === "..")) {
|
|
19025
|
+
throw frozenError(`frozen snapshot exclusion entry is not a safe relative path: ${JSON.stringify(entry)}`);
|
|
19026
|
+
}
|
|
19027
|
+
if (segments.length === 1) {
|
|
19028
|
+
excludedRootNames.add(segments[0]);
|
|
19029
|
+
} else {
|
|
19030
|
+
excludedPathPrefixes.push(segments.join("/"));
|
|
19031
|
+
}
|
|
19032
|
+
}
|
|
19017
19033
|
async function walk(dir) {
|
|
19018
19034
|
const children = await readdir3(dir, { withFileTypes: true });
|
|
19019
19035
|
children.sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
19020
19036
|
for (const child of children) {
|
|
19021
|
-
if (dir === root &&
|
|
19037
|
+
if (dir === root && excludedRootNames.has(child.name)) continue;
|
|
19022
19038
|
const absolute = join3(dir, child.name);
|
|
19023
19039
|
const rel = relative7(root, absolute).split("\\").join("/");
|
|
19040
|
+
if (excludedPathPrefixes.some((prefix) => rel === prefix || rel.startsWith(`${prefix}/`))) continue;
|
|
19024
19041
|
const st = await lstat5(absolute);
|
|
19025
19042
|
if (st.isSymbolicLink()) {
|
|
19026
19043
|
throw frozenError(`frozen snapshot contains symlink: ${rel}`);
|
|
@@ -76932,7 +76949,8 @@ function transportPayload(entries) {
|
|
|
76932
76949
|
}
|
|
76933
76950
|
function consumerTransportExclusions(consumer) {
|
|
76934
76951
|
if (consumer === "claude") return [".in_use"];
|
|
76935
|
-
if (consumer === "codex"
|
|
76952
|
+
if (consumer === "codex") return [".git", ".codex-plugin/migrated-command-skills"];
|
|
76953
|
+
if (consumer === "kimi") return [".git"];
|
|
76936
76954
|
return [];
|
|
76937
76955
|
}
|
|
76938
76956
|
function extractDeclaredPluginSource(consumer, entry) {
|
package/package.json
CHANGED
|
@@ -50,12 +50,18 @@ function transportPayload(entries) {
|
|
|
50
50
|
|
|
51
51
|
// Consumer-owned transport metadata written into the plugin install root
|
|
52
52
|
// that is not part of the published payload. Codex checks out the
|
|
53
|
-
// repository (root `.git` metadata)
|
|
54
|
-
//
|
|
55
|
-
//
|
|
53
|
+
// repository (root `.git` metadata) and materializes migrated command
|
|
54
|
+
// skills under `.codex-plugin/migrated-command-skills/` (the CLI converts
|
|
55
|
+
// plugin commands/ into skill format at install time); Claude marks in-use
|
|
56
|
+
// plugin checkouts with an empty root `.in_use` marker. Single-segment
|
|
57
|
+
// exclusions apply to root entries only; the multi-segment exclusion names
|
|
58
|
+
// the exact CLI-generated subtree. All other payload paths keep the
|
|
59
|
+
// fail-closed file checks — the exemption must never widen to
|
|
60
|
+
// ".codex-plugin/*" or arbitrary extra files.
|
|
56
61
|
function consumerTransportExclusions(consumer) {
|
|
57
62
|
if (consumer === 'claude') return ['.in_use'];
|
|
58
|
-
if (consumer === 'codex'
|
|
63
|
+
if (consumer === 'codex') return ['.git', '.codex-plugin/migrated-command-skills'];
|
|
64
|
+
if (consumer === 'kimi') return ['.git'];
|
|
59
65
|
return [];
|
|
60
66
|
}
|
|
61
67
|
|
package/src/core/baseline.mjs
CHANGED
|
@@ -17,6 +17,16 @@ const execFile = promisify(execFileCb);
|
|
|
17
17
|
* use reserved prefixes; immutable plans and approvals use exact digest-shaped
|
|
18
18
|
* paths so arbitrary files under similarly named directories remain visible.
|
|
19
19
|
*
|
|
20
|
+
* `kimi-attestations` holds Kimi's closure-protocol lifecycle artifacts:
|
|
21
|
+
* the manual installation requirement that publish/reconcile itself emits
|
|
22
|
+
* for a PARTIAL kimi checkpoint, and the human-written attestation that is
|
|
23
|
+
* the designed closure input (independently bound to planDigest,
|
|
24
|
+
* payloadDigest, exact version/tag, install path, responsible person, and
|
|
25
|
+
* expiry). Neither is publishable source or project configuration — they
|
|
26
|
+
* never enter the frozen snapshot — so excluding them keeps reconcile's own
|
|
27
|
+
* requirement output and the flow-required attestation from invalidating
|
|
28
|
+
* the baseline of every subsequent reconcile.
|
|
29
|
+
*
|
|
20
30
|
* `project.yaml` is intentionally **not** listed — changes to project
|
|
21
31
|
* configuration must always cause a baseline drift.
|
|
22
32
|
*/
|
|
@@ -27,6 +37,7 @@ const CONTROL_PLANE_PREFIXES = [
|
|
|
27
37
|
'.release-skill/lock-audit',
|
|
28
38
|
'.release-skill/runs',
|
|
29
39
|
'.release-skill/transactions',
|
|
40
|
+
'.release-skill/kimi-attestations',
|
|
30
41
|
];
|
|
31
42
|
const RESERVED_CONTROL_PREFIXES = [
|
|
32
43
|
...CONTROL_PLANE_PREFIXES,
|
package/src/snapshot/frozen.mjs
CHANGED
|
@@ -83,9 +83,14 @@ async function readStableRegularFile(filePath, displayPath) {
|
|
|
83
83
|
*
|
|
84
84
|
* `excludeRootEntries` is reserved for consumer-owned transport metadata
|
|
85
85
|
* that is not part of the published payload: Codex's root `.git` checkout
|
|
86
|
-
* metadata
|
|
87
|
-
*
|
|
88
|
-
*
|
|
86
|
+
* metadata, Codex's CLI-generated `.codex-plugin/migrated-command-skills/`
|
|
87
|
+
* subtree, and Claude's root `.in_use` in-use plugin marker. Single-segment
|
|
88
|
+
* entries only match direct children of the root (historical behavior);
|
|
89
|
+
* multi-segment entries name an exact relative path whose subtree is
|
|
90
|
+
* skipped. Every other payload path retains the normal fail-closed file
|
|
91
|
+
* checks — the exemption must never widen to whole directories or
|
|
92
|
+
* arbitrary extra files. Malformed entries (absolute, "..", backslash)
|
|
93
|
+
* fail closed: a bad exclusion list is a caller bug, not transport metadata.
|
|
89
94
|
*/
|
|
90
95
|
export async function computeFrozenSnapshot(snapshotDir, { excludeRootEntries = [] } = {}) {
|
|
91
96
|
const root = await realpath(snapshotDir);
|
|
@@ -95,14 +100,33 @@ export async function computeFrozenSnapshot(snapshotDir, { excludeRootEntries =
|
|
|
95
100
|
}
|
|
96
101
|
|
|
97
102
|
const entries = [];
|
|
98
|
-
const
|
|
103
|
+
const excludedRootNames = new Set();
|
|
104
|
+
const excludedPathPrefixes = [];
|
|
105
|
+
for (const entry of excludeRootEntries) {
|
|
106
|
+
if (typeof entry !== 'string') {
|
|
107
|
+
throw frozenError('frozen snapshot exclusion entries must be strings');
|
|
108
|
+
}
|
|
109
|
+
const segments = entry.split('/').filter((segment) => segment !== '' && segment !== '.');
|
|
110
|
+
if (
|
|
111
|
+
segments.length === 0 || entry.startsWith('/') || entry.includes('\\') ||
|
|
112
|
+
segments.some((segment) => segment === '..')
|
|
113
|
+
) {
|
|
114
|
+
throw frozenError(`frozen snapshot exclusion entry is not a safe relative path: ${JSON.stringify(entry)}`);
|
|
115
|
+
}
|
|
116
|
+
if (segments.length === 1) {
|
|
117
|
+
excludedRootNames.add(segments[0]);
|
|
118
|
+
} else {
|
|
119
|
+
excludedPathPrefixes.push(segments.join('/'));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
99
122
|
async function walk(dir) {
|
|
100
123
|
const children = await readdir(dir, { withFileTypes: true });
|
|
101
124
|
children.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
|
|
102
125
|
for (const child of children) {
|
|
103
|
-
if (dir === root &&
|
|
126
|
+
if (dir === root && excludedRootNames.has(child.name)) continue;
|
|
104
127
|
const absolute = join(dir, child.name);
|
|
105
128
|
const rel = relative(root, absolute).split('\\').join('/');
|
|
129
|
+
if (excludedPathPrefixes.some((prefix) => rel === prefix || rel.startsWith(`${prefix}/`))) continue;
|
|
106
130
|
const st = await lstat(absolute);
|
|
107
131
|
if (st.isSymbolicLink()) {
|
|
108
132
|
throw frozenError(`frozen snapshot contains symlink: ${rel}`);
|