release-skill 0.2.1 → 0.2.2

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 (54) 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 +21 -0
  7. package/INSTALL.md +183 -21
  8. package/INSTALL.zh-CN.md +160 -16
  9. package/README.md +112 -11
  10. package/README.zh-CN.md +73 -10
  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.bundle.mjs +1718 -600
  14. package/adapters/claude/schemas/release-plan.schema.json +44 -2
  15. package/adapters/claude/schemas/release-project.schema.json +46 -4
  16. package/adapters/claude/schemas/release-run.schema.json +1 -0
  17. package/adapters/codex/.codex-plugin/plugin.json +2 -2
  18. package/adapters/codex/bin/release-skill.bundle.mjs +1718 -600
  19. package/adapters/codex/schemas/release-plan.schema.json +44 -2
  20. package/adapters/codex/schemas/release-project.schema.json +46 -4
  21. package/adapters/codex/schemas/release-run.schema.json +1 -0
  22. package/adapters/kimi/.kimi-plugin/plugin.json +1 -1
  23. package/adapters/kimi/bin/release-skill.bundle.mjs +1718 -600
  24. package/adapters/kimi/schemas/release-plan.schema.json +44 -2
  25. package/adapters/kimi/schemas/release-project.schema.json +46 -4
  26. package/adapters/kimi/schemas/release-run.schema.json +1 -0
  27. package/adapters/workbuddy/.codebuddy-plugin/plugin.json +4 -2
  28. package/adapters/workbuddy/bin/release-skill.bundle.mjs +1718 -600
  29. package/adapters/workbuddy/schemas/release-plan.schema.json +44 -2
  30. package/adapters/workbuddy/schemas/release-project.schema.json +46 -4
  31. package/adapters/workbuddy/schemas/release-run.schema.json +1 -0
  32. package/bin/release-skill-cli.mjs +46 -4
  33. package/bin/release-skill.bundle.mjs +1718 -600
  34. package/package.json +1 -1
  35. package/references/02-project-config.md +7 -0
  36. package/references/06-adapter-contract.md +21 -2
  37. package/schemas/release-plan.schema.json +44 -2
  38. package/schemas/release-project.schema.json +46 -4
  39. package/schemas/release-run.schema.json +1 -0
  40. package/scripts/sync-public-files.mjs +8 -4
  41. package/src/adapters/contract.mjs +1 -0
  42. package/src/adapters/plugin-marketplace.mjs +536 -23
  43. package/src/commands/assess.mjs +50 -1
  44. package/src/commands/prepare.mjs +273 -9
  45. package/src/commands/publish.mjs +1 -0
  46. package/src/commands/reconcile.mjs +1 -0
  47. package/src/commands/setup.mjs +7 -3
  48. package/src/commands/verify.mjs +2 -0
  49. package/src/core/checkpoints.mjs +7 -2
  50. package/src/core/plan.mjs +97 -4
  51. package/src/core/verification-gates.mjs +1 -1
  52. package/src/platforms/codebuddy.mjs +618 -0
  53. package/src/platforms/registry.mjs +100 -5
  54. package/src/producers/build-adapters.mjs +21 -13
package/src/core/plan.mjs CHANGED
@@ -776,6 +776,19 @@ export function validatePlanActionCompleteness(plan, options = {}) {
776
776
  );
777
777
  }
778
778
 
779
+ // External independent marketplace form: the distribution declares
780
+ // marketplaceRepo, so the install targets the external marketplace
781
+ // repository instead of publicRepo. Only platforms with a marketplace
782
+ // add capability (marketplaceRefForm !== null: claude=name, codex=sha)
783
+ // may carry it; kimi/codebuddy fail closed. Inline form (no
784
+ // marketplaceRepo) keeps every assertion below byte-for-byte.
785
+ const externalMarketplace = dist.marketplaceRepo !== undefined && dist.marketplaceRepo !== null;
786
+ if (externalMarketplace && platform.marketplaceRefForm === null) {
787
+ failures.push(
788
+ `unit "${unitId}", action "${action.id}": ${platform.distributionType} distribution declares marketplaceRepo but the platform has no marketplace add capability`,
789
+ );
790
+ }
791
+
779
792
  // Parameter checks
780
793
  _checkRequired(action, 'parameters.consumer', action.parameters?.consumer, platform.id, unitId, failures);
781
794
  _checkRequired(action, 'parameters.plugin', action.parameters?.plugin, plugin, unitId, failures);
@@ -792,12 +805,53 @@ export function validatePlanActionCompleteness(plan, options = {}) {
792
805
  `unit "${unitId}", action "${action.id}": parameters.marketplace is "${action.parameters.marketplace}", expected optional legacy value "${marketplace}"`,
793
806
  );
794
807
  }
795
- _checkRequired(action, 'parameters.repo', action.parameters?.repo, publicRepo, unitId, failures);
808
+ if (externalMarketplace) {
809
+ // External form: the install repo is the external marketplace repo,
810
+ // not publicRepo; marketplaceLocation is the action-level marker.
811
+ _checkRequired(action, 'parameters.repo', action.parameters?.repo, dist.marketplaceRepo, unitId, failures);
812
+ _checkRequired(action, 'parameters.marketplaceLocation', action.parameters?.marketplaceLocation, 'external', unitId, failures);
813
+ } else {
814
+ _checkRequired(action, 'parameters.repo', action.parameters?.repo, publicRepo, unitId, failures);
815
+ }
796
816
  _checkRequired(action, 'parameters.version', action.parameters?.version, targetVersion, unitId, failures);
797
817
  _checkRequired(action, 'parameters.entrySkill', action.parameters?.entrySkill, entrySkill, unitId, failures);
798
818
  if (production) {
819
+ // snapshotPath/manifestDigest always bind the unit's own frozen
820
+ // snapshot — the payload authority is unchanged for external form.
799
821
  _checkRequired(action, 'parameters.snapshotPath', action.parameters?.snapshotPath, frozen?.path, unitId, failures);
800
- _checkRequired(action, 'parameters.ref', action.parameters?.ref, expectedTag, unitId, failures);
822
+ if (externalMarketplace) {
823
+ // The add-ref is frozen online by prepare (codex=commit sha,
824
+ // claude=default branch name) and cannot be re-derived offline;
825
+ // validate structural safety plus self-consistency with expected.ref.
826
+ const ref = action.parameters?.ref;
827
+ if (ref === undefined || ref === null) {
828
+ failures.push(
829
+ `unit "${unitId}", action "${action.id}": parameters.ref is missing, expected the frozen external marketplace add-ref`,
830
+ );
831
+ } else if (!_isStructurallySafeExternalRef(ref)) {
832
+ failures.push(
833
+ `unit "${unitId}", action "${action.id}": parameters.ref is not a structurally safe ref: ${JSON.stringify(ref)}`,
834
+ );
835
+ } else if (ref !== action.expected?.ref) {
836
+ failures.push(
837
+ `unit "${unitId}", action "${action.id}": parameters.ref is "${ref}", expected self-consistent expected.ref "${action.expected?.ref}"`,
838
+ );
839
+ }
840
+ // marketplaceCommitSha is the frozen 40-hex marketplace HEAD
841
+ // (online freeze, offline completeness — same model as manifestDigest).
842
+ const sha = action.parameters?.marketplaceCommitSha;
843
+ if (sha === undefined || sha === null) {
844
+ failures.push(
845
+ `unit "${unitId}", action "${action.id}": parameters.marketplaceCommitSha is missing, expected a frozen 40-hex commit sha`,
846
+ );
847
+ } else if (typeof sha !== 'string' || !EXTERNAL_MARKETPLACE_SHA_RE.test(sha)) {
848
+ failures.push(
849
+ `unit "${unitId}", action "${action.id}": parameters.marketplaceCommitSha must be a 40-hex commit sha, got: ${JSON.stringify(sha)}`,
850
+ );
851
+ }
852
+ } else {
853
+ _checkRequired(action, 'parameters.ref', action.parameters?.ref, expectedTag, unitId, failures);
854
+ }
801
855
  _checkRequired(action, 'parameters.manifestDigest', action.parameters?.manifestDigest, frozen?.manifestDigest, unitId, failures);
802
856
  }
803
857
  // timeoutMs is mandatory for all marketplace install actions.
@@ -840,8 +894,15 @@ export function validatePlanActionCompleteness(plan, options = {}) {
840
894
  _checkRequired(action, 'expected.entrySkill', action.expected?.entrySkill, entrySkill, unitId, failures);
841
895
  if (production) {
842
896
  _checkRequired(action, 'expected.consumer', action.expected?.consumer, platform.id, unitId, failures);
843
- _checkRequired(action, 'expected.repo', action.expected?.repo, publicRepo, unitId, failures);
844
- _checkRequired(action, 'expected.ref', action.expected?.ref, expectedTag, unitId, failures);
897
+ if (externalMarketplace) {
898
+ _checkRequired(action, 'expected.repo', action.expected?.repo, dist.marketplaceRepo, unitId, failures);
899
+ _checkRequired(action, 'expected.ref', action.expected?.ref, action.parameters?.ref, unitId, failures);
900
+ _checkRequired(action, 'expected.marketplaceLocation', action.expected?.marketplaceLocation, 'external', unitId, failures);
901
+ _checkRequired(action, 'expected.marketplaceCommitSha', action.expected?.marketplaceCommitSha, action.parameters?.marketplaceCommitSha, unitId, failures);
902
+ } else {
903
+ _checkRequired(action, 'expected.repo', action.expected?.repo, publicRepo, unitId, failures);
904
+ _checkRequired(action, 'expected.ref', action.expected?.ref, expectedTag, unitId, failures);
905
+ }
845
906
  _checkRequired(action, 'expected.entrySkillFound', action.expected?.entrySkillFound, true, unitId, failures);
846
907
  _checkRequired(action, 'expected.manifestDigest', action.expected?.manifestDigest, frozen?.manifestDigest, unitId, failures);
847
908
  }
@@ -946,3 +1007,35 @@ function _checkRequired(action, fieldPath, actual, expected, unitId, failures) {
946
1007
  );
947
1008
  }
948
1009
  }
1010
+
1011
+ // External independent marketplace form (external-marketplace): a frozen
1012
+ // marketplace HEAD commit sha is a 40-char lowercase hex string.
1013
+ const EXTERNAL_MARKETPLACE_SHA_RE = /^[0-9a-f]{40}$/;
1014
+
1015
+ /**
1016
+ * Structural safety check for an externally frozen marketplace add-ref.
1017
+ *
1018
+ * The add-ref (codex=commit sha, claude=default branch name) is frozen online
1019
+ * by prepare and cannot be re-derived offline; full injection-safety validation
1020
+ * already happened at freeze time (plugin-marketplace `validateSafeRef`). The
1021
+ * offline completeness gate re-checks structural well-formedness so a tampered
1022
+ * or corrupted frozen ref fails closed here too. Mirrors that validator's rules.
1023
+ *
1024
+ * @param {unknown} ref
1025
+ * @returns {boolean}
1026
+ */
1027
+ function _isStructurallySafeExternalRef(ref) {
1028
+ if (typeof ref !== 'string' || ref.length === 0) return false;
1029
+ if (/[\x00-\x1f]/.test(ref)) return false;
1030
+ if (ref.startsWith('-')) return false;
1031
+ if (ref.includes('\\')) return false;
1032
+ if (ref.includes('//')) return false;
1033
+ if (ref.startsWith('/') || ref.endsWith('/')) return false;
1034
+ if (ref.endsWith('.')) return false;
1035
+ if (ref.endsWith('.lock')) return false;
1036
+ if (ref.includes('@{')) return false;
1037
+ if (ref === '@') return false;
1038
+ if (ref.includes('..')) return false;
1039
+ if (/[;|&`$(){}]/.test(ref)) return false;
1040
+ return /^[a-zA-Z0-9][a-zA-Z0-9._/-]*$/.test(ref);
1041
+ }
@@ -57,7 +57,7 @@ function validateGate(gate) {
57
57
  if (!gate.scope || typeof gate.scope.unit !== 'string') {
58
58
  throw gateError(gate, 'must declare scope.unit');
59
59
  }
60
- if (gate.phase === 'consumer-verify' && !['npm', 'claude-plugin', 'codex-plugin', 'kimi-plugin'].includes(gate.scope.distribution)) {
60
+ if (gate.phase === 'consumer-verify' && !['npm', 'claude-plugin', 'codex-plugin', 'kimi-plugin', 'codebuddy-plugin'].includes(gate.scope.distribution)) {
61
61
  throw gateError(gate, 'consumer-verify must declare a supported scope.distribution');
62
62
  }
63
63
  if (!Array.isArray(gate.command) || gate.command.length === 0 || gate.command.some((value) => typeof value !== 'string')) {