release-skill 0.9.35 → 0.9.37
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/plugin.json +1 -1
- package/.codebuddy-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +2 -2
- package/.cursor-plugin/plugin.json +1 -1
- package/.kimi-plugin/plugin.json +1 -1
- package/.qoder-plugin/plugin.json +1 -1
- package/CHANGELOG.md +45 -0
- package/INSTALL.md +2 -2
- package/INSTALL.zh-CN.md +2 -2
- package/README.md +24 -9
- package/README.zh-CN.md +15 -9
- package/adapters/claude/.claude-plugin/plugin.json +1 -1
- package/adapters/claude/bin/release-skill.bundle.mjs +270 -58
- package/adapters/claude/schemas/.render-manifest.json +6 -2
- package/adapters/claude/skills/release-config/SKILL.md +36 -41
- package/adapters/claude/skills/release-docs/SKILL.md +38 -35
- package/adapters/claude/skills/release-finish/SKILL.md +2 -2
- package/adapters/claude/skills/release-help/SKILL.md +51 -41
- package/adapters/claude/skills/release-marketplace/SKILL.md +38 -46
- package/adapters/claude/skills/release-prepare/SKILL.md +19 -28
- package/adapters/claude/skills/release-publish/SKILL.md +29 -45
- package/adapters/codex/.codex-plugin/plugin.json +2 -2
- package/adapters/codex/bin/release-skill.bundle.mjs +270 -58
- package/adapters/codex/schemas/.render-manifest.json +6 -2
- package/adapters/codex/skills/release-config/SKILL.md +36 -41
- package/adapters/codex/skills/release-docs/SKILL.md +38 -35
- package/adapters/codex/skills/release-finish/SKILL.md +2 -2
- package/adapters/codex/skills/release-help/SKILL.md +51 -41
- package/adapters/codex/skills/release-marketplace/SKILL.md +38 -46
- package/adapters/codex/skills/release-prepare/SKILL.md +19 -28
- package/adapters/codex/skills/release-publish/SKILL.md +29 -45
- package/adapters/cursor/.cursor-plugin/plugin.json +1 -1
- package/adapters/cursor/bin/release-skill.bundle.mjs +270 -58
- package/adapters/cursor/schemas/.render-manifest.json +6 -2
- package/adapters/cursor/skills/release-config/SKILL.md +36 -41
- package/adapters/cursor/skills/release-docs/SKILL.md +38 -35
- package/adapters/cursor/skills/release-finish/SKILL.md +2 -2
- package/adapters/cursor/skills/release-help/SKILL.md +51 -41
- package/adapters/cursor/skills/release-marketplace/SKILL.md +38 -46
- package/adapters/cursor/skills/release-prepare/SKILL.md +19 -28
- package/adapters/cursor/skills/release-publish/SKILL.md +29 -45
- package/adapters/kimi/.kimi-plugin/plugin.json +1 -1
- package/adapters/kimi/bin/release-skill.bundle.mjs +270 -58
- package/adapters/kimi/schemas/.render-manifest.json +6 -2
- package/adapters/kimi/skills/release-config/SKILL.md +36 -41
- package/adapters/kimi/skills/release-docs/SKILL.md +38 -35
- package/adapters/kimi/skills/release-finish/SKILL.md +2 -2
- package/adapters/kimi/skills/release-help/SKILL.md +51 -41
- package/adapters/kimi/skills/release-marketplace/SKILL.md +38 -46
- package/adapters/kimi/skills/release-prepare/SKILL.md +19 -28
- package/adapters/kimi/skills/release-publish/SKILL.md +29 -45
- package/adapters/qoder/.qoder-plugin/plugin.json +1 -1
- package/adapters/qoder/bin/release-skill.bundle.mjs +270 -58
- package/adapters/qoder/schemas/.render-manifest.json +6 -2
- package/adapters/qoder/skills/release-config/SKILL.md +36 -41
- package/adapters/qoder/skills/release-docs/SKILL.md +38 -35
- package/adapters/qoder/skills/release-finish/SKILL.md +2 -2
- package/adapters/qoder/skills/release-help/SKILL.md +51 -41
- package/adapters/qoder/skills/release-marketplace/SKILL.md +38 -46
- package/adapters/qoder/skills/release-prepare/SKILL.md +19 -28
- package/adapters/qoder/skills/release-publish/SKILL.md +29 -45
- package/adapters/workbuddy/.codebuddy-plugin/plugin.json +1 -1
- package/adapters/workbuddy/bin/release-skill.bundle.mjs +270 -58
- package/adapters/workbuddy/schemas/.render-manifest.json +6 -2
- package/adapters/workbuddy/skills/release-config/SKILL.md +36 -41
- package/adapters/workbuddy/skills/release-docs/SKILL.md +38 -35
- package/adapters/workbuddy/skills/release-finish/SKILL.md +2 -2
- package/adapters/workbuddy/skills/release-help/SKILL.md +51 -41
- package/adapters/workbuddy/skills/release-marketplace/SKILL.md +38 -46
- package/adapters/workbuddy/skills/release-prepare/SKILL.md +19 -28
- package/adapters/workbuddy/skills/release-publish/SKILL.md +29 -45
- package/bin/release-skill.bundle.mjs +270 -58
- package/package.json +1 -1
- package/platform-manifest.json +4 -4
- package/references/.render-manifest.json +2 -2
- package/references/02-project-config.md +91 -8
- package/schemas/.render-manifest.json +6 -2
- package/skills/release-config/SKILL.md +36 -41
- package/skills/release-docs/SKILL.md +38 -35
- package/skills/release-finish/SKILL.md +2 -2
- package/skills/release-help/SKILL.md +51 -41
- package/skills/release-marketplace/SKILL.md +38 -46
- package/skills/release-prepare/SKILL.md +19 -28
- package/skills/release-publish/SKILL.md +29 -45
- package/skills-src/release-config/SKILL.md +36 -41
- package/skills-src/release-docs/SKILL.md +38 -35
- package/skills-src/release-finish/SKILL.md +2 -2
- package/skills-src/release-help/SKILL.md +51 -41
- package/skills-src/release-marketplace/SKILL.md +38 -46
- package/skills-src/release-prepare/SKILL.md +19 -28
- package/skills-src/release-publish/SKILL.md +29 -45
- package/src/adapters/plugin-marketplace.mjs +152 -43
- package/src/commands/post-release-local.mjs +41 -22
- package/src/commands/verify.mjs +123 -17
- package/src/core/skill-resource-closure.mjs +1 -1
|
@@ -9,9 +9,9 @@ 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.9.
|
|
12
|
+
const __bundlePkg = Object.freeze({"name":"release-skill","version":"0.9.37"});
|
|
13
13
|
// Build-time source digest for the BUNDLE_STALE freshness gate (see above).
|
|
14
|
-
const __bundleSourceDigest = "
|
|
14
|
+
const __bundleSourceDigest = "6eb7b6560da84252426dc5cfc81297a3d5d6d6101aecb1a8fbf3f35402892715";
|
|
15
15
|
|
|
16
16
|
var __create = Object.create;
|
|
17
17
|
var __defProp = Object.defineProperty;
|
|
@@ -113912,6 +113912,66 @@ function normalizeCodeBuddySkillsRel(skillsRaw) {
|
|
|
113912
113912
|
}
|
|
113913
113913
|
return rel;
|
|
113914
113914
|
}
|
|
113915
|
+
async function resolveCodexEntrySkillFile(pluginRoot, entrySkill, pluginName) {
|
|
113916
|
+
const { normalizeGenericSkillsRel: normalizeGenericSkillsRel2 } = await init_surface_host_bindings().then(() => surface_host_bindings_exports);
|
|
113917
|
+
if (!entrySkill || typeof entrySkill !== "string" || !SAFE_ID_RE.test(entrySkill)) {
|
|
113918
|
+
throw new Error(`unsafe entrySkill: "${entrySkill}"`);
|
|
113919
|
+
}
|
|
113920
|
+
const platform = getPlatform("codex");
|
|
113921
|
+
const manifestPath = await resolveContained(pluginRoot, platform.manifestPaths.plugin);
|
|
113922
|
+
let manifest;
|
|
113923
|
+
try {
|
|
113924
|
+
manifest = JSON.parse(await readFile26(manifestPath, "utf8"));
|
|
113925
|
+
} catch (err) {
|
|
113926
|
+
throw new Error(`Codex plugin manifest cannot be read: ${err.message}`);
|
|
113927
|
+
}
|
|
113928
|
+
if (!manifest || typeof manifest !== "object" || Array.isArray(manifest)) {
|
|
113929
|
+
throw new Error("Codex plugin manifest must be an object");
|
|
113930
|
+
}
|
|
113931
|
+
const skillsRel = Object.hasOwn(manifest, "skills") ? normalizeGenericSkillsRel2(manifest.skills) : "skills";
|
|
113932
|
+
const skillsRoot = await resolveContained(pluginRoot, skillsRel);
|
|
113933
|
+
let skillsRootStat;
|
|
113934
|
+
try {
|
|
113935
|
+
skillsRootStat = await lstat37(skillsRoot);
|
|
113936
|
+
} catch {
|
|
113937
|
+
throw new Error(`Codex manifest skills root does not exist: ${manifest.skills ?? skillsRel}`);
|
|
113938
|
+
}
|
|
113939
|
+
if (skillsRootStat.isSymbolicLink() || !skillsRootStat.isDirectory()) {
|
|
113940
|
+
throw new Error(`Codex manifest skills root must be a real directory: ${manifest.skills ?? skillsRel}`);
|
|
113941
|
+
}
|
|
113942
|
+
const findCandidate = /* @__PURE__ */ __name(async (skillDirName) => {
|
|
113943
|
+
const skillDir = await resolveContained(pluginRoot, `${skillsRel}/${skillDirName}`);
|
|
113944
|
+
let skillDirStat;
|
|
113945
|
+
try {
|
|
113946
|
+
skillDirStat = await lstat37(skillDir);
|
|
113947
|
+
} catch (err) {
|
|
113948
|
+
if (err?.code === "ENOENT") return null;
|
|
113949
|
+
throw err;
|
|
113950
|
+
}
|
|
113951
|
+
if (skillDirStat.isSymbolicLink() || !skillDirStat.isDirectory()) {
|
|
113952
|
+
throw new Error(`Codex entry skill directory must be a real directory: ${skillsRel}/${skillDirName}`);
|
|
113953
|
+
}
|
|
113954
|
+
const skillFile = await resolveContained(pluginRoot, `${skillsRel}/${skillDirName}/SKILL.md`);
|
|
113955
|
+
let skillStat;
|
|
113956
|
+
try {
|
|
113957
|
+
skillStat = await lstat37(skillFile);
|
|
113958
|
+
} catch (err) {
|
|
113959
|
+
if (err?.code === "ENOENT") return null;
|
|
113960
|
+
throw err;
|
|
113961
|
+
}
|
|
113962
|
+
if (skillStat.isSymbolicLink() || !skillStat.isFile()) {
|
|
113963
|
+
throw new Error(`Codex entry skill must be a regular non-symlink file: ${skillsRel}/${skillDirName}/SKILL.md`);
|
|
113964
|
+
}
|
|
113965
|
+
return skillFile;
|
|
113966
|
+
}, "findCandidate");
|
|
113967
|
+
const shortNameEntry = await findCandidate(entrySkill);
|
|
113968
|
+
if (shortNameEntry) return shortNameEntry;
|
|
113969
|
+
if (pluginName && SAFE_ID_RE.test(pluginName)) {
|
|
113970
|
+
const prefixedEntry = await findCandidate(`${pluginName}-${entrySkill}`);
|
|
113971
|
+
if (prefixedEntry) return prefixedEntry;
|
|
113972
|
+
}
|
|
113973
|
+
throw new Error(`Codex entry skill not found: ${skillsRel}/${entrySkill}/SKILL.md`);
|
|
113974
|
+
}
|
|
113915
113975
|
async function resolveCodeBuddyEntrySkillFile(pluginRootReal, manifest, entrySkill) {
|
|
113916
113976
|
if (!entrySkill || typeof entrySkill !== "string" || !SAFE_ID_RE.test(entrySkill)) {
|
|
113917
113977
|
throw new Error(`unsafe entrySkill: "${entrySkill}"`);
|
|
@@ -115067,6 +115127,17 @@ function createPluginMarketplaceAdapter(deps = {}) {
|
|
|
115067
115127
|
error: `entry skill not resolvable in snapshot: ${entryErr.message}`
|
|
115068
115128
|
});
|
|
115069
115129
|
}
|
|
115130
|
+
} else if (consumer === "codex") {
|
|
115131
|
+
const pluginRootForSkill = pluginRootForEntrySkill || snapshotDirReal;
|
|
115132
|
+
try {
|
|
115133
|
+
await resolveCodexEntrySkillFile(pluginRootForSkill, action.entrySkill, action.plugin);
|
|
115134
|
+
} catch (entryErr) {
|
|
115135
|
+
return createResult({
|
|
115136
|
+
actionType,
|
|
115137
|
+
status: ActionStatus.PREFLIGHT_FAILED,
|
|
115138
|
+
error: `entry skill not resolvable in snapshot: ${entryErr.message}`
|
|
115139
|
+
});
|
|
115140
|
+
}
|
|
115070
115141
|
} else {
|
|
115071
115142
|
const pluginRootForSkill = pluginRootForEntrySkill || snapshotDirReal;
|
|
115072
115143
|
let entrySkillFile = resolve22(pluginRootForSkill, "skills", action.entrySkill, "SKILL.md");
|
|
@@ -116181,42 +116252,59 @@ function createPluginMarketplaceAdapter(deps = {}) {
|
|
|
116181
116252
|
}
|
|
116182
116253
|
});
|
|
116183
116254
|
}
|
|
116184
|
-
|
|
116185
|
-
|
|
116186
|
-
|
|
116187
|
-
|
|
116188
|
-
|
|
116189
|
-
|
|
116255
|
+
if (consumer === "codex") {
|
|
116256
|
+
try {
|
|
116257
|
+
await resolveCodexEntrySkillFile(installPath, action.entrySkill, action.plugin);
|
|
116258
|
+
} catch (entryErr) {
|
|
116259
|
+
return createResult({
|
|
116260
|
+
actionType,
|
|
116261
|
+
status: ActionStatus.OBSERVED,
|
|
116262
|
+
observation: {
|
|
116263
|
+
installed: true,
|
|
116264
|
+
installPath,
|
|
116265
|
+
entrySkillFound: false,
|
|
116266
|
+
error: `entry skill not resolvable in installed plugin: ${entryErr.message}`
|
|
116267
|
+
}
|
|
116268
|
+
});
|
|
116190
116269
|
}
|
|
116191
|
-
}
|
|
116192
|
-
|
|
116193
|
-
|
|
116194
|
-
const prefixedPath = resolve22(
|
|
116195
|
-
installPath,
|
|
116196
|
-
"skills",
|
|
116197
|
-
`${action.plugin}-${action.entrySkill}`,
|
|
116198
|
-
"SKILL.md"
|
|
116199
|
-
);
|
|
116270
|
+
} else {
|
|
116271
|
+
let entrySkillPath = resolve22(installPath, "skills", action.entrySkill, "SKILL.md");
|
|
116272
|
+
let entrySkillFound = false;
|
|
116200
116273
|
try {
|
|
116201
|
-
const skillStat = await lstat37(
|
|
116274
|
+
const skillStat = await lstat37(entrySkillPath);
|
|
116202
116275
|
if (skillStat.isFile() && !skillStat.isSymbolicLink()) {
|
|
116203
|
-
entrySkillPath = prefixedPath;
|
|
116204
116276
|
entrySkillFound = true;
|
|
116205
116277
|
}
|
|
116206
116278
|
} catch {
|
|
116207
116279
|
}
|
|
116208
|
-
|
|
116209
|
-
|
|
116210
|
-
return createResult({
|
|
116211
|
-
actionType,
|
|
116212
|
-
status: ActionStatus.OBSERVED,
|
|
116213
|
-
observation: {
|
|
116214
|
-
installed: true,
|
|
116280
|
+
if (!entrySkillFound && action.plugin) {
|
|
116281
|
+
const prefixedPath = resolve22(
|
|
116215
116282
|
installPath,
|
|
116216
|
-
|
|
116217
|
-
|
|
116283
|
+
"skills",
|
|
116284
|
+
`${action.plugin}-${action.entrySkill}`,
|
|
116285
|
+
"SKILL.md"
|
|
116286
|
+
);
|
|
116287
|
+
try {
|
|
116288
|
+
const skillStat = await lstat37(prefixedPath);
|
|
116289
|
+
if (skillStat.isFile() && !skillStat.isSymbolicLink()) {
|
|
116290
|
+
entrySkillPath = prefixedPath;
|
|
116291
|
+
entrySkillFound = true;
|
|
116292
|
+
}
|
|
116293
|
+
} catch {
|
|
116218
116294
|
}
|
|
116219
|
-
}
|
|
116295
|
+
}
|
|
116296
|
+
if (!entrySkillFound) {
|
|
116297
|
+
return createResult({
|
|
116298
|
+
actionType,
|
|
116299
|
+
status: ActionStatus.OBSERVED,
|
|
116300
|
+
observation: {
|
|
116301
|
+
installed: true,
|
|
116302
|
+
installPath,
|
|
116303
|
+
entrySkillFound: false,
|
|
116304
|
+
error: `entry skill not found: skills/${action.entrySkill}/SKILL.md`
|
|
116305
|
+
}
|
|
116306
|
+
});
|
|
116307
|
+
}
|
|
116220
116308
|
}
|
|
116221
116309
|
let manifestDigest;
|
|
116222
116310
|
let manifestError = null;
|
|
@@ -116418,6 +116506,7 @@ var init_plugin_marketplace = __esm({
|
|
|
116418
116506
|
__name(normalizeKimiSkillsRel, "normalizeKimiSkillsRel");
|
|
116419
116507
|
__name(resolveKimiEntrySkillFile, "resolveKimiEntrySkillFile");
|
|
116420
116508
|
__name(normalizeCodeBuddySkillsRel, "normalizeCodeBuddySkillsRel");
|
|
116509
|
+
__name(resolveCodexEntrySkillFile, "resolveCodexEntrySkillFile");
|
|
116421
116510
|
__name(resolveCodeBuddyEntrySkillFile, "resolveCodeBuddyEntrySkillFile");
|
|
116422
116511
|
SUPPORTED_TYPES = [
|
|
116423
116512
|
ActionType.PLUGIN_MANIFEST_VALIDATE,
|
|
@@ -116458,6 +116547,14 @@ var init_plugin_marketplace = __esm({
|
|
|
116458
116547
|
});
|
|
116459
116548
|
|
|
116460
116549
|
// src/core/surface-host-bindings.mjs
|
|
116550
|
+
var surface_host_bindings_exports = {};
|
|
116551
|
+
__export(surface_host_bindings_exports, {
|
|
116552
|
+
deriveSurfaceHostBinding: () => deriveSurfaceHostBinding,
|
|
116553
|
+
groupSurfaceHostBindings: () => groupSurfaceHostBindings,
|
|
116554
|
+
normalizeGenericSkillsRel: () => normalizeGenericSkillsRel,
|
|
116555
|
+
normalizeSurfacePath: () => normalizeSurfacePath,
|
|
116556
|
+
pluginRootFromManifestRelativePath: () => pluginRootFromManifestRelativePath
|
|
116557
|
+
});
|
|
116461
116558
|
import { dirname as dirname10, isAbsolute as isAbsolute18, join as join19, normalize as normalize3, resolve as resolve23, sep as sep9 } from "node:path";
|
|
116462
116559
|
import { lstat as lstat38 } from "node:fs/promises";
|
|
116463
116560
|
function normalizeSurfacePath(rawPath) {
|
|
@@ -116586,6 +116683,49 @@ import { dirname as dirname11, join as join20, relative as relative18, isAbsolut
|
|
|
116586
116683
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
116587
116684
|
import { execFile as execFileCb7 } from "node:child_process";
|
|
116588
116685
|
import { promisify as promisify7 } from "node:util";
|
|
116686
|
+
function transportIdentityEntries(entries) {
|
|
116687
|
+
return entries.map(({ path: path43, type, mode, size, contentDigest }) => ({
|
|
116688
|
+
path: path43,
|
|
116689
|
+
type,
|
|
116690
|
+
mode: mode & ~WRITE_BITS,
|
|
116691
|
+
size,
|
|
116692
|
+
contentDigest
|
|
116693
|
+
}));
|
|
116694
|
+
}
|
|
116695
|
+
function compareInstallToFrozenTransport(frozenEntries, installedEntries) {
|
|
116696
|
+
const frozen = transportIdentityEntries(frozenEntries);
|
|
116697
|
+
const installed = transportIdentityEntries(installedEntries);
|
|
116698
|
+
const installedByPath = new Map(installed.map((entry) => [entry.path, entry]));
|
|
116699
|
+
const conflicts = [];
|
|
116700
|
+
for (const frozenEntry of frozen) {
|
|
116701
|
+
const installedEntry = installedByPath.get(frozenEntry.path);
|
|
116702
|
+
if (!installedEntry) {
|
|
116703
|
+
conflicts.push(`missing: ${frozenEntry.path}`);
|
|
116704
|
+
continue;
|
|
116705
|
+
}
|
|
116706
|
+
if (installedEntry.type !== frozenEntry.type) {
|
|
116707
|
+
conflicts.push(`type mismatch: ${frozenEntry.path}`);
|
|
116708
|
+
} else if (installedEntry.size !== frozenEntry.size || installedEntry.contentDigest !== frozenEntry.contentDigest) {
|
|
116709
|
+
conflicts.push(`content mismatch: ${frozenEntry.path}`);
|
|
116710
|
+
} else if (installedEntry.mode !== frozenEntry.mode) {
|
|
116711
|
+
conflicts.push(`mode mismatch: ${frozenEntry.path}`);
|
|
116712
|
+
}
|
|
116713
|
+
}
|
|
116714
|
+
const frozenPaths = new Set(frozen.map((entry) => entry.path));
|
|
116715
|
+
for (const installedEntry of installed) {
|
|
116716
|
+
if (!frozenPaths.has(installedEntry.path)) {
|
|
116717
|
+
conflicts.push(`extra: ${installedEntry.path}`);
|
|
116718
|
+
}
|
|
116719
|
+
}
|
|
116720
|
+
return conflicts;
|
|
116721
|
+
}
|
|
116722
|
+
function frozenSnapshotRelativePath(unit, actions, unitId) {
|
|
116723
|
+
if (typeof unit?.frozenSnapshot?.path === "string" && unit.frozenSnapshot.path.length > 0) {
|
|
116724
|
+
return unit.frozenSnapshot.path;
|
|
116725
|
+
}
|
|
116726
|
+
const action = (actions ?? []).find((item) => item.unitId === unitId && typeof item.parameters?.snapshotPath === "string" && item.parameters.snapshotPath.length > 0);
|
|
116727
|
+
return action?.parameters?.snapshotPath ?? null;
|
|
116728
|
+
}
|
|
116589
116729
|
async function verifyCursorHostDistributions({
|
|
116590
116730
|
plan,
|
|
116591
116731
|
root,
|
|
@@ -118161,16 +118301,65 @@ async function verifyRelease(options) {
|
|
|
118161
118301
|
}
|
|
118162
118302
|
const pluginDistCount = (surface.unit?.distributions ?? []).filter((d) => d.type !== "npm").length;
|
|
118163
118303
|
if (pluginDistCount === 1 && surface.frozenPluginRoot === ".") {
|
|
118164
|
-
const
|
|
118165
|
-
|
|
118166
|
-
|
|
118167
|
-
|
|
118168
|
-
|
|
118169
|
-
|
|
118170
|
-
|
|
118171
|
-
|
|
118172
|
-
|
|
118173
|
-
|
|
118304
|
+
const frozenRel = frozenSnapshotRelativePath(surface.unit, actions, surface.unitId);
|
|
118305
|
+
if (frozenRel) {
|
|
118306
|
+
const frozenDir = await resolveFrozenPath(root, frozenRel, "frozen snapshot path");
|
|
118307
|
+
const frozenClosure = await checkSkillResourceClosure({
|
|
118308
|
+
snapshotDir: frozenDir,
|
|
118309
|
+
host: surface.host,
|
|
118310
|
+
surfaceHostBindings: [{ surfaceId: surface.surfaceId, host: surface.host }]
|
|
118311
|
+
});
|
|
118312
|
+
const frozenReceipt = createSkillResourceClosureReceipt(frozenClosure, {
|
|
118313
|
+
unitId: surface.unitId,
|
|
118314
|
+
preparedAt: expectedUnitReceipt.preparedAt ?? null,
|
|
118315
|
+
exitCode: expectedUnitReceipt.exitCode ?? 0
|
|
118316
|
+
});
|
|
118317
|
+
assertSkillResourceClosureReceipt(
|
|
118318
|
+
expectedUnitReceipt,
|
|
118319
|
+
frozenReceipt,
|
|
118320
|
+
`unit "${surface.unitId}"`
|
|
118321
|
+
);
|
|
118322
|
+
const frozenSnap = await computeFrozenSnapshot(frozenDir, {
|
|
118323
|
+
excludeRootEntries: TRANSPORT_EXCLUSIONS
|
|
118324
|
+
});
|
|
118325
|
+
const installedSnap = await computeFrozenSnapshot(surface.installPath, {
|
|
118326
|
+
excludeRootEntries: TRANSPORT_EXCLUSIONS
|
|
118327
|
+
});
|
|
118328
|
+
const conflicts = compareInstallToFrozenTransport(
|
|
118329
|
+
frozenSnap.entries,
|
|
118330
|
+
installedSnap.entries
|
|
118331
|
+
);
|
|
118332
|
+
await evidence.append({
|
|
118333
|
+
phase: "verify",
|
|
118334
|
+
step: "skill-resource-closure",
|
|
118335
|
+
status: "install-comparison",
|
|
118336
|
+
unitId: surface.unitId,
|
|
118337
|
+
frozenInputDigest: frozenSnap.digest,
|
|
118338
|
+
installedInputDigest: installedSnap.digest,
|
|
118339
|
+
frozenModes: frozenSnap.entries.map((entry) => ({ path: entry.path, mode: entry.mode })),
|
|
118340
|
+
installedModes: installedSnap.entries.map((entry) => ({ path: entry.path, mode: entry.mode }))
|
|
118341
|
+
});
|
|
118342
|
+
if (conflicts.length > 0) {
|
|
118343
|
+
const listed = conflicts.slice(0, PAYLOAD_CONFLICT_REPORT_CAP2).join("; ");
|
|
118344
|
+
const overflow = conflicts.length > PAYLOAD_CONFLICT_REPORT_CAP2 ? `; and ${conflicts.length - PAYLOAD_CONFLICT_REPORT_CAP2} more conflicting path(s)` : "";
|
|
118345
|
+
throw new ReleaseError(
|
|
118346
|
+
POST_PUBLISH_VERIFY_FAILED,
|
|
118347
|
+
`installed plugin root differs in path, bytes, size, or non-write mode bits for unit "${surface.unitId}": ${listed}${overflow}`,
|
|
118348
|
+
{ unitId: surface.unitId, conflicts }
|
|
118349
|
+
);
|
|
118350
|
+
}
|
|
118351
|
+
} else {
|
|
118352
|
+
const observedReceipt = createSkillResourceClosureReceipt(closureResult, {
|
|
118353
|
+
unitId: surface.unitId,
|
|
118354
|
+
preparedAt: expectedUnitReceipt.preparedAt ?? null,
|
|
118355
|
+
exitCode: expectedUnitReceipt.exitCode ?? 0
|
|
118356
|
+
});
|
|
118357
|
+
assertSkillResourceClosureReceipt(
|
|
118358
|
+
expectedUnitReceipt,
|
|
118359
|
+
observedReceipt,
|
|
118360
|
+
`unit "${surface.unitId}"`
|
|
118361
|
+
);
|
|
118362
|
+
}
|
|
118174
118363
|
}
|
|
118175
118364
|
}
|
|
118176
118365
|
skillResourceClosureReceipts.push(createSkillResourceClosureReceipt(
|
|
@@ -118381,7 +118570,7 @@ async function verifyRelease(options) {
|
|
|
118381
118570
|
throw err;
|
|
118382
118571
|
}
|
|
118383
118572
|
}
|
|
118384
|
-
var execFile6, VERIFICATION_RESOLVED_TYPES, ADAPTER_ACTION_TYPE_MAP2, FIRST_RELEASE_BOOTSTRAP_MODE, EXTERNAL_MARKETPLACE_SHA_RE2, defaultNpmExecutor;
|
|
118573
|
+
var execFile6, VERIFICATION_RESOLVED_TYPES, WRITE_BITS, PAYLOAD_CONFLICT_REPORT_CAP2, ADAPTER_ACTION_TYPE_MAP2, FIRST_RELEASE_BOOTSTRAP_MODE, EXTERNAL_MARKETPLACE_SHA_RE2, defaultNpmExecutor;
|
|
118385
118574
|
var init_verify = __esm({
|
|
118386
118575
|
async "src/commands/verify.mjs"() {
|
|
118387
118576
|
init_src2();
|
|
@@ -118419,6 +118608,11 @@ var init_verify = __esm({
|
|
|
118419
118608
|
PASSED_MANUAL: "PASSED_MANUAL",
|
|
118420
118609
|
NOT_REQUIRED_UNCHANGED: "NOT_REQUIRED_UNCHANGED"
|
|
118421
118610
|
});
|
|
118611
|
+
WRITE_BITS = 146;
|
|
118612
|
+
PAYLOAD_CONFLICT_REPORT_CAP2 = 10;
|
|
118613
|
+
__name(transportIdentityEntries, "transportIdentityEntries");
|
|
118614
|
+
__name(compareInstallToFrozenTransport, "compareInstallToFrozenTransport");
|
|
118615
|
+
__name(frozenSnapshotRelativePath, "frozenSnapshotRelativePath");
|
|
118422
118616
|
__name(verifyCursorHostDistributions, "verifyCursorHostDistributions");
|
|
118423
118617
|
__name(verifyPublicSourceAuthorityReceiptOffline, "verifyPublicSourceAuthorityReceiptOffline");
|
|
118424
118618
|
ADAPTER_ACTION_TYPE_MAP2 = {
|
|
@@ -139649,7 +139843,7 @@ async function observeQoderPlugin(target, command2, env, run6) {
|
|
|
139649
139843
|
found
|
|
139650
139844
|
};
|
|
139651
139845
|
}
|
|
139652
|
-
async function readQoderManifest(root, label) {
|
|
139846
|
+
async function readQoderManifest(root, label, target) {
|
|
139653
139847
|
const candidates = [];
|
|
139654
139848
|
for (const manifestPath of [".qoder-plugin/plugin.json", ".claude-plugin/plugin.json"]) {
|
|
139655
139849
|
let text;
|
|
@@ -139663,10 +139857,11 @@ async function readQoderManifest(root, label) {
|
|
|
139663
139857
|
if (!manifest || typeof manifest !== "object" || Array.isArray(manifest)) {
|
|
139664
139858
|
throw new Error(`${label} (${manifestPath}) did not return an object`);
|
|
139665
139859
|
}
|
|
139860
|
+
await assertQoderPluginManifest(target, manifest, `${label} (${manifestPath})`, root);
|
|
139666
139861
|
candidates.push({ manifestPath, manifest });
|
|
139667
139862
|
}
|
|
139668
139863
|
if (candidates.length === 0) throw new Error(`${label} has no native or compatible plugin manifest`);
|
|
139669
|
-
if (candidates.length === 2 && ["name", "version"
|
|
139864
|
+
if (candidates.length === 2 && ["name", "version"].some((field) => candidates[0].manifest[field] !== candidates[1].manifest[field])) {
|
|
139670
139865
|
throw new Error(`${label} does not match the frozen Qoder plugin identity and projection path: conflicting native and compatible manifests`);
|
|
139671
139866
|
}
|
|
139672
139867
|
return candidates[0];
|
|
@@ -139687,26 +139882,43 @@ async function assertFrozenQoderManifest(target, root) {
|
|
|
139687
139882
|
snapshotPath: target.snapshotPath,
|
|
139688
139883
|
expectedDigest: target.manifestDigest
|
|
139689
139884
|
});
|
|
139690
|
-
const { manifestPath, manifest } = await readQoderManifest(snapshotRoot, "frozen Qoder plugin manifest");
|
|
139885
|
+
const { manifestPath, manifest } = await readQoderManifest(snapshotRoot, "frozen Qoder plugin manifest", target);
|
|
139691
139886
|
const skills = await assertQoderPluginManifest(target, manifest, "frozen Qoder plugin manifest", snapshotRoot);
|
|
139692
139887
|
return { manifestPath, skills };
|
|
139693
139888
|
}
|
|
139694
139889
|
async function assertQoderHubEntry(target, marketplaceRoot) {
|
|
139695
|
-
|
|
139696
|
-
|
|
139697
|
-
|
|
139698
|
-
|
|
139699
|
-
|
|
139700
|
-
|
|
139701
|
-
|
|
139702
|
-
|
|
139703
|
-
|
|
139704
|
-
|
|
139705
|
-
|
|
139706
|
-
|
|
139707
|
-
|
|
139708
|
-
|
|
139890
|
+
let found = false;
|
|
139891
|
+
for (const indexPath of ["marketplace.json", ".claude-plugin/marketplace.json"]) {
|
|
139892
|
+
let text;
|
|
139893
|
+
try {
|
|
139894
|
+
text = await readFileContained(marketplaceRoot, indexPath, { encoding: "utf8" });
|
|
139895
|
+
} catch (error) {
|
|
139896
|
+
if (error?.code === "SFC2004" && error?.details?.kind === "missing-resource") continue;
|
|
139897
|
+
throw error;
|
|
139898
|
+
}
|
|
139899
|
+
found = true;
|
|
139900
|
+
const marketplace = parseJson2(text, `Qoder Hub marketplace manifest (${indexPath})`);
|
|
139901
|
+
if (!marketplace || typeof marketplace !== "object" || Array.isArray(marketplace) || marketplace.name !== target.marketplace || !Array.isArray(marketplace.plugins)) {
|
|
139902
|
+
throw new Error("Qoder Hub marketplace manifest does not match the frozen marketplace");
|
|
139903
|
+
}
|
|
139904
|
+
if (indexPath === ".claude-plugin/marketplace.json") {
|
|
139905
|
+
if (target.hub.githubHost !== "github.com" || typeof target.frozenTag !== "string" || target.frozenTag.length === 0) {
|
|
139906
|
+
throw new Error("Qoder compatible Hub entry requires a frozen GitHub tag identity");
|
|
139907
|
+
}
|
|
139908
|
+
await assertHubHostEntry({ ...target, host: "claude", pluginTag: target.frozenTag, githubHost: target.hub.githubHost }, marketplaceRoot);
|
|
139909
|
+
continue;
|
|
139910
|
+
}
|
|
139911
|
+
const matches = marketplace.plugins.filter((entry2) => entry2?.name === target.plugin);
|
|
139912
|
+
if (matches.length !== 1) {
|
|
139913
|
+
throw new Error(`Qoder Hub marketplace manifest must contain exactly one ${target.plugin} entry`);
|
|
139914
|
+
}
|
|
139915
|
+
const entry = matches[0];
|
|
139916
|
+
const source = entry.source;
|
|
139917
|
+
if (source?.source !== "url" || normalizeHubGitSource(source.url, target.hub.githubHost) !== target.pluginRepo || source.sha !== target.pluginCommit || entry.version !== void 0 && entry.version !== target.version || source.ref !== void 0 && (typeof target.frozenTag !== "string" || source.ref !== target.frozenTag)) {
|
|
139918
|
+
throw new Error("Qoder Hub entry does not match the frozen public source identity");
|
|
139919
|
+
}
|
|
139709
139920
|
}
|
|
139921
|
+
if (!found) throw new Error("Qoder Hub has no native or compatible marketplace manifest");
|
|
139710
139922
|
}
|
|
139711
139923
|
async function verifyQoderInstalledPayload({
|
|
139712
139924
|
target,
|
|
@@ -139715,7 +139927,7 @@ async function verifyQoderInstalledPayload({
|
|
|
139715
139927
|
frozenManifest,
|
|
139716
139928
|
verifyInstalledPayload
|
|
139717
139929
|
}) {
|
|
139718
|
-
const { manifestPath, manifest } = await readQoderManifest(installPath, "installed Qoder plugin manifest");
|
|
139930
|
+
const { manifestPath, manifest } = await readQoderManifest(installPath, "installed Qoder plugin manifest", target);
|
|
139719
139931
|
if (manifestPath !== frozenManifest.manifestPath) {
|
|
139720
139932
|
throw new Error("installed Qoder plugin manifest path differs from the frozen manifest selection");
|
|
139721
139933
|
}
|
|
@@ -17,6 +17,10 @@
|
|
|
17
17
|
"digest": "86c9cab024ebe9c7f8ec3358fcc12d05b8ed246ab59da2b0acc6a517f31274ea",
|
|
18
18
|
"bytes": 2488
|
|
19
19
|
},
|
|
20
|
+
"evidence-event-v2.schema.json": {
|
|
21
|
+
"digest": "693430e636afc85bf4a79e3f7bf3fb87254cbd62f2e3f35c35d6f84e5e8e0be1",
|
|
22
|
+
"bytes": 6058
|
|
23
|
+
},
|
|
20
24
|
"evidence-event.schema.json": {
|
|
21
25
|
"digest": "b7e14522a5aba818cab191545f23d2323be0e4c80566e9d3e4da576103a00490",
|
|
22
26
|
"bytes": 2390
|
|
@@ -34,8 +38,8 @@
|
|
|
34
38
|
"bytes": 57111
|
|
35
39
|
},
|
|
36
40
|
"release-run.schema.json": {
|
|
37
|
-
"digest": "
|
|
38
|
-
"bytes":
|
|
41
|
+
"digest": "26c44ddf1ed42f266a2ddee7f6132cee94c59593e37f24359c9c48f12612ec22",
|
|
42
|
+
"bytes": 21874
|
|
39
43
|
},
|
|
40
44
|
"test-intake.schema.json": {
|
|
41
45
|
"digest": "654e91ce518cb2b8aca84947d0c3bb8c4262ab047d86081e7e93dc07a9c6c739",
|
|
@@ -7,36 +7,29 @@ description: "Config-only workflow profile: route confirms config-only diff, ass
|
|
|
7
7
|
|
|
8
8
|
## 触发
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
用户发起仅配置变更的发布流程,涉及 `.release-skill/project.yaml`、配置 schema、`releaseUnits` 映射、`policy` 策略定义等配置文件的修改,且无代码、文档或 marketplace 变更。
|
|
11
11
|
|
|
12
12
|
## 当前状态
|
|
13
13
|
|
|
14
|
-
`release-config`
|
|
14
|
+
`release-config` 是工作流配置文件(§4)定义的独立工作流之一,专门处理仅配置变更场景。其遵循简化生命周期,专注于配置验证与发布路径决策分支。
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
per-unit `snapshotDigest` 与最新冻结 plan——公开字节未变 → `publishPath:
|
|
18
|
-
'no-publish-needed'`(externalActions 被移除,无 publish 路径);字节变化或无对比
|
|
19
|
-
plan → `publishPath: 'publish-needed'`(fail-safe)。决策以 `workflowDecision` 绑定
|
|
20
|
-
进 plan digest,不可篡改。**不存在** `NO_PUBLISH_NEEDED`/`REPORTED` 虚构状态:
|
|
21
|
-
prepare 的真实输出是 plan 内的 `workflowDecision`。
|
|
16
|
+
**机械实现**:`prepare --workflow config` 确定性地裁剪代码类门禁(H5),并比较当前 per-unit `snapshotDigest` 与最新冻结 plan——公开字节未变 → `publishPath: 'no-publish-needed'`(`externalActions` 被移除,无 publish 路径);字节变化或无对比 plan → `publishPath: 'publish-needed'`(fail-safe)。决策以 `workflowDecision` 绑定进 plan digest,不可篡改。**不存在** `NO_PUBLISH_NEEDED`/`REPORTED` 虚构状态:prepare 的真实输出是 plan 内的 `workflowDecision`。
|
|
22
17
|
|
|
23
18
|
**边界**:裁剪代码类检查(declared hooks、snapshot-verify gates、skill-resource-closure),保留基线、快照、计划冻结和文档新鲜度检查。来源权威检查按发布分支决定,不能一并裁掉:
|
|
24
19
|
|
|
25
|
-
-
|
|
26
|
-
-
|
|
20
|
+
- **场景 A**:公开字节未变,`externalActions=[]`,不生成 `plan.sourceAuthority`(冻结的源码来源权威),也不进入 approve/publish/verify。即使配置了公开来源收据,这一边界也不变。
|
|
21
|
+
- **场景 B**:公开字节变化或不可判定,需要发布。production prepare 必须通过现有来源权威检查并冻结 `plan.sourceAuthority`;publish、reconcile、verify 继续校验冻结绑定和远端一致性,consumer-verify 保留。
|
|
27
22
|
|
|
28
23
|
旧 production 计划缺少 `sourceAuthority` 时,仍在外部写入前拒绝。未发生外部写入的旧计划必须重新 prepare 并批准新摘要,不补字段、不迁移旧批准。已有 `PARTIAL` 保留检查点,走匹配版本的恢复路径。docs production 同样要求来源权威;marketplace 委托目标工作区发布的边界不变。
|
|
29
24
|
|
|
30
25
|
## 职责与边界
|
|
31
26
|
|
|
32
|
-
- **步骤① diff 确认 config-only
|
|
33
|
-
- **步骤② assess with schema validation
|
|
34
|
-
- **步骤③ prepare --workflow config
|
|
35
|
-
- **步骤④ decision branch**(来自 plan.workflowDecision
|
|
36
|
-
-
|
|
37
|
-
|
|
38
|
-
- 场景 B:`publishPath === 'publish-needed'`(公开 surface 变化或不可判定)→ 运行
|
|
39
|
-
轻链 (approve→publish→verify)
|
|
27
|
+
- **步骤① diff 确认 config-only**:调用 `release-skill route` 命令确认仅有配置变更
|
|
28
|
+
- **步骤② assess with schema validation**:执行配置结构验证、schema 检查、contract 一致性
|
|
29
|
+
- **步骤③ prepare --workflow config**:本地 freeze 检查,生成只读计划;输出 `workflowDecision`
|
|
30
|
+
- **步骤④ decision branch**(来自 plan.workflowDecision):
|
|
31
|
+
- **场景 A**:`publishPath === 'no-publish-needed'`(公开字节未变化)→ 记录决策并结束,无 publish 路径,不运行 approve/publish/verify
|
|
32
|
+
- **场景 B**:`publishPath === 'publish-needed'`(公开 surface 变化或不可判定)→ 运行轻链(approve→publish→verify)
|
|
40
33
|
|
|
41
34
|
存量增量只改本轮目标映射。已有合法字段、历史发行记录与精确授权保持不变,不要重建 `.release-skill/project.yaml`。
|
|
42
35
|
|
|
@@ -44,25 +37,27 @@ prepare 的真实输出是 plan 内的 `workflowDecision`。
|
|
|
44
37
|
|
|
45
38
|
`delivery.include/exclude` 不是文件包含或排除。排除不得覆盖 `requiredPublicFiles`。互相冲突的配置必须失败关闭。Foundation 建议不能作为发布批准。未经精确批准不产生远端动作。分类文字不会机械识别全部私有内容。接入评估缺失码 `REQUIRED_PUBLIC_FILE_MISSING` 不属于本技能的 prepare 路径;config-only prepare 仍走 `release-prepare` 原生错误。
|
|
46
39
|
|
|
47
|
-
|
|
40
|
+
**授权边界**:命令调用本身即授权执行配置的 hooks/gates。config-only 工作流的远程写操作受标准 approval 机制约束,不 bypass 安全 gate。
|
|
48
41
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
42
|
+
**接入选择**:进入本入口的新一轮生产准备前,必须按 `release-prepare` 同一完整流程核对 `testIntake`。若缺失,须说明缺项并默认推动 `skill-family-test:skill-family-test-plan`,再在授权范围内调用 `skill-family-test:skill-family-test-run`,由 TEST 组织检查并交回结果。跳过须先明确征询,再依据本轮适用且范围匹配的明确同意决定。**沉默、拒绝、仅普通发布预授权、旧轮次、其他项目、版本或范围不匹配均不可跳过**。本轮匹配答复可复用。**不得把跳过写成测试已达标,也不得用跳过清除已声明的适用要求**。已冻结计划的批准、发布、对账与正式验证不回头追加接入义务。只读和非生产准备不新增接入义务。直接非交互 CLI 仍接受可选 `testIntake`,不新增选择参数。答复与适用范围记入既有任务或执行计划。
|
|
43
|
+
|
|
44
|
+
**阶段通过规则**:
|
|
45
|
+
- **场景 A**:prepare 输出 `workflowDecision.decision === 'public-bytes-unchanged'`(无 publish 路径)
|
|
46
|
+
- **场景 B**:`status === 'VERIFIED'` + CLI exit code 0
|
|
52
47
|
|
|
53
48
|
## 正向执行路径
|
|
54
49
|
|
|
55
|
-
1. 运行 `release-skill route --root <path> [--target-version <ver>] --json` 获取 diff
|
|
50
|
+
1. 运行 `release-skill route --root <path> [--target-version <ver>] --json` 获取 diff 分类;已知目标版本时显式传入,`route` 只是工作流建议
|
|
56
51
|
2. 若推荐 `workflowKind === 'config-only'`,则使用本技能
|
|
57
52
|
3. 执行步骤②:运行 `release-skill assess --root <path> --offline --json` 进行 schema validation
|
|
58
|
-
4.
|
|
59
|
-
5.
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
- **B
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
53
|
+
4. 进入本入口新一轮生产准备前完成接入选择:按 `release-prepare` 同一完整流程核对 `testIntake`,默认推动 `skill-family-test:skill-family-test-plan` 与授权范围内的 `skill-family-test-run`。跳过须先明确征询再依据本轮匹配答复决定。未完成接入且无有效跳过时,不进入下一步 `prepare`。该分支只决定后续是否进入发布链,不改变生产 prepare 前的测试接入要求。
|
|
54
|
+
5. 执行步骤③:运行 `release-skill prepare --offline --workflow config --target-version <ver> --json`
|
|
55
|
+
6. 读取输出中的 `workflowDecision`:
|
|
56
|
+
- **A**:`publishPath === 'no-publish-needed'` → 记录决策(plan 已冻结,无 `externalActions`),结束。无需 approve/publish/verify
|
|
57
|
+
- **B**:`publishPath === 'publish-needed'` → 继续 approve → publish → verify 链条
|
|
58
|
+
7. (场景 B 续)执行步骤⑥:运行 `release-skill approve --plan <path> --actor <name>`
|
|
59
|
+
8. (场景 B 续)执行步骤⑦:运行 `release-skill publish --plan <path> --approval <path>`
|
|
60
|
+
9. (场景 B 续)执行步骤⑧:运行 `release-skill verify --plan <path> --run <path> --json`
|
|
66
61
|
|
|
67
62
|
## 确定性脚本调用
|
|
68
63
|
|
|
@@ -135,21 +130,21 @@ node "${CLAUDE_PLUGIN_ROOT}/bin/release-skill.mjs" verify \
|
|
|
135
130
|
|
|
136
131
|
## 与其他工作流的关系
|
|
137
132
|
|
|
138
|
-
- **docs-only
|
|
139
|
-
- **marketplace-only
|
|
140
|
-
- **full-happy-end
|
|
133
|
+
- **docs-only**:纯文档变更时使用 `release-docs`
|
|
134
|
+
- **marketplace-only**:仅 marketplace 变更时使用独立工作流
|
|
135
|
+
- **full-happy-end**:混合变更(code+config+docs)时降级到此完整路径
|
|
141
136
|
|
|
142
137
|
## 关联技能
|
|
143
138
|
|
|
144
|
-
- `release-skill route
|
|
145
|
-
- `release-assess
|
|
146
|
-
- `release-prepare
|
|
147
|
-
- `release-approve
|
|
148
|
-
- `release-publish
|
|
149
|
-
- `release-verify
|
|
139
|
+
- `release-skill route`:快速入门决策路由(§4.3)
|
|
140
|
+
- `release-assess`:配置 schema/contract 验证入口
|
|
141
|
+
- `release-prepare`:离线冻结检查(`--workflow config` 输出 publish-path 决策)
|
|
142
|
+
- `release-approve`:Plan approval(仅场景 B)
|
|
143
|
+
- `release-publish`:制品发布(仅在 public surface 变化时执行)
|
|
144
|
+
- `release-verify`:消费者验证(场景 B 的最终验证门)
|
|
150
145
|
|
|
151
146
|
## 人类最终回复
|
|
152
147
|
|
|
153
148
|
纯问询或转交时短答:写明实际回答、适用范围或理由、必要限制和下一步。建议保持为建议。
|
|
154
149
|
|
|
155
|
-
执行路径说明实际分支、已完成步骤、未执行步骤,以及既有计划、`workflowDecision` 产物和限制。`publishPath` 为 `no-publish-needed` 时按原合同结束,无发布路径。场景 B 只写入已经执行的 approve、publish、verify 结果。已有文件输出按原合同呈现。栏目只收录当前命令或分支已经返回的事实。
|
|
150
|
+
执行路径说明实际分支、已完成步骤、未执行步骤,以及既有计划、`workflowDecision` 产物和限制。`publishPath` 为 `no-publish-needed` 时按原合同结束,无发布路径。场景 B 只写入已经执行的 approve、publish、verify 结果。已有文件输出按原合同呈现。栏目只收录当前命令或分支已经返回的事实。
|