release-skill 0.6.1 → 0.6.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 (31) 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 +17 -0
  7. package/INSTALL.md +2 -2
  8. package/INSTALL.zh-CN.md +2 -2
  9. package/README.md +12 -9
  10. package/README.zh-CN.md +12 -9
  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 +326 -70
  14. package/adapters/claude/schemas/release-plan.schema.json +9 -0
  15. package/adapters/codex/.codex-plugin/plugin.json +2 -2
  16. package/adapters/codex/bin/release-skill.bundle.mjs +326 -70
  17. package/adapters/codex/schemas/release-plan.schema.json +9 -0
  18. package/adapters/kimi/.kimi-plugin/plugin.json +1 -1
  19. package/adapters/kimi/bin/release-skill.bundle.mjs +326 -70
  20. package/adapters/kimi/schemas/release-plan.schema.json +9 -0
  21. package/adapters/workbuddy/.codebuddy-plugin/plugin.json +1 -1
  22. package/adapters/workbuddy/bin/release-skill.bundle.mjs +326 -70
  23. package/adapters/workbuddy/schemas/release-plan.schema.json +9 -0
  24. package/bin/release-skill.bundle.mjs +326 -70
  25. package/package.json +1 -1
  26. package/schemas/release-plan.schema.json +9 -0
  27. package/src/commands/lineage.mjs +101 -32
  28. package/src/commands/prepare.mjs +59 -1
  29. package/src/commands/publish.mjs +10 -1
  30. package/src/core/skill-resource-closure.mjs +240 -10
  31. package/src/platforms/registry.mjs +12 -0
@@ -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.6.1"});
12
+ const __bundlePkg = Object.freeze({"name":"release-skill","version":"0.6.2"});
13
13
  // Build-time source digest for the BUNDLE_STALE freshness gate (see above).
14
- const __bundleSourceDigest = "c51fa1df96e9ef06d5310a990e6ce2366e4878332d646b034842d0deaec549d4";
14
+ const __bundleSourceDigest = "12dcb7942e6587f1321c3f81625b0bc3f1dd64afe978ddf8084bf1a5824de23a";
15
15
 
16
16
  var __create = Object.create;
17
17
  var __defProp = Object.defineProperty;
@@ -23549,13 +23549,13 @@ var require_cross_spawn = __commonJS({
23549
23549
  var cp2 = __require("child_process");
23550
23550
  var parse2 = require_parse();
23551
23551
  var enoent = require_enoent();
23552
- function spawn4(command2, args2, options) {
23552
+ function spawn5(command2, args2, options) {
23553
23553
  const parsed = parse2(command2, args2, options);
23554
23554
  const spawned = cp2.spawn(parsed.command, parsed.args, parsed.options);
23555
23555
  enoent.hookChildProcess(spawned, parsed);
23556
23556
  return spawned;
23557
23557
  }
23558
- __name(spawn4, "spawn");
23558
+ __name(spawn5, "spawn");
23559
23559
  function spawnSync2(command2, args2, options) {
23560
23560
  const parsed = parse2(command2, args2, options);
23561
23561
  const result = cp2.spawnSync(parsed.command, parsed.args, parsed.options);
@@ -23563,8 +23563,8 @@ var require_cross_spawn = __commonJS({
23563
23563
  return result;
23564
23564
  }
23565
23565
  __name(spawnSync2, "spawnSync");
23566
- module.exports = spawn4;
23567
- module.exports.spawn = spawn4;
23566
+ module.exports = spawn5;
23567
+ module.exports.spawn = spawn5;
23568
23568
  module.exports.sync = spawnSync2;
23569
23569
  module.exports._parse = parse2;
23570
23570
  module.exports._enoent = enoent;
@@ -32218,7 +32218,7 @@ var init_report = __esm({
32218
32218
  init_closure();
32219
32219
  init_errors3();
32220
32220
  init_validation();
32221
- PACKAGE_META = Object.freeze({ "name": "release-skill", "version": "0.6.1" });
32221
+ PACKAGE_META = Object.freeze({ "name": "release-skill", "version": "0.6.2" });
32222
32222
  REPORT_RENDERER_VERSION = PACKAGE_META.version;
32223
32223
  SUPPORTED_REPORT_LOCALES = Object.freeze(["zh-CN", "en-US"]);
32224
32224
  EXECUTION_STATUSES = Object.freeze([
@@ -35543,6 +35543,9 @@ function assertRegistry(registry = PLATFORMS) {
35543
35543
  if (!platform.buildAdapter || typeof platform.buildAdapter !== "object") {
35544
35544
  throw new Error(`platform registry: ${label} buildAdapter must be an object`);
35545
35545
  }
35546
+ if (typeof platform.buildAdapter.name !== "string" || platform.buildAdapter.name.length === 0) {
35547
+ throw new Error(`platform registry: ${label} buildAdapter needs a non-empty name (its adapter directory name)`);
35548
+ }
35546
35549
  if (!VALID_LIST_OUTPUTS.has(platform.jsonProtocol?.listOutput)) {
35547
35550
  throw new Error(`platform registry: ${label} has illegal jsonProtocol.listOutput "${platform.jsonProtocol?.listOutput}"`);
35548
35551
  }
@@ -35730,6 +35733,9 @@ var init_registry2 = __esm({
35730
35733
  schemaRequiredFields: Object.freeze(["plugin", "marketplace", "entrySkill"]),
35731
35734
  skillRendering: Object.freeze({ mode: "verbatim", preamble: null, placeholder: "${CLAUDE_PLUGIN_ROOT}" }),
35732
35735
  buildAdapter: Object.freeze({
35736
+ // D6: explicit adapter directory name (adapters/claude/); assertRegistry
35737
+ // requires this on every platform.
35738
+ name: "claude",
35733
35739
  pluginDirName: ".claude-plugin",
35734
35740
  templateFileName: "plugin.json",
35735
35741
  marketplaceFileName: "marketplace.json",
@@ -35787,6 +35793,8 @@ var init_registry2 = __esm({
35787
35793
  schemaRequiredFields: Object.freeze(["plugin", "marketplace", "entrySkill"]),
35788
35794
  skillRendering: Object.freeze({ mode: "substitute", preamble: "codex", placeholder: "${CLAUDE_PLUGIN_ROOT}" }),
35789
35795
  buildAdapter: Object.freeze({
35796
+ // D6: explicit adapter directory name (adapters/codex/).
35797
+ name: "codex",
35790
35798
  pluginDirName: ".codex-plugin",
35791
35799
  templateFileName: "plugin.json",
35792
35800
  marketplaceFileName: null,
@@ -35843,6 +35851,8 @@ var init_registry2 = __esm({
35843
35851
  schemaRequiredFields: Object.freeze(["plugin", "entrySkill"]),
35844
35852
  skillRendering: Object.freeze({ mode: "substitute", preamble: "kimi", placeholder: "${CLAUDE_PLUGIN_ROOT}" }),
35845
35853
  buildAdapter: Object.freeze({
35854
+ // D6: explicit adapter directory name (adapters/kimi/).
35855
+ name: "kimi",
35846
35856
  pluginDirName: ".kimi-plugin",
35847
35857
  templateFileName: "plugin.json",
35848
35858
  marketplaceFileName: null,
@@ -41707,7 +41717,7 @@ function trimCandidate(value) {
41707
41717
  function isPathToken(value) {
41708
41718
  const token = trimCandidate(value);
41709
41719
  if (!token || GLOB_PATTERN.test(token)) return false;
41710
- return BARE_PREFIXES.some((prefix) => token.startsWith(prefix)) || EXPLICIT_PREFIXES.some((prefix) => token.startsWith(prefix)) || SOURCE_TREE_PATTERN.test(token) || MACHINE_ABSOLUTE_PATTERN.test(token);
41720
+ return BARE_PREFIXES.some((prefix) => token.startsWith(prefix)) || EXPLICIT_PREFIXES.some((prefix) => token.startsWith(prefix)) || HOME_DIRECTORY_PATTERN.test(token) || SOURCE_TREE_PATTERN.test(token) || MACHINE_ABSOLUTE_PATTERN.test(token);
41711
41721
  }
41712
41722
  function scanSnippet(snippet, line, sourceOnly, results, seen) {
41713
41723
  const candidates = snippet.match(/(?:"[^"\n]+"|'[^'\n]+'|[^\s"'`()\[\],;]+)/gu) ?? [];
@@ -41732,15 +41742,14 @@ function extractPathTokens(content) {
41732
41742
  inFence = !inFence;
41733
41743
  continue;
41734
41744
  }
41735
- const sourceOnly = SOURCE_ONLY_MARKER.test(line);
41736
- if (inFence) scanSnippet(line, lineNumber, sourceOnly, results, seen);
41745
+ if (inFence) scanSnippet(line, lineNumber, SOURCE_ONLY_MARKER.test(line), results, seen);
41737
41746
  for (const match of line.matchAll(/`([^`]+)`/gu)) {
41738
- scanSnippet(match[1], lineNumber, sourceOnly, results, seen);
41747
+ scanSnippet(match[1], lineNumber, SOURCE_ONLY_MARKER.test(match[1]), results, seen);
41739
41748
  }
41740
41749
  for (const match of line.matchAll(/\]\(([^)]+)\)/gu)) {
41741
41750
  const target = match[1].trim().split(/[?#]/u)[0];
41742
41751
  if (!/^(?:https?:|#)/iu.test(target)) {
41743
- scanSnippet(target, lineNumber, sourceOnly, results, seen);
41752
+ scanSnippet(target, lineNumber, SOURCE_ONLY_MARKER.test(match[1]), results, seen);
41744
41753
  }
41745
41754
  }
41746
41755
  }
@@ -41761,6 +41770,14 @@ function classifyReference(token, skillRoot, pluginRoot, scanRoot2) {
41761
41770
  absoluteTarget: token
41762
41771
  };
41763
41772
  }
41773
+ if (HOME_DIRECTORY_PATTERN.test(token)) {
41774
+ return {
41775
+ classification: CLASSIFICATION.HOME_DIRECTORY,
41776
+ resolutionRoot: "(home)",
41777
+ resolvedTarget: token,
41778
+ absoluteTarget: token
41779
+ };
41780
+ }
41764
41781
  if (SOURCE_TREE_PATTERN.test(token)) {
41765
41782
  return {
41766
41783
  classification: CLASSIFICATION.SOURCE_BACKJUMP,
@@ -41806,8 +41823,26 @@ async function inspectRegularFile(root, target) {
41806
41823
  }
41807
41824
  return { code: null };
41808
41825
  }
41826
+ async function collectRegularFiles(dir, results) {
41827
+ let entries;
41828
+ try {
41829
+ entries = await readdir8(dir, { withFileTypes: true });
41830
+ } catch (error) {
41831
+ if (error.code === "ENOENT") return;
41832
+ throw error;
41833
+ }
41834
+ for (const entry of [...entries].sort((a, b) => a.name.localeCompare(b.name))) {
41835
+ if (entry.isSymbolicLink()) continue;
41836
+ const absolute = join12(dir, entry.name);
41837
+ if (entry.isDirectory()) {
41838
+ await collectRegularFiles(absolute, results);
41839
+ } else if (entry.isFile()) {
41840
+ results.push(absolute);
41841
+ }
41842
+ }
41843
+ }
41809
41844
  function inferSurfaceHost(surfaceId, defaultHost) {
41810
- const match = /^adapters\/([^/]+)$/u.exec(surfaceId);
41845
+ const match = ADAPTER_SURFACE_PATTERN.exec(surfaceId);
41811
41846
  return match?.[1] ?? defaultHost;
41812
41847
  }
41813
41848
  function receiptProjection(result) {
@@ -41818,6 +41853,7 @@ function receiptProjection(result) {
41818
41853
  skillCount: result.skillCount,
41819
41854
  referenceCount: result.referenceCount,
41820
41855
  sourceOnlyCount: result.sourceOnlyCount,
41856
+ sourceOnlyReferences: result.sourceOnlyReferences,
41821
41857
  findingCount: result.findings.length
41822
41858
  };
41823
41859
  }
@@ -41894,8 +41930,23 @@ async function checkSkillResourceClosure({
41894
41930
  const skillPaths = await discoverSkills(scanRoot2);
41895
41931
  const findings = [];
41896
41932
  const surfaceMap = /* @__PURE__ */ new Map();
41933
+ const skillsBySurface = /* @__PURE__ */ new Map();
41934
+ const resolvedResourcesBySurface = /* @__PURE__ */ new Map();
41935
+ const referencedTargetsBySurface = /* @__PURE__ */ new Map();
41936
+ const resourceReferencesBySurface = /* @__PURE__ */ new Map();
41937
+ const sourceOnlyReferences = [];
41897
41938
  let referenceCount = 0;
41898
41939
  let sourceOnlyCount = 0;
41940
+ const recordSourceOnlyExemption = /* @__PURE__ */ __name((surface, skill, pathToken) => {
41941
+ sourceOnlyCount += 1;
41942
+ surface.sourceOnlyCount += 1;
41943
+ sourceOnlyReferences.push({
41944
+ skill,
41945
+ line: pathToken.line,
41946
+ reference: pathToken.token,
41947
+ surface: surface.id
41948
+ });
41949
+ }, "recordSourceOnlyExemption");
41899
41950
  for (const skill of skillPaths) {
41900
41951
  const skillRoot = resolveSkillRoot(skill, scanRoot2);
41901
41952
  const pluginRoot = resolvePluginRoot(skill, scanRoot2);
@@ -41910,6 +41961,8 @@ async function checkSkillResourceClosure({
41910
41961
  };
41911
41962
  surface.skillCount += 1;
41912
41963
  surfaceMap.set(surfaceId, surface);
41964
+ if (!skillsBySurface.has(surfaceId)) skillsBySurface.set(surfaceId, []);
41965
+ skillsBySurface.get(surfaceId).push(skill);
41913
41966
  const content = await readFile12(resolve16(scanRoot2, skill), "utf8");
41914
41967
  for (const pathToken of extractPathTokens(content)) {
41915
41968
  referenceCount += 1;
@@ -41932,8 +41985,7 @@ async function checkSkillResourceClosure({
41932
41985
  };
41933
41986
  if (classification.classification === CLASSIFICATION.SOURCE_BACKJUMP) {
41934
41987
  if (pathToken.sourceOnly) {
41935
- sourceOnlyCount += 1;
41936
- surface.sourceOnlyCount += 1;
41988
+ recordSourceOnlyExemption(surface, skill, pathToken);
41937
41989
  } else {
41938
41990
  findings.push({ ...findingBase, code: FINDING_CODE.SOURCE_BACKJUMP });
41939
41991
  }
@@ -41943,6 +41995,10 @@ async function checkSkillResourceClosure({
41943
41995
  findings.push({ ...findingBase, code: FINDING_CODE.MACHINE_ABSOLUTE_PATH });
41944
41996
  continue;
41945
41997
  }
41998
+ if (classification.classification === CLASSIFICATION.HOME_DIRECTORY) {
41999
+ findings.push({ ...findingBase, code: FINDING_CODE.HOME_DIRECTORY_SEARCH });
42000
+ continue;
42001
+ }
41946
42002
  if (classification.classification === CLASSIFICATION.OUT_OF_BOUNDS) {
41947
42003
  findings.push({ ...findingBase, code: FINDING_CODE.OUT_OF_BOUNDS });
41948
42004
  continue;
@@ -41954,14 +42010,112 @@ async function checkSkillResourceClosure({
41954
42010
  );
41955
42011
  if (inspection.code) {
41956
42012
  if (pathToken.sourceOnly && inspection.code === FINDING_CODE.RESOURCE_MISSING) {
41957
- sourceOnlyCount += 1;
41958
- surface.sourceOnlyCount += 1;
42013
+ recordSourceOnlyExemption(surface, skill, pathToken);
41959
42014
  } else {
41960
42015
  findings.push({ ...findingBase, code: inspection.code });
41961
42016
  }
42017
+ continue;
42018
+ }
42019
+ const relativeResource = relativeStable(pluginRoot, classification.absoluteTarget);
42020
+ if (!resolvedResourcesBySurface.has(surfaceId)) {
42021
+ resolvedResourcesBySurface.set(surfaceId, /* @__PURE__ */ new Map());
42022
+ referencedTargetsBySurface.set(surfaceId, /* @__PURE__ */ new Set());
42023
+ resourceReferencesBySurface.set(surfaceId, /* @__PURE__ */ new Map());
42024
+ }
42025
+ resolvedResourcesBySurface.get(surfaceId).set(relativeResource, classification.absoluteTarget);
42026
+ referencedTargetsBySurface.get(surfaceId).add(classification.absoluteTarget);
42027
+ const resourceReferences = resourceReferencesBySurface.get(surfaceId);
42028
+ if (!resourceReferences.has(relativeResource)) resourceReferences.set(relativeResource, []);
42029
+ resourceReferences.get(relativeResource).push({
42030
+ surface: surfaceId,
42031
+ skill,
42032
+ line: pathToken.line
42033
+ });
42034
+ }
42035
+ }
42036
+ const contentDigestCache = /* @__PURE__ */ new Map();
42037
+ const digestOfTarget = /* @__PURE__ */ __name(async (absoluteTarget) => {
42038
+ if (!contentDigestCache.has(absoluteTarget)) {
42039
+ contentDigestCache.set(
42040
+ absoluteTarget,
42041
+ digestDocument({ content: await readFile12(absoluteTarget, "utf8") })
42042
+ );
42043
+ }
42044
+ return contentDigestCache.get(absoluteTarget);
42045
+ }, "digestOfTarget");
42046
+ const surfaceIds = [...resolvedResourcesBySurface.keys()].sort((a, b) => a.localeCompare(b));
42047
+ for (let i = 0; i < surfaceIds.length; i += 1) {
42048
+ for (let j = i + 1; j < surfaceIds.length; j += 1) {
42049
+ const [leftId, rightId] = [surfaceIds[i], surfaceIds[j]];
42050
+ const left = resolvedResourcesBySurface.get(leftId);
42051
+ const right = resolvedResourcesBySurface.get(rightId);
42052
+ const commonPaths = [...left.keys()].filter((path15) => right.has(path15)).sort((a, b) => a.localeCompare(b));
42053
+ for (const resourcePath of commonPaths) {
42054
+ const [leftDigest, rightDigest] = await Promise.all([
42055
+ digestOfTarget(left.get(resourcePath)),
42056
+ digestOfTarget(right.get(resourcePath))
42057
+ ]);
42058
+ if (leftDigest === rightDigest) continue;
42059
+ const rightSurface = surfaceMap.get(rightId);
42060
+ const driftReferences = [];
42061
+ const seenReference = /* @__PURE__ */ new Set();
42062
+ for (const surfaceId of [leftId, rightId]) {
42063
+ for (const ref of resourceReferencesBySurface.get(surfaceId)?.get(resourcePath) ?? []) {
42064
+ const key = `${ref.surface}\0${ref.skill}\0${ref.line}`;
42065
+ if (seenReference.has(key)) continue;
42066
+ seenReference.add(key);
42067
+ driftReferences.push({ surface: ref.surface, skill: ref.skill, line: ref.line });
42068
+ }
42069
+ }
42070
+ driftReferences.sort((a, b) => a.surface.localeCompare(b.surface) || a.skill.localeCompare(b.skill) || a.line - b.line);
42071
+ findings.push({
42072
+ host: rightSurface.host,
42073
+ surface: rightId,
42074
+ skill: null,
42075
+ line: null,
42076
+ reference: resourcePath,
42077
+ classification: CLASSIFICATION.RESOURCE_DRIFT,
42078
+ resolutionRoot: rightId,
42079
+ resolvedTarget: resourcePath,
42080
+ surfaces: [leftId, rightId],
42081
+ references: driftReferences,
42082
+ code: FINDING_CODE.RESOURCE_DRIFT
42083
+ });
42084
+ }
42085
+ }
42086
+ }
42087
+ for (const surfaceId of [...skillsBySurface.keys()].sort((a, b) => a.localeCompare(b))) {
42088
+ if (!ADAPTER_SURFACE_PATTERN.test(surfaceId)) continue;
42089
+ const surface = surfaceMap.get(surfaceId);
42090
+ const surfaceRootAbsolute = resolve16(scanRoot2, surfaceId);
42091
+ const referencedTargets = referencedTargetsBySurface.get(surfaceId) ?? /* @__PURE__ */ new Set();
42092
+ const stale = [];
42093
+ for (const skill of skillsBySurface.get(surfaceId)) {
42094
+ const skillDir = resolve16(scanRoot2, dirname7(skill));
42095
+ for (const closureDir of CLOSURE_RESOURCE_DIRS) {
42096
+ const files = [];
42097
+ await collectRegularFiles(join12(skillDir, closureDir), files);
42098
+ for (const absolute of files) {
42099
+ if (referencedTargets.has(absolute)) continue;
42100
+ const relativeResource = relativeStable(surfaceRootAbsolute, absolute);
42101
+ stale.push({
42102
+ host: surface.host,
42103
+ surface: surfaceId,
42104
+ skill,
42105
+ line: null,
42106
+ reference: relativeResource,
42107
+ classification: CLASSIFICATION.STALE_RESOURCE,
42108
+ resolutionRoot: surfaceId,
42109
+ resolvedTarget: relativeResource,
42110
+ code: FINDING_CODE.STALE_RESOURCE
42111
+ });
42112
+ }
41962
42113
  }
41963
42114
  }
42115
+ stale.sort((a, b) => a.skill.localeCompare(b.skill) || a.resolvedTarget.localeCompare(b.resolvedTarget));
42116
+ findings.push(...stale);
41964
42117
  }
42118
+ sourceOnlyReferences.sort((a, b) => a.skill.localeCompare(b.skill) || a.line - b.line || a.reference.localeCompare(b.reference));
41965
42119
  if (snapshotError) {
41966
42120
  findings.push({
41967
42121
  host,
@@ -41984,18 +42138,29 @@ async function checkSkillResourceClosure({
41984
42138
  skillCount: skillPaths.length,
41985
42139
  referenceCount,
41986
42140
  sourceOnlyCount,
42141
+ sourceOnlyReferences,
41987
42142
  findings
41988
42143
  };
41989
42144
  result.receiptDigest = digestDocument(receiptProjection(result));
41990
42145
  return result;
41991
42146
  }
41992
- var CHECKER_VERSION, BARE_PREFIXES, EXPLICIT_PREFIXES, SOURCE_TREE_PATTERN, MACHINE_ABSOLUTE_PATTERN, GLOB_PATTERN, SOURCE_ONLY_MARKER, TRANSPORT_EXCLUSIONS, CLASSIFICATION, FINDING_CODE;
42147
+ function evaluateDeclaredHostSurfaceCoverage(expectedHosts, surfaces) {
42148
+ const missing = [];
42149
+ for (const expectedHost of [...new Set(expectedHosts ?? [])].sort((a, b) => a.localeCompare(b))) {
42150
+ const surface = (surfaces ?? []).find((item) => item.host === expectedHost);
42151
+ if (!surface || !(surface.skillCount >= 1)) {
42152
+ missing.push({ host: expectedHost, skillCount: surface?.skillCount ?? 0 });
42153
+ }
42154
+ }
42155
+ return { passed: missing.length === 0, missing };
42156
+ }
42157
+ var CHECKER_VERSION, BARE_PREFIXES, EXPLICIT_PREFIXES, SOURCE_TREE_PATTERN, MACHINE_ABSOLUTE_PATTERN, HOME_DIRECTORY_PATTERN, ADAPTER_SURFACE_PATTERN, CLOSURE_RESOURCE_DIRS, GLOB_PATTERN, SOURCE_ONLY_MARKER, TRANSPORT_EXCLUSIONS, CLASSIFICATION, FINDING_CODE;
41993
42158
  var init_skill_resource_closure = __esm({
41994
42159
  "src/core/skill-resource-closure.mjs"() {
41995
42160
  init_src();
41996
42161
  init_errors();
41997
42162
  init_frozen();
41998
- CHECKER_VERSION = "skill-resource-closure-v1";
42163
+ CHECKER_VERSION = "skill-resource-closure-v2";
41999
42164
  BARE_PREFIXES = ["references/", "assets/", "schemas/", "examples/", "scripts/"];
42000
42165
  EXPLICIT_PREFIXES = [
42001
42166
  "<plugin-root>/",
@@ -42007,6 +42172,9 @@ var init_skill_resource_closure = __esm({
42007
42172
  ];
42008
42173
  SOURCE_TREE_PATTERN = /(?:^|\/)packages\/[A-Za-z0-9._-]+(?:\/|$)/u;
42009
42174
  MACHINE_ABSOLUTE_PATTERN = /^(?:\/(?:Users|home|root|tmp|var|etc|opt)(?:\/|$)|[A-Za-z]:[\\/])/u;
42175
+ HOME_DIRECTORY_PATTERN = /^(?:~|\$HOME|\$\{HOME\})\/.+/u;
42176
+ ADAPTER_SURFACE_PATTERN = /^adapters\/([^/]+)$/u;
42177
+ CLOSURE_RESOURCE_DIRS = Object.freeze(["references", "assets", "schemas", "examples", "scripts"]);
42010
42178
  GLOB_PATTERN = /[*?\[]/u;
42011
42179
  SOURCE_ONLY_MARKER = /(?:\bsource-only\b|仅源码包)/iu;
42012
42180
  TRANSPORT_EXCLUSIONS = Object.freeze([
@@ -42020,7 +42188,10 @@ var init_skill_resource_closure = __esm({
42020
42188
  PLUGIN_ROOT: "plugin_root",
42021
42189
  SOURCE_BACKJUMP: "source_backjump",
42022
42190
  MACHINE_ABSOLUTE: "machine_absolute",
42023
- OUT_OF_BOUNDS: "out_of_bounds"
42191
+ HOME_DIRECTORY: "home_directory",
42192
+ OUT_OF_BOUNDS: "out_of_bounds",
42193
+ RESOURCE_DRIFT: "resource_drift",
42194
+ STALE_RESOURCE: "stale_resource"
42024
42195
  });
42025
42196
  FINDING_CODE = Object.freeze({
42026
42197
  SNAPSHOT_UNSAFE: "SNAPSHOT_UNSAFE",
@@ -42028,8 +42199,11 @@ var init_skill_resource_closure = __esm({
42028
42199
  RESOURCE_NOT_REGULAR_FILE: "RESOURCE_NOT_REGULAR_FILE",
42029
42200
  SOURCE_BACKJUMP: "SOURCE_BACKJUMP",
42030
42201
  MACHINE_ABSOLUTE_PATH: "MACHINE_ABSOLUTE_PATH",
42202
+ HOME_DIRECTORY_SEARCH: "HOME_DIRECTORY_SEARCH",
42031
42203
  OUT_OF_BOUNDS: "OUT_OF_BOUNDS",
42032
- SYMLINK_NOT_ALLOWED: "SYMLINK_NOT_ALLOWED"
42204
+ SYMLINK_NOT_ALLOWED: "SYMLINK_NOT_ALLOWED",
42205
+ RESOURCE_DRIFT: "RESOURCE_DRIFT",
42206
+ STALE_RESOURCE: "STALE_RESOURCE"
42033
42207
  });
42034
42208
  __name(toPosix, "toPosix");
42035
42209
  __name(relativeStable, "relativeStable");
@@ -42044,12 +42218,14 @@ var init_skill_resource_closure = __esm({
42044
42218
  __name(stripExplicitPrefix, "stripExplicitPrefix");
42045
42219
  __name(classifyReference, "classifyReference");
42046
42220
  __name(inspectRegularFile, "inspectRegularFile");
42221
+ __name(collectRegularFiles, "collectRegularFiles");
42047
42222
  __name(inferSurfaceHost, "inferSurfaceHost");
42048
42223
  __name(receiptProjection, "receiptProjection");
42049
42224
  __name(createSkillResourceClosureReceipt, "createSkillResourceClosureReceipt");
42050
42225
  __name(assertSkillResourceClosureReceipt, "assertSkillResourceClosureReceipt");
42051
42226
  __name(evaluateConsumerSkillResourceClosureReceipts, "evaluateConsumerSkillResourceClosureReceipts");
42052
42227
  __name(checkSkillResourceClosure, "checkSkillResourceClosure");
42228
+ __name(evaluateDeclaredHostSurfaceCoverage, "evaluateDeclaredHostSurfaceCoverage");
42053
42229
  }
42054
42230
  });
42055
42231
 
@@ -72000,7 +72176,7 @@ var require_escape3 = __commonJS({
72000
72176
  var require_lib36 = __commonJS({
72001
72177
  "../../node_modules/.pnpm/@npmcli+promise-spawn@8.0.3/node_modules/@npmcli/promise-spawn/lib/index.js"(exports, module) {
72002
72178
  "use strict";
72003
- var { spawn: spawn4 } = __require("child_process");
72179
+ var { spawn: spawn5 } = __require("child_process");
72004
72180
  var os4 = __require("os");
72005
72181
  var which = require_lib35();
72006
72182
  var escape2 = require_escape3();
@@ -72027,7 +72203,7 @@ var require_lib36 = __commonJS({
72027
72203
  const resultError = getResult(erOpts);
72028
72204
  reject(Object.assign(er, resultError));
72029
72205
  }, "rejectWithOpts");
72030
- const proc = spawn4(cmd, args2, opts);
72206
+ const proc = spawn5(cmd, args2, opts);
72031
72207
  promise.stdin = proc.stdin;
72032
72208
  promise.process = proc;
72033
72209
  proc.on("error", rejectWithOpts);
@@ -72533,7 +72709,7 @@ var require_which3 = __commonJS({
72533
72709
  // ../../node_modules/.pnpm/@npmcli+git@6.0.3/node_modules/@npmcli/git/lib/spawn.js
72534
72710
  var require_spawn = __commonJS({
72535
72711
  "../../node_modules/.pnpm/@npmcli+git@6.0.3/node_modules/@npmcli/git/lib/spawn.js"(exports, module) {
72536
- var spawn4 = require_lib36();
72712
+ var spawn5 = require_lib36();
72537
72713
  var promiseRetry = require_promise_retry();
72538
72714
  var { log } = require_lib21();
72539
72715
  var makeError = require_make_error();
@@ -72558,7 +72734,7 @@ var require_spawn = __commonJS({
72558
72734
  if (number !== 1) {
72559
72735
  log.silly("git", `Retrying git command: ${args2.join(" ")} attempt # ${number}`);
72560
72736
  }
72561
- return spawn4(gitPath, args2, makeOpts(opts)).catch((er) => {
72737
+ return spawn5(gitPath, args2, makeOpts(opts)).catch((er) => {
72562
72738
  const gitError = makeError(er);
72563
72739
  if (!gitError.shouldRetry(number)) {
72564
72740
  throw gitError;
@@ -72682,7 +72858,7 @@ var require_lines_to_revs = __commonJS({
72682
72858
  // ../../node_modules/.pnpm/@npmcli+git@6.0.3/node_modules/@npmcli/git/lib/revs.js
72683
72859
  var require_revs = __commonJS({
72684
72860
  "../../node_modules/.pnpm/@npmcli+git@6.0.3/node_modules/@npmcli/git/lib/revs.js"(exports, module) {
72685
- var spawn4 = require_spawn();
72861
+ var spawn5 = require_spawn();
72686
72862
  var { LRUCache } = require_commonjs3();
72687
72863
  var linesToRevs = require_lines_to_revs();
72688
72864
  var revsCache = new LRUCache({
@@ -72696,7 +72872,7 @@ var require_revs = __commonJS({
72696
72872
  return cached;
72697
72873
  }
72698
72874
  }
72699
- const { stdout } = await spawn4(["ls-remote", repo], opts);
72875
+ const { stdout } = await spawn5(["ls-remote", repo], opts);
72700
72876
  const revs = linesToRevs(stdout.trim().split("\n"));
72701
72877
  revsCache.set(repo, revs);
72702
72878
  return revs;
@@ -73240,7 +73416,7 @@ var require_clone2 = __commonJS({
73240
73416
  var { parse: parse2 } = __require("url");
73241
73417
  var path15 = __require("path");
73242
73418
  var getRevs = require_revs();
73243
- var spawn4 = require_spawn();
73419
+ var spawn5 = require_spawn();
73244
73420
  var { isWindows } = require_utils4();
73245
73421
  var pickManifest = require_lib39();
73246
73422
  var fs = __require("fs/promises");
@@ -73294,7 +73470,7 @@ var require_clone2 = __commonJS({
73294
73470
  var other = /* @__PURE__ */ __name((repo, revDoc, target, opts) => {
73295
73471
  const shallow = maybeShallow(repo, opts);
73296
73472
  const fetchOrigin = ["fetch", "origin", revDoc.rawRef].concat(shallow ? ["--depth=1"] : []);
73297
- const git3 = /* @__PURE__ */ __name((args2) => spawn4(args2, { ...opts, cwd: target }), "git");
73473
+ const git3 = /* @__PURE__ */ __name((args2) => spawn5(args2, { ...opts, cwd: target }), "git");
73298
73474
  return fs.mkdir(target, { recursive: true }).then(() => git3(["init"])).then(() => isWindows(opts) ? git3(["config", "--local", "--add", "core.longpaths", "true"]) : null).then(() => git3(["remote", "add", "origin", repo])).then(() => git3(fetchOrigin)).then(() => git3(["checkout", revDoc.sha])).then(() => updateSubmodules(target, opts)).then(() => revDoc.sha);
73299
73475
  }, "other");
73300
73476
  var branch = /* @__PURE__ */ __name((repo, revDoc, target, opts) => {
@@ -73312,7 +73488,7 @@ var require_clone2 = __commonJS({
73312
73488
  if (isWindows(opts)) {
73313
73489
  args2.push("--config", "core.longpaths=true");
73314
73490
  }
73315
- return spawn4(args2, opts).then(() => revDoc.sha);
73491
+ return spawn5(args2, opts).then(() => revDoc.sha);
73316
73492
  }, "branch");
73317
73493
  var plain = /* @__PURE__ */ __name((repo, revDoc, target, opts) => {
73318
73494
  const args2 = [
@@ -73327,14 +73503,14 @@ var require_clone2 = __commonJS({
73327
73503
  if (isWindows(opts)) {
73328
73504
  args2.push("--config", "core.longpaths=true");
73329
73505
  }
73330
- return spawn4(args2, opts).then(() => revDoc.sha);
73506
+ return spawn5(args2, opts).then(() => revDoc.sha);
73331
73507
  }, "plain");
73332
73508
  var updateSubmodules = /* @__PURE__ */ __name(async (target, opts) => {
73333
73509
  const hasSubmodules = await fs.stat(`${target}/.gitmodules`).then(() => true).catch(() => false);
73334
73510
  if (!hasSubmodules) {
73335
73511
  return null;
73336
73512
  }
73337
- return spawn4([
73513
+ return spawn5([
73338
73514
  "submodule",
73339
73515
  "update",
73340
73516
  "-q",
@@ -73345,7 +73521,7 @@ var require_clone2 = __commonJS({
73345
73521
  var unresolved = /* @__PURE__ */ __name((repo, ref, target, opts) => {
73346
73522
  const lp = isWindows(opts) ? ["--config", "core.longpaths=true"] : [];
73347
73523
  const cloneArgs = ["clone", "--mirror", "-q", repo, target + "/.git"];
73348
- const git3 = /* @__PURE__ */ __name((args2) => spawn4(args2, { ...opts, cwd: target }), "git");
73524
+ const git3 = /* @__PURE__ */ __name((args2) => spawn5(args2, { ...opts, cwd: target }), "git");
73349
73525
  return fs.mkdir(target, { recursive: true }).then(() => git3(cloneArgs.concat(lp))).then(() => git3(["init"])).then(() => git3(["checkout", ref])).then(() => updateSubmodules(target, opts)).then(() => git3(["rev-parse", "--revs-only", "HEAD"])).then(({ stdout }) => stdout.trim());
73350
73526
  }, "unresolved");
73351
73527
  }
@@ -73382,8 +73558,8 @@ var require_find = __commonJS({
73382
73558
  // ../../node_modules/.pnpm/@npmcli+git@6.0.3/node_modules/@npmcli/git/lib/is-clean.js
73383
73559
  var require_is_clean = __commonJS({
73384
73560
  "../../node_modules/.pnpm/@npmcli+git@6.0.3/node_modules/@npmcli/git/lib/is-clean.js"(exports, module) {
73385
- var spawn4 = require_spawn();
73386
- module.exports = (opts = {}) => spawn4(["status", "--porcelain=v1", "-uno"], opts).then((res) => !res.stdout.trim().split(/\r?\n+/).map((l) => l.trim()).filter((l) => l).length);
73561
+ var spawn5 = require_spawn();
73562
+ module.exports = (opts = {}) => spawn5(["status", "--porcelain=v1", "-uno"], opts).then((res) => !res.stdout.trim().split(/\r?\n+/).map((l) => l.trim()).filter((l) => l).length);
73387
73563
  }
73388
73564
  });
73389
73565
 
@@ -97074,7 +97250,11 @@ async function prepareRelease(options) {
97074
97250
  snapshotDir: manifest.outputDir,
97075
97251
  host: "root"
97076
97252
  });
97077
- const receipt = createSkillResourceClosureReceipt(closureResult, { unitId: unit.id });
97253
+ const receipt = createSkillResourceClosureReceipt(closureResult, {
97254
+ unitId: unit.id,
97255
+ preparedAt: freezeTimestamp ?? null,
97256
+ exitCode: 0
97257
+ });
97078
97258
  skillResourceClosureResults.push(receipt);
97079
97259
  if (closureResult.findings.length > 0) {
97080
97260
  await evidence.append({
@@ -97087,7 +97267,10 @@ async function prepareRelease(options) {
97087
97267
  line: f.line,
97088
97268
  reference: f.reference,
97089
97269
  classification: f.classification,
97090
- code: f.code
97270
+ code: f.code,
97271
+ // D4: RESOURCE_DRIFT findings localize via references (the
97272
+ // finding's own skill/line stay null for a cross-surface drift).
97273
+ ...f.references ? { references: f.references } : {}
97091
97274
  }))
97092
97275
  });
97093
97276
  throw new ReleaseError(
@@ -97100,6 +97283,33 @@ async function prepareRelease(options) {
97100
97283
  }
97101
97284
  );
97102
97285
  }
97286
+ const expectedHosts = (unit.distributions ?? []).map((distribution) => PLATFORMS.find((platform) => platform.distributionType === distribution.type)).filter(Boolean).map((platform) => platform.buildAdapter.name);
97287
+ const hostCoverage = evaluateDeclaredHostSurfaceCoverage(
97288
+ expectedHosts,
97289
+ closureResult.surfaces
97290
+ );
97291
+ if (!hostCoverage.passed) {
97292
+ await evidence.append({
97293
+ phase: "skill-resource-closure",
97294
+ status: "blocking",
97295
+ unitId: unit.id,
97296
+ reason: "declared-host-surface-missing",
97297
+ missingHosts: hostCoverage.missing
97298
+ });
97299
+ throw new ReleaseError(
97300
+ GATE_FAILED,
97301
+ `skill resource closure gate failed for unit "${unit.id}": declared host surface(s) missing or empty: ${hostCoverage.missing.map((item) => item.host).join(", ")}`,
97302
+ {
97303
+ unitId: unit.id,
97304
+ missingHosts: hostCoverage.missing,
97305
+ observedSurfaces: closureResult.surfaces.map((surface) => ({
97306
+ id: surface.id,
97307
+ host: surface.host,
97308
+ skillCount: surface.skillCount
97309
+ }))
97310
+ }
97311
+ );
97312
+ }
97103
97313
  await evidence.append({
97104
97314
  phase: "skill-resource-closure",
97105
97315
  status: "completed",
@@ -97109,6 +97319,10 @@ async function prepareRelease(options) {
97109
97319
  skillCount: receipt.skillCount,
97110
97320
  referenceCount: closureResult.referenceCount,
97111
97321
  sourceOnlyCount: closureResult.sourceOnlyCount,
97322
+ // D2: per-reference exemption detail for approval/audit review —
97323
+ // evidence-layer only; the receipt object (and its digest binding)
97324
+ // is intentionally left unchanged.
97325
+ sourceOnlyReferences: closureResult.sourceOnlyReferences,
97112
97326
  findingCount: 0,
97113
97327
  receiptDigest: closureResult.receiptDigest
97114
97328
  });
@@ -98779,7 +98993,11 @@ async function publishRelease(options) {
98779
98993
  { unitId, findings: closureResult.findings }
98780
98994
  );
98781
98995
  }
98782
- const observed = createSkillResourceClosureReceipt(closureResult, { unitId });
98996
+ const observed = createSkillResourceClosureReceipt(closureResult, {
98997
+ unitId,
98998
+ preparedAt: expected.preparedAt ?? null,
98999
+ exitCode: expected.exitCode ?? 0
99000
+ });
98783
99001
  assertSkillResourceClosureReceipt(expected, observed, `unit "${unitId}"`);
98784
99002
  }
98785
99003
  await evidence.append({
@@ -107381,13 +107599,14 @@ __export(lineage_exports, {
107381
107599
  listReleaseTags: () => listReleaseTags,
107382
107600
  objectExists: () => objectExists,
107383
107601
  parseArgs: () => parseArgs,
107602
+ parseCommitIdent: () => parseCommitIdent,
107384
107603
  parseReleaseTag: () => parseReleaseTag,
107385
107604
  parseSemverVersion: () => parseSemverVersion2,
107386
107605
  readCommitMeta: () => readCommitMeta,
107387
107606
  rebuildLineage: () => rebuildLineage,
107388
107607
  runLineageCommand: () => runLineageCommand
107389
107608
  });
107390
- import { execFile as execFileCb16 } from "node:child_process";
107609
+ import { execFile as execFileCb16, spawn as spawn4 } from "node:child_process";
107391
107610
  import { promisify as promisify20 } from "node:util";
107392
107611
  function parseSemverVersion2(version) {
107393
107612
  if (typeof version !== "string") {
@@ -107441,6 +107660,26 @@ async function git2(root, args2, options = {}) {
107441
107660
  });
107442
107661
  return stdout.trim();
107443
107662
  }
107663
+ async function gitRaw(root, args2, options = {}) {
107664
+ const { stdout } = await execFile17("git", args2, {
107665
+ cwd: root,
107666
+ encoding: "utf8",
107667
+ maxBuffer: 64 * 1024 * 1024,
107668
+ ...options
107669
+ });
107670
+ return stdout;
107671
+ }
107672
+ function parseCommitIdent(line) {
107673
+ if (typeof line !== "string") {
107674
+ throw new Error(`commit ident line must be a string, got ${typeof line}`);
107675
+ }
107676
+ const match = line.match(/^(.*) <([^>]*)> (\d+) ([+-]\d{4})$/);
107677
+ if (!match) {
107678
+ throw new Error(`unparseable commit ident line (fail-closed): "${line}"`);
107679
+ }
107680
+ const [, name, email, ts, tz] = match;
107681
+ return { name, email, ts, tz };
107682
+ }
107444
107683
  async function getLocalTags(root) {
107445
107684
  const output = await git2(root, ["tag", "-l", "--format=%(refname:short) %(objectname)"]);
107446
107685
  if (!output) return [];
@@ -107473,40 +107712,32 @@ async function objectExists(root, sha) {
107473
107712
  }
107474
107713
  }
107475
107714
  async function readCommitMeta(root, commitSha) {
107476
- const raw = await git2(root, ["cat-file", "commit", commitSha]);
107477
- const lines = raw.split("\n");
107478
- const headers = {};
107479
- const messageLines = [];
107480
- let inBody = false;
107481
- for (const line of lines) {
107482
- if (inBody) {
107483
- messageLines.push(line);
107484
- continue;
107485
- }
107486
- if (line === "") {
107487
- inBody = true;
107488
- continue;
107489
- }
107490
- const colon = line.indexOf(" ");
107491
- if (colon === -1) continue;
107492
- const key = line.slice(0, colon);
107493
- const value = line.slice(colon + 1);
107494
- headers[key] = value;
107715
+ const raw = await gitRaw(root, ["cat-file", "commit", commitSha]);
107716
+ const separator = raw.indexOf("\n\n");
107717
+ if (separator === -1) {
107718
+ throw new Error(`malformed commit object ${commitSha}: missing header/message separator`);
107495
107719
  }
107496
- const message = messageLines.join("\n");
107497
- const authorParts = (headers.author ?? "").split(/\s+>/);
107498
- const committerParts = (headers.committer ?? "").split(/\s+>/);
107720
+ const message = raw.slice(separator + 2);
107721
+ const headers = {};
107722
+ for (const line of raw.slice(0, separator).split("\n")) {
107723
+ if (line.startsWith(" ")) continue;
107724
+ const space = line.indexOf(" ");
107725
+ if (space === -1) continue;
107726
+ headers[line.slice(0, space)] = line.slice(space + 1);
107727
+ }
107728
+ const author = parseCommitIdent(headers.author ?? "");
107729
+ const committer = parseCommitIdent(headers.committer ?? "");
107499
107730
  return {
107500
107731
  message,
107501
107732
  author: {
107502
- name: authorParts[0] ?? "",
107503
- email: (authorParts[1] ?? "").replace(/^</, "").replace(/\d+ [+-]\d{4}$/, "").trim(),
107504
- date: (headers.author ?? "").match(/(\d+ [+-]\d{4})$/)?.[1] ?? ""
107733
+ name: author.name,
107734
+ email: author.email,
107735
+ date: `${author.ts} ${author.tz}`
107505
107736
  },
107506
107737
  committer: {
107507
- name: committerParts[0] ?? "",
107508
- email: (committerParts[1] ?? "").replace(/^</, "").replace(/\d+ [+-]\d{4}$/, "").trim(),
107509
- date: (headers.committer ?? "").match(/(\d+ [+-]\d{4})$/)?.[1] ?? ""
107738
+ name: committer.name,
107739
+ email: committer.email,
107740
+ date: `${committer.ts} ${committer.tz}`
107510
107741
  }
107511
107742
  };
107512
107743
  }
@@ -107591,7 +107822,7 @@ async function analyzeLineage(root) {
107591
107822
  async function createRebuiltCommit(root, treeSha, parentSha, message, identity2) {
107592
107823
  const args2 = ["commit-tree", treeSha];
107593
107824
  if (parentSha) args2.push("-p", parentSha);
107594
- args2.push("-m", message);
107825
+ args2.push("-F", "-");
107595
107826
  const env = {
107596
107827
  ...process.env,
107597
107828
  GIT_AUTHOR_NAME: identity2.author.name,
@@ -107601,8 +107832,31 @@ async function createRebuiltCommit(root, treeSha, parentSha, message, identity2)
107601
107832
  GIT_COMMITTER_EMAIL: identity2.committer.email,
107602
107833
  GIT_COMMITTER_DATE: identity2.committer.date
107603
107834
  };
107604
- const { stdout } = await execFile17("git", args2, { cwd: root, encoding: "utf8", env });
107605
- return stdout.trim();
107835
+ return new Promise((resolvePromise, rejectPromise) => {
107836
+ const child = spawn4("git", args2, { cwd: root, env });
107837
+ let stdout = "";
107838
+ let stderr = "";
107839
+ child.stdout.setEncoding("utf8");
107840
+ child.stderr.setEncoding("utf8");
107841
+ child.stdout.on("data", (chunk) => {
107842
+ stdout += chunk;
107843
+ });
107844
+ child.stderr.on("data", (chunk) => {
107845
+ stderr += chunk;
107846
+ });
107847
+ child.on("error", rejectPromise);
107848
+ child.on("close", (code) => {
107849
+ if (code !== 0) {
107850
+ rejectPromise(new Error(`git commit-tree failed (exit ${code}): ${stderr.trim()}`));
107851
+ return;
107852
+ }
107853
+ resolvePromise(stdout.trim());
107854
+ });
107855
+ child.stdin.on("error", () => {
107856
+ });
107857
+ child.stdin.write(message);
107858
+ child.stdin.end();
107859
+ });
107606
107860
  }
107607
107861
  async function rebuildLineage(root, options = {}) {
107608
107862
  const { dryRun = false } = options;
@@ -107729,6 +107983,8 @@ var init_lineage = __esm({
107729
107983
  __name(compareSemverVersions2, "compareSemverVersions");
107730
107984
  __name(parseReleaseTag, "parseReleaseTag");
107731
107985
  __name(git2, "git");
107986
+ __name(gitRaw, "gitRaw");
107987
+ __name(parseCommitIdent, "parseCommitIdent");
107732
107988
  __name(getLocalTags, "getLocalTags");
107733
107989
  __name(listReleaseTags, "listReleaseTags");
107734
107990
  __name(getCommitTreeHash, "getCommitTreeHash");