release-skill 0.8.1 → 0.9.0

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.
Files changed (66) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.codebuddy-plugin/plugin.json +1 -1
  4. package/.codex-plugin/plugin.json +2 -2
  5. package/.kimi-plugin/plugin.json +1 -1
  6. package/CHANGELOG.md +31 -0
  7. package/INSTALL.md +14 -2
  8. package/INSTALL.zh-CN.md +12 -2
  9. package/README.md +28 -16
  10. package/README.zh-CN.md +23 -14
  11. package/adapters/claude/.claude-plugin/marketplace.json +1 -1
  12. package/adapters/claude/.claude-plugin/plugin.json +1 -1
  13. package/adapters/claude/bin/release-skill-local-finish.mjs +4 -0
  14. package/adapters/claude/bin/release-skill.bundle.mjs +2416 -1320
  15. package/adapters/claude/schemas/release-plan.schema.json +40 -3
  16. package/adapters/claude/skills/release-finish/SKILL.md +65 -0
  17. package/adapters/claude/skills/release-verify/SKILL.md +6 -1
  18. package/adapters/codex/.codex-plugin/plugin.json +2 -2
  19. package/adapters/codex/bin/release-skill-local-finish.mjs +4 -0
  20. package/adapters/codex/bin/release-skill.bundle.mjs +2416 -1320
  21. package/adapters/codex/schemas/release-plan.schema.json +40 -3
  22. package/adapters/codex/skills/release-finish/SKILL.md +72 -0
  23. package/adapters/codex/skills/release-verify/SKILL.md +6 -1
  24. package/adapters/kimi/.kimi-plugin/plugin.json +1 -1
  25. package/adapters/kimi/bin/release-skill-local-finish.mjs +4 -0
  26. package/adapters/kimi/bin/release-skill.bundle.mjs +2416 -1320
  27. package/adapters/kimi/schemas/release-plan.schema.json +40 -3
  28. package/adapters/kimi/skills/release-finish/SKILL.md +72 -0
  29. package/adapters/kimi/skills/release-verify/SKILL.md +6 -1
  30. package/adapters/workbuddy/.codebuddy-plugin/plugin.json +1 -1
  31. package/adapters/workbuddy/bin/release-skill-local-finish.mjs +4 -0
  32. package/adapters/workbuddy/bin/release-skill.bundle.mjs +2416 -1320
  33. package/adapters/workbuddy/schemas/release-plan.schema.json +40 -3
  34. package/adapters/workbuddy/skills/release-finish/SKILL.md +65 -0
  35. package/adapters/workbuddy/skills/release-verify/SKILL.md +6 -1
  36. package/bin/release-skill-cli.mjs +126 -1
  37. package/bin/release-skill-local-finish.mjs +4 -0
  38. package/bin/release-skill.bundle.mjs +2416 -1320
  39. package/package.json +1 -1
  40. package/platform-manifest.json +30 -4
  41. package/schemas/release-plan.schema.json +40 -3
  42. package/skills/release-finish/SKILL.md +65 -0
  43. package/skills/release-verify/SKILL.md +6 -1
  44. package/skills-src/release-finish/SKILL.md +65 -0
  45. package/skills-src/release-verify/SKILL.md +6 -1
  46. package/src/commands/approve.mjs +14 -2
  47. package/src/commands/distribute.mjs +562 -321
  48. package/src/commands/post-release-local.mjs +611 -0
  49. package/src/commands/postverify.mjs +262 -155
  50. package/src/commands/prepare.mjs +67 -52
  51. package/src/commands/publish.mjs +11 -10
  52. package/src/commands/reconcile.mjs +11 -10
  53. package/src/commands/setup.mjs +26 -13
  54. package/src/commands/ship.mjs +45 -12
  55. package/src/commands/verify.mjs +19 -8
  56. package/src/core/adoption-assessment.mjs +0 -3
  57. package/src/core/approval.mjs +11 -8
  58. package/src/core/hooks.mjs +0 -16
  59. package/src/core/plan.mjs +19 -11
  60. package/src/core/postpublish-approval.mjs +12 -2
  61. package/src/core/postpublish-bundle.mjs +51 -13
  62. package/src/core/postpublish.mjs +146 -6
  63. package/src/core/preset-executor.mjs +53 -0
  64. package/src/core/proposal-inbox.mjs +91 -27
  65. package/src/core/recovery.mjs +27 -12
  66. package/src/producers/build-adapters.mjs +10 -1
@@ -33,7 +33,7 @@ import { validatePlan, computePlanDigest, assertImmutablePlanAuthority } from '.
33
33
  import { validateApproval, validateApprovalRecordSchema, assertImmutableApprovalAuthority, computeApprovalDigest } from './approval.mjs';
34
34
  import { isMarketplaceAction } from './checkpoints.mjs';
35
35
  import { ReleaseError, GATE_FAILED } from './errors.mjs';
36
- import { effectiveHookRequiresApproval } from './postpublish.mjs';
36
+ import { effectiveHookRequiresApproval, normalizePostPublishView, postPublishActionId } from './postpublish.mjs';
37
37
  import { assertPostPublishApprovalAuthority, validatePostPublishApproval } from './postpublish-approval.mjs';
38
38
 
39
39
  /** Remote errors alone are insufficient to select a safe recovery phase. */
@@ -194,12 +194,18 @@ export async function readRunRecovery(runPath, options = {}) {
194
194
  throw new ReleaseError(GATE_FAILED, 'distribute recovery requires its same-lineage PUBLISHED publication');
195
195
  }
196
196
  // Mapping only: the common 1:1 checkpoint validator remains authoritative.
197
- const actions = (plan.postPublish?.targets ?? []).flatMap((target) => [
198
- { id: `probe-${target.id}`, type: 'distribute-probe' },
199
- { id: target.id, type: 'distribute-mirror' },
200
- ]).concat((plan.postPublish?.hooks ?? [])
201
- .filter((hook) => hook.phase !== 'postVerify')
202
- .map((hook) => ({ id: hook.id, type: 'postpublish-hook' })));
197
+ // §4.3 unified normalization: per-declaration mapping through the shared
198
+ // action-id derivation so v3 checkpoint ids (unitId/localId) match the
199
+ // executed records exactly; legacy plans resolve to the same bare ids.
200
+ const actions = normalizePostPublishView(plan).flatMap((declaration) => [
201
+ ...(declaration.targets ?? []).flatMap((target) => [
202
+ { id: postPublishActionId({ planVersion: plan.planVersion, unitId: declaration.unitId, localId: `probe-${target.id}` }), type: 'distribute-probe' },
203
+ { id: postPublishActionId({ planVersion: plan.planVersion, unitId: declaration.unitId, localId: target.id }), type: 'distribute-mirror' },
204
+ ]),
205
+ ...(declaration.hooks ?? [])
206
+ .filter((hook) => hook.phase !== 'postVerify')
207
+ .map((hook) => ({ id: postPublishActionId({ planVersion: plan.planVersion, unitId: declaration.unitId, localId: hook.id }), type: 'postpublish-hook' })),
208
+ ]);
203
209
  // A preflight BLOCKED record may precede checkpoint initialization.
204
210
  if (!(run.status === 'BLOCKED' && run.checkpoints.length === 0)) {
205
211
  validateRunCheckpointMapping(run, actions);
@@ -268,8 +274,11 @@ export async function readRunRecovery(runPath, options = {}) {
268
274
  }
269
275
  } else if (['publish', 'reconcile'].includes(command)) {
270
276
  if (run.status === 'PUBLISHED') {
271
- const needsDistribution = (plan.postPublish?.targets?.length ?? 0) > 0
272
- || (plan.postPublish?.hooks?.length ?? 0) > 0;
277
+ // §4.3 unified normalization: v3 empty arrays mean no distribute work
278
+ // at all; only declarations carrying targets or hooks require the
279
+ // distribution phase.
280
+ const needsDistribution = normalizePostPublishView(plan).some((declaration) =>
281
+ (declaration.targets?.length ?? 0) > 0 || (declaration.hooks?.length ?? 0) > 0);
273
282
  code = needsDistribution ? 'DISTRIBUTE' : 'VERIFY';
274
283
  } else if (run.status === 'PARTIAL') {
275
284
  code = 'RECONCILE';
@@ -280,9 +289,15 @@ export async function readRunRecovery(runPath, options = {}) {
280
289
  } else code = 'DIAGNOSE';
281
290
 
282
291
  if (code === 'DISTRIBUTE') {
283
- const pendingApprovals = (plan.postPublish?.hooks ?? []).filter((hook) => hook.phase !== 'postVerify'
284
- && effectiveHookRequiresApproval(hook)
285
- && !(run.command === 'distribute' && run.checkpoints.some((cp) => cp.actionId === hook.id && completed(cp))));
292
+ // §4.3 unified normalization: approval gating resolves declared hooks
293
+ // across all declarations; checkpoint match uses the shared action-id
294
+ // derivation so a v3 record (unitId/hookId) counts as completed.
295
+ const pendingApprovals = normalizePostPublishView(plan).flatMap((declaration) =>
296
+ (declaration.hooks ?? [])
297
+ .filter((hook) => hook.phase !== 'postVerify' && effectiveHookRequiresApproval(hook))
298
+ .filter((hook) => !(run.command === 'distribute' && run.checkpoints.some((cp) =>
299
+ cp.actionId === postPublishActionId({ planVersion: plan.planVersion, unitId: declaration.unitId, localId: hook.id })
300
+ && completed(cp)))));
286
301
  if (pendingApprovals.length > 0) {
287
302
  try {
288
303
  const approved = new Set();
@@ -371,9 +371,17 @@ function renderSkillForPlatform(content, platformName) {
371
371
  const hostLabel = platformName === 'codex' ? 'Codex' : 'Kimi';
372
372
  const preamble = platformName === 'codex' ? CODEX_PREAMBLE : KIMI_PREAMBLE;
373
373
  let rendered = content.replaceAll(
374
+ '${CLAUDE_PLUGIN_ROOT}/bin/release-skill-local-finish.mjs',
375
+ '$RELEASE_SKILL_LOCAL_FINISH_ENTRY',
376
+ ).replaceAll(
374
377
  '${CLAUDE_PLUGIN_ROOT}/bin/release-skill.mjs',
375
378
  '$RELEASE_SKILL_ENTRY',
376
379
  );
380
+ const renderedPreamble = rendered.includes('$RELEASE_SKILL_LOCAL_FINISH_ENTRY')
381
+ ? preamble
382
+ .replaceAll('RELEASE_SKILL_ENTRY', 'RELEASE_SKILL_LOCAL_FINISH_ENTRY')
383
+ .replaceAll('release-skill.mjs', 'release-skill-local-finish.mjs')
384
+ : preamble;
377
385
  // A remaining bare host-root reference has no safe path-derived equivalent.
378
386
  if (rendered.includes('${CLAUDE_PLUGIN_ROOT}')) {
379
387
  throw new Error(`${hostLabel} rendering found an unsupported bare CLAUDE_PLUGIN_ROOT reference`);
@@ -385,7 +393,7 @@ function renderSkillForPlatform(content, platformName) {
385
393
  throw new Error(`${hostLabel} rendering requires a valid leading YAML frontmatter block`);
386
394
  }
387
395
  const insertionPoint = frontmatterEnd + '\n---\n'.length;
388
- return `${rendered.slice(0, insertionPoint)}\n${preamble}${rendered.slice(insertionPoint)}`;
396
+ return `${rendered.slice(0, insertionPoint)}\n${renderedPreamble}${rendered.slice(insertionPoint)}`;
389
397
  }
390
398
 
391
399
  return content;
@@ -527,6 +535,7 @@ async function generateAdapterFiles(platform, skills, templateJson, root, market
527
535
 
528
536
  const HOST_BIN_FILES = new Set([
529
537
  'release-skill.mjs',
538
+ 'release-skill-local-finish.mjs',
530
539
  'release-skill.bundle.mjs',
531
540
  'release-skill-cli.mjs',
532
541
  'foundation-resource-binding.json',