release-skill 0.1.8 → 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.
@@ -9,7 +9,7 @@
9
9
  {
10
10
  "name": "release-skill",
11
11
  "source": "./",
12
- "version": "0.1.8",
12
+ "version": "0.1.10",
13
13
  "description": "Safe preparation and frozen GitHub/npm production publishing with full happy end verification"
14
14
  }
15
15
  ]
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "release-skill",
3
- "version": "0.1.8",
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": "广州市风荷科技有限公司"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "release-skill",
3
- "version": "0.1.8",
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.8.",
22
+ "Prepare a release plan for version 0.1.10.",
23
23
  "Help me understand the release workflow."
24
24
  ]
25
25
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "release-skill",
3
- "version": "0.1.8",
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": "广州市风荷科技有限公司"
package/CHANGELOG.md CHANGED
@@ -1,5 +1,73 @@
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
+
37
+ <!-- release-skill:changelog:start version=0.1.9 locale=en baseline=sha256:409f940c03e2d6fd41d33659b246b3d4b622918b4ac5a3a711d83aa09740ef11 -->
38
+ ## [0.1.9] - 2026-07-23
39
+
40
+ v0.1.9 fixes a structural marketplace install verification failure: consumer installs that declare a plugin `source` subdirectory (e.g. `./adapters/claude`) now bind the installed payload to the declared subtree of the sealed whole-unit snapshot, and Claude's root `.in_use` marker is exempted as consumer-owned transport metadata. 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.
41
+
42
+ ### Fixed
43
+
44
+ - **Marketplace payload binding for subdirectory source layouts**: consumer
45
+ marketplaces may declare a plugin `source` subdirectory such as
46
+ `./adapters/claude`; the consumer CLI then installs only that subtree while
47
+ the sealed authority is the whole unit snapshot. Install verification now
48
+ revalidates the sealed whole-snapshot digest, re-reads the declared source
49
+ from the marketplace manifest inside the digest-verified snapshot entries,
50
+ and binds the installed payload to that prefix-stripped subtree. Root
51
+ layouts and Kimi keep the whole-tree comparison. This resolves the
52
+ flow-architect v0.4.1 and v0.5.0 PARTIAL marketplace install failures;
53
+ already-frozen plans reconcile unchanged because the sealed digest, plan
54
+ schema, and prepare-side freezing are untouched.
55
+ - **Claude `.in_use` transport marker exemption**: the Claude CLI writes an
56
+ empty `.in_use` marker into the plugin install root; it is now exempted as
57
+ consumer-owned transport metadata alongside the existing Codex/Kimi `.git`
58
+ exemption, through a single shared exclusion helper that also backs the
59
+ observe-time diagnostic fallback. Exemptions remain root-only: nested
60
+ markers, extra payload, byte tampering, and sealed authority tampering
61
+ still fail closed.
62
+ - **Regression coverage**: new protocol-level fake-CLI tests cover the
63
+ subdirectory claude cycle with `.in_use` (including byte-tamper,
64
+ extra-file, missing-file, `.git`-not-exempt, and nested-marker negatives),
65
+ fail-closed manifest anomalies (duplicate plugin entry, wrong marketplace
66
+ name, empty source projection), root-layout claude with `.in_use`, and a
67
+ codex subdirectory variant.
68
+ <!-- release-skill:changelog:end version=0.1.9 locale=en -->
69
+
70
+
3
71
  <!-- release-skill:changelog:start version=0.1.8 locale=en baseline=sha256:1e1a0af9d5807bceb7af1eae88b726f67e6811dba4db579fd625c07f3bdbca89 -->
4
72
  ## [0.1.8] - 2026-07-23
5
73
 
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.8 -->
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.8
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.8",
86
+ "version": "0.1.10",
87
87
  "entrySkill": "release-help",
88
88
  "repo": "ifoohoo/release-skill",
89
- "ref": "release-skill-v0.1.8",
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.8 -->
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.8
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.8",
79
+ "version": "0.1.10",
80
80
  "entrySkill": "release-help",
81
81
  "repo": "ifoohoo/release-skill",
82
- "ref": "release-skill-v0.1.8",
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.8 -->
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,29 +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.8** (2026-07-23)
15
-
16
- v0.1.8 adds Kimi Code as a first-class plugin host without rewriting the already-published v0.1.7 artifacts. Kimi delivery uses a generated self-contained adapter and a fail-closed, plan-bound manual installation attestation because Kimi Code has no scriptable non-interactive plugin installation interface. The npm package name (`release-skill`), publishing identity (`publisher: mzdbxqh`), public repository (`ifoohoo/release-skill`), and corporate maintainer remain unchanged.
17
-
18
- **Changed**
19
-
20
- - **Kimi Code plugin delivery and verification**: v0.1.8 adds the root
21
- `.kimi-plugin/plugin.json`, a generated self-contained `adapters/kimi/` bundle,
22
- and public installation guidance. Because Kimi Code exposes no scriptable
23
- non-interactive plugin installation interface, production publish emits a
24
- version-pinned manual installation requirement and enters `PARTIAL`; an
25
- isolated `KIMI_CODE_HOME` installation and a trusted attestation bound
26
- independently to the frozen plan digest and payload digest are required before
27
- `reconcile` can reach `PUBLISHED` and `verify` can reach `VERIFIED`.
28
- - **Immutable v0.1.7 history preserved**: the existing v0.1.7 Git tag,
29
- GitHub Release, npm version, and public commit remain untouched. The v0.1.8
30
- production plan binds the published v0.1.7 commit
31
- `fe5897456d4166a2ec60e99405836b122562b80d` as its previous public baseline.
14
+ **0.1.10** (2026-07-24)
15
+
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
+
18
+ **Fixed**
19
+
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
32
+ schema, and prepare-side freezing are untouched.
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.
32
44
  <!-- release-skill:managed:end id=latest-release -->
33
45
 
34
46
  <!-- release-skill:capability:external-write-boundary -->
35
- > **Current boundary:** v0.1.8 is the current release (v0.1.7 previously held
36
- > published status before the Kimi Code distribution was added).
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).
37
49
  > v0.1.1 completed a real production release to GitHub and npm — the first
38
50
  > production-verified milestone — followed by
39
51
  > exact npm installation and Claude/Codex consumer installation verification
@@ -50,7 +62,7 @@ v0.1.8 adds Kimi Code as a first-class plugin host without rewriting the already
50
62
  > publish global preflight.
51
63
 
52
64
  <!-- release-skill:capability:safe-first-command -->
53
- > **Production path verified since the v0.1.1 milestone; v0.1.8 is the current
65
+ > **Production path verified since the v0.1.1 milestone; v0.1.9 is the current
54
66
  > release.** The npm-installed CLI is the supported user entry. Source checkout
55
67
  > is the development/contributor fallback.
56
68
  >
package/README.zh-CN.md CHANGED
@@ -2,31 +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.8 -->
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.8** (2026-07-23)
12
-
13
- v0.1.8 在不改写已经公开的 v0.1.7 制品的前提下,新增对 Kimi Code 一等插件宿主的支持。由于 Kimi Code 没有可脚本化的非交互插件安装接口,Kimi 分发采用生成的自包含适配器,以及失败关闭、绑定冻结计划的人工安装证明。npm 包名(`release-skill`)、发布身份(`publisher: mzdbxqh`)、公开仓库(`ifoohoo/release-skill`)与公司维护主体均保持不变。
14
-
15
- **变更**
16
-
17
- - **Kimi Code 插件分发与验证**:v0.1.8 新增根
18
- `.kimi-plugin/plugin.json`、生成的自包含 `adapters/kimi/` 适配器和公开安装说明。
19
- 由于 Kimi Code 没有可脚本化的非交互插件安装接口,生产发布会生成版本钉死的人工
20
- 安装要求并进入 `PARTIAL`;操作者必须在隔离的 `KIMI_CODE_HOME` 中完成安装,并
21
- 提供分别绑定冻结计划摘要和载荷摘要的可信证明,之后 `reconcile` 才能进入
22
- `PUBLISHED`,`verify` 才能进入 `VERIFIED`。
23
- - **保留不可变的 v0.1.7 历史**:既有 v0.1.7 Git 标签、GitHub Release、npm
24
- 版本与公开提交均不改写。v0.1.8 生产计划以已公开的 v0.1.7 提交
25
- `fe5897456d4166a2ec60e99405836b122562b80d` 作为前序公开基线。
11
+ **0.1.10** (2026-07-24)
12
+
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
+
15
+ **修复**
16
+
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
+ 篡改与多余文件负例。
26
34
  <!-- release-skill:managed:end id=latest-release -->
27
35
 
28
36
  <!-- release-skill:capability:external-write-boundary -->
29
- > **当前边界:** v0.1.8 是当前发布版本(v0.1.7 曾处于已发布、待独立验证状态)。
37
+ > **当前边界:** v0.1.10 是当前发布版本(v0.1.9 曾处于已发布、待独立验证状态)。
30
38
  > v0.1.1 已完成 GitHub 与 npm 的
31
39
  > 真实生产发布,是首次生产验证的历史里程碑,并从冻结 Git ref 完成精确 npm
32
40
  > 安装及 Claude/Codex 消费者安装验证;“当前发布版本”与“首次生产验证里程碑”
@@ -39,7 +47,7 @@ v0.1.8 在不改写已经公开的 v0.1.7 制品的前提下,新增对 Kimi Co
39
47
  > 远端唯一性检查在 `publish` 全局预检执行。
40
48
 
41
49
  <!-- release-skill:capability:safe-first-command -->
42
- > **生产路径自 v0.1.1 里程碑起已完成真实生产验证;v0.1.8 是当前发布版本。**
50
+ > **生产路径自 v0.1.1 里程碑起已完成真实生产验证;v0.1.9 是当前发布版本。**
43
51
  > npm 安装的 CLI 是受支持的用户入口;源码 checkout 保留为开发/贡献者路径。
44
52
  >
45
53
  > **第一条命令:**
@@ -9,7 +9,7 @@
9
9
  {
10
10
  "name": "release-skill",
11
11
  "source": "./",
12
- "version": "0.1.8",
12
+ "version": "0.1.10",
13
13
  "description": "Safe preparation and frozen GitHub/npm production publishing with full happy end verification"
14
14
  }
15
15
  ]
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "release-skill",
3
- "version": "0.1.8",
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": "广州市风荷科技有限公司"
@@ -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.8"});
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 excluded = new Set(excludeRootEntries);
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 && excluded.has(child.name)) continue;
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}`);
@@ -76930,6 +76947,50 @@ function transportPayload(entries) {
76930
76947
  contentDigest
76931
76948
  }));
76932
76949
  }
76950
+ function consumerTransportExclusions(consumer) {
76951
+ if (consumer === "claude") return [".in_use"];
76952
+ if (consumer === "codex") return [".git", ".codex-plugin/migrated-command-skills"];
76953
+ if (consumer === "kimi") return [".git"];
76954
+ return [];
76955
+ }
76956
+ function extractDeclaredPluginSource(consumer, entry) {
76957
+ const rawSource = consumer === "claude" ? entry.source : entry.source?.source === "local" ? entry.source?.path : null;
76958
+ if (typeof rawSource !== "string" || rawSource.length === 0) {
76959
+ throw new Error(`marketplace plugin entry source must be a non-empty relative path${consumer === "codex" ? ' (object with source:"local")' : ""}, got ${JSON.stringify(entry.source)}`);
76960
+ }
76961
+ if (rawSource.startsWith("/") || rawSource.includes("..") || rawSource.includes("\\") || /^https?:\/\//i.test(rawSource)) {
76962
+ throw new Error(`marketplace plugin entry source "${rawSource}" is not a safe relative path`);
76963
+ }
76964
+ const segments = rawSource.split("/").filter((segment) => segment !== "" && segment !== ".");
76965
+ if (segments.some((segment) => segment === "..")) {
76966
+ throw new Error(`marketplace plugin entry source "${rawSource}" is not a safe relative path`);
76967
+ }
76968
+ return segments.length === 0 ? "." : segments.join("/");
76969
+ }
76970
+ async function resolveInstalledPayloadSubpath(snapshotDir, sourceEntries, action, consumer) {
76971
+ if (consumer === "kimi") return ".";
76972
+ const marketplaceRelative = consumer === "claude" ? ".claude-plugin/marketplace.json" : ".agents/plugins/marketplace.json";
76973
+ const anchored = sourceEntries.some((entry) => entry.type === "file" && entry.path === marketplaceRelative);
76974
+ if (!anchored) {
76975
+ throw new Error(`frozen snapshot is missing the marketplace manifest ${marketplaceRelative}`);
76976
+ }
76977
+ const result = await validateManifestFile(resolve19(snapshotDir, marketplaceRelative), ["name", "plugins"]);
76978
+ if (!result.valid) {
76979
+ throw new Error(`frozen snapshot ${marketplaceRelative} invalid: ${result.error}`);
76980
+ }
76981
+ if (result.manifest.name !== action.marketplace) {
76982
+ throw new Error(`marketplace manifest name "${result.manifest.name}" does not match action marketplace "${action.marketplace}"`);
76983
+ }
76984
+ const plugins = result.manifest.plugins;
76985
+ if (!Array.isArray(plugins)) {
76986
+ throw new Error(`${marketplaceRelative} must have a plugins[] array`);
76987
+ }
76988
+ const matches = plugins.filter((entry) => entry.name === action.plugin);
76989
+ if (matches.length !== 1) {
76990
+ throw new Error(`expected exactly one plugins[] entry with name "${action.plugin}", found ${matches.length}`);
76991
+ }
76992
+ return extractDeclaredPluginSource(consumer, matches[0]);
76993
+ }
76933
76994
  async function verifyInstalledMarketplacePayload(action, context, installPath, consumer) {
76934
76995
  const sourcePath = await resolveFrozenPath(
76935
76996
  context.root,
@@ -76940,10 +77001,21 @@ async function verifyInstalledMarketplacePayload(action, context, installPath, c
76940
77001
  if (sourceSnapshot.digest !== action.manifestDigest) {
76941
77002
  throw new Error("frozen marketplace snapshot digest no longer matches the plan");
76942
77003
  }
77004
+ const payloadSubpath = await resolveInstalledPayloadSubpath(
77005
+ sourcePath,
77006
+ sourceSnapshot.entries,
77007
+ action,
77008
+ consumer
77009
+ );
77010
+ const prefix = payloadSubpath === "." ? null : `${payloadSubpath}/`;
77011
+ const authorityEntries = prefix === null ? sourceSnapshot.entries : sourceSnapshot.entries.filter((entry) => entry.path.startsWith(prefix)).map((entry) => ({ ...entry, path: entry.path.slice(prefix.length) }));
77012
+ if (authorityEntries.length === 0) {
77013
+ throw new Error("frozen snapshot contains no payload under the declared marketplace source");
77014
+ }
76943
77015
  const installedSnapshot = await computeFrozenSnapshot(installPath, {
76944
- excludeRootEntries: consumer === "codex" || consumer === "kimi" ? [".git"] : []
77016
+ excludeRootEntries: consumerTransportExclusions(consumer)
76945
77017
  });
76946
- if (JSON.stringify(transportPayload(sourceSnapshot.entries)) !== JSON.stringify(transportPayload(installedSnapshot.entries))) {
77018
+ if (JSON.stringify(transportPayload(authorityEntries)) !== JSON.stringify(transportPayload(installedSnapshot.entries))) {
76947
77019
  throw new Error("installed marketplace payload differs in path, bytes, size, or non-write mode bits");
76948
77020
  }
76949
77021
  return action.manifestDigest;
@@ -77643,19 +77715,14 @@ function createPluginMarketplaceAdapter(deps = {}) {
77643
77715
  });
77644
77716
  }
77645
77717
  const entry = pluginEntry[0];
77646
- const sourcePath = consumer === "claude" ? entry.source : entry.source?.source === "local" ? entry.source?.path : null;
77647
- if (typeof sourcePath !== "string" || sourcePath.length === 0) {
77648
- return createResult({
77649
- actionType,
77650
- status: ActionStatus.PREFLIGHT_FAILED,
77651
- error: `marketplace plugin entry source must be a non-empty relative path${consumer === "codex" ? ' (object with source:"local")' : ""}, got ${JSON.stringify(entry.source)}`
77652
- });
77653
- }
77654
- if (sourcePath.startsWith("/") || sourcePath.includes("..") || sourcePath.includes("\\") || /^https?:\/\//i.test(sourcePath)) {
77718
+ let sourcePath;
77719
+ try {
77720
+ sourcePath = extractDeclaredPluginSource(consumer, entry);
77721
+ } catch (sourceErr) {
77655
77722
  return createResult({
77656
77723
  actionType,
77657
77724
  status: ActionStatus.PREFLIGHT_FAILED,
77658
- error: `marketplace plugin entry source "${sourcePath}" is not a safe relative path`
77725
+ error: sourceErr.message
77659
77726
  });
77660
77727
  }
77661
77728
  const sourceDirAbs = resolve19(snapshotDirReal, sourcePath);
@@ -78578,7 +78645,7 @@ function createPluginMarketplaceAdapter(deps = {}) {
78578
78645
  } catch (digestErr) {
78579
78646
  try {
78580
78647
  const installedSnapshot = await computeFrozenSnapshot(installPath, {
78581
- excludeRootEntries: consumer === "codex" || consumer === "kimi" ? [".git"] : []
78648
+ excludeRootEntries: consumerTransportExclusions(consumer)
78582
78649
  });
78583
78650
  manifestDigest = installedSnapshot.digest;
78584
78651
  } catch {
@@ -78744,6 +78811,9 @@ var init_plugin_marketplace = __esm({
78744
78811
  execFile9 = promisify10(execFileCb10);
78745
78812
  NAME4 = "plugin-marketplace";
78746
78813
  __name(transportPayload, "transportPayload");
78814
+ __name(consumerTransportExclusions, "consumerTransportExclusions");
78815
+ __name(extractDeclaredPluginSource, "extractDeclaredPluginSource");
78816
+ __name(resolveInstalledPayloadSubpath, "resolveInstalledPayloadSubpath");
78747
78817
  __name(verifyInstalledMarketplacePayload, "verifyInstalledMarketplacePayload");
78748
78818
  __name(writeEvidenceAtomic, "writeEvidenceAtomic");
78749
78819
  KIMI_REQUIREMENT_FILE = "release-skill-kimi-manual-install.json";
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "release-skill",
3
- "version": "0.1.8",
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.8.",
22
+ "Prepare a release plan for version 0.1.10.",
23
23
  "Help me understand the release workflow."
24
24
  ]
25
25
  }