@delorenj/skillex 0.1.1 → 0.1.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.
package/dist/cli.js CHANGED
@@ -520,7 +520,8 @@ var PROJECT_CLI_ALIASES = Object.freeze([
520
520
  ".gemini/skills",
521
521
  ".copilot/skills",
522
522
  ".opencode/skills",
523
- ".kimi-code/skills"
523
+ ".kimi-code/skills",
524
+ ".zcode/skills"
524
525
  ]);
525
526
  var NEVER_TOUCH = Object.freeze([".hermes", ".augment", ".cursor", ".crush"]);
526
527
  function aliasPaths(base, scope) {
@@ -531,7 +532,7 @@ function aliasPaths(base, scope) {
531
532
  }
532
533
 
533
534
  // src/core/catalog.ts
534
- import { readdir as readdir3 } from "node:fs/promises";
535
+ import { readdir as readdir4 } from "node:fs/promises";
535
536
  import { join as join7 } from "node:path";
536
537
 
537
538
  // src/core/composition.ts
@@ -954,10 +955,12 @@ async function packInventory(registry, selection2) {
954
955
  }
955
956
 
956
957
  // src/core/discovery.ts
957
- import { lstat as lstat3, realpath as realpath4, stat } from "node:fs/promises";
958
+ import { execFile } from "node:child_process";
959
+ import { lstat as lstat3, readdir as readdir3, readFile as readFile3, realpath as realpath4, stat } from "node:fs/promises";
958
960
  import { homedir as homedir2 } from "node:os";
959
961
  import { dirname as dirname2, join as join5, parse, resolve as resolve3 } from "node:path";
960
962
  import { fileURLToPath } from "node:url";
963
+ import { promisify } from "node:util";
961
964
  var manifestParts = [".agents", "skills.json"];
962
965
  function errorMessage(error) {
963
966
  return error instanceof Error ? error.message : String(error);
@@ -1107,7 +1110,70 @@ async function installedPackageRoot() {
1107
1110
  current = parent;
1108
1111
  }
1109
1112
  }
1110
- async function catalogRoot(path, required) {
1113
+ var execute = promisify(execFile);
1114
+ async function recordedCatalog(root) {
1115
+ const env = {};
1116
+ for (const [key2, value] of Object.entries(process.env))
1117
+ if (!key2.startsWith("GIT_")) env[key2] = value;
1118
+ let stdout;
1119
+ try {
1120
+ ({ stdout } = await execute(
1121
+ "git",
1122
+ ["-C", root, "ls-files", "--stage", "--full-name", "-z", "--", "all-skills"],
1123
+ {
1124
+ encoding: "utf8",
1125
+ maxBuffer: 64 * 1024 * 1024,
1126
+ env: {
1127
+ ...env,
1128
+ GIT_OPTIONAL_LOCKS: "0",
1129
+ GIT_TERMINAL_PROMPT: "0",
1130
+ GIT_CONFIG_NOSYSTEM: "1",
1131
+ GIT_CONFIG_GLOBAL: "/dev/null"
1132
+ }
1133
+ }
1134
+ ));
1135
+ } catch {
1136
+ return void 0;
1137
+ }
1138
+ const records = stdout.split("\0").filter(Boolean);
1139
+ if (records.some((record9) => /^160000 [0-9a-f]+ \d\tall-skills$/.test(record9))) return "gitlink";
1140
+ if (records.some((record9) => /^\d{6} [0-9a-f]+ \d\tall-skills\//.test(record9))) return "tree";
1141
+ return void 0;
1142
+ }
1143
+ async function holdsDefinition(catalog, names2) {
1144
+ for (const name of names2) {
1145
+ try {
1146
+ if ((await stat(join5(catalog, name, "SKILL.md"))).isFile()) return true;
1147
+ } catch {
1148
+ }
1149
+ }
1150
+ return false;
1151
+ }
1152
+ async function uninitializedCatalog(root, catalog) {
1153
+ let declaration;
1154
+ try {
1155
+ declaration = await readFile3(join5(root, ".gitmodules"), "utf8");
1156
+ } catch (error) {
1157
+ if (["ENOENT", "ENOTDIR"].includes(error.code ?? "")) {
1158
+ return void 0;
1159
+ }
1160
+ return ioFailure2(join5(root, ".gitmodules"), error);
1161
+ }
1162
+ if (!/^[\t ]*path[\t ]*=[\t ]*"?all-skills\/?"?[\t ]*$/m.test(declaration)) return void 0;
1163
+ if (await entry(join5(catalog, ".git"))) return void 0;
1164
+ let names2;
1165
+ try {
1166
+ names2 = (await readdir3(catalog)).sort();
1167
+ } catch (error) {
1168
+ return ioFailure2(catalog, error);
1169
+ }
1170
+ if (!names2.length) return names2;
1171
+ const recorded = await recordedCatalog(root);
1172
+ if (recorded === "gitlink") return names2;
1173
+ if (recorded === "tree") return void 0;
1174
+ return await holdsDefinition(catalog, names2) ? void 0 : names2;
1175
+ }
1176
+ async function catalogRoot(path, required, source) {
1111
1177
  const found = await entry(path);
1112
1178
  if (!found) {
1113
1179
  if (!required) return void 0;
@@ -1138,6 +1204,21 @@ async function catalogRoot(path, required) {
1138
1204
  fix: "Select the owning catalog checkout, or run skillex migrate to repair its topology."
1139
1205
  });
1140
1206
  }
1207
+ const leftovers = await uninitializedCatalog(root, catalog);
1208
+ if (leftovers) {
1209
+ const quoted = JSON.stringify(root);
1210
+ const more = leftovers.length > 8 ? `, and ${leftovers.length - 8} more` : "";
1211
+ const clear = leftovers.length ? `First move the entries git left in all-skills/ (${leftovers.slice(0, 8).join(", ")}${more}) somewhere outside it, such as a sibling directory, keeping anything you still need: git will not populate a non-empty directory. Then ` : "";
1212
+ const step = (text2) => clear ? `${clear}${text2}` : `${text2.charAt(0).toUpperCase()}${text2.slice(1)}`;
1213
+ fail(
1214
+ "E_REGISTRY_ROOT",
1215
+ `The registry's all-skills/ catalog is an uninitialized git submodule: ${catalog}`,
1216
+ {
1217
+ path: catalog,
1218
+ fix: source === "cache" ? `skillex never clones or fetches this registry cache. ${step(`bring it current and populate its catalog: git -C ${quoted} pull --ff-only && git -C ${quoted} submodule update --init --recursive.`)} Or drop the manifest's registry field, or pin a complete checkout with PJ_SKILLS_REGISTRY_ROOT.` : `${step(`populate the catalog submodule: git -C ${quoted} submodule update --init --recursive.`)} Or select a complete checkout with --registry-root or PJ_SKILLS_REGISTRY_ROOT.`
1219
+ }
1220
+ );
1221
+ }
1141
1222
  return root;
1142
1223
  }
1143
1224
  async function discoverRegistry(options = {}) {
@@ -1149,7 +1230,7 @@ async function discoverRegistry(options = {}) {
1149
1230
  const path = absolutePath(value, cwd, home, "E_REGISTRY_ROOT", "registry root");
1150
1231
  if (searched.includes(path)) return void 0;
1151
1232
  searched.push(path);
1152
- const root = await catalogRoot(path, required);
1233
+ const root = await catalogRoot(path, required, source);
1153
1234
  return root ? { root, source, searched: [...searched] } : void 0;
1154
1235
  };
1155
1236
  if (options.registryRoot !== void 0) {
@@ -1195,7 +1276,7 @@ async function discoverRegistry(options = {}) {
1195
1276
  }
1196
1277
 
1197
1278
  // src/core/metadata.ts
1198
- import { readFile as readFile3 } from "node:fs/promises";
1279
+ import { readFile as readFile4 } from "node:fs/promises";
1199
1280
  import { join as join6 } from "node:path";
1200
1281
  import { parseDocument } from "yaml";
1201
1282
  function mapping(value) {
@@ -1238,7 +1319,7 @@ async function textFile(path, missing) {
1238
1319
  }
1239
1320
  let bytes;
1240
1321
  try {
1241
- bytes = await readFile3(path);
1322
+ bytes = await readFile4(path);
1242
1323
  } catch {
1243
1324
  fail(
1244
1325
  "E_IO",
@@ -1443,7 +1524,7 @@ async function compositionReferences(registry, findings) {
1443
1524
  await inspectPack(name, path);
1444
1525
  inspected += 1;
1445
1526
  }
1446
- for (const entry3 of (await readdir3(path, { withFileTypes: true })).sort(
1527
+ for (const entry3 of (await readdir4(path, { withFileTypes: true })).sort(
1447
1528
  (a, b) => compare(a.name, b.name)
1448
1529
  )) {
1449
1530
  if (entry3.name.startsWith(".") || entry3.name.startsWith("_")) continue;
@@ -1488,7 +1569,7 @@ async function compositionReferences(registry, findings) {
1488
1569
  try {
1489
1570
  if (!await inspectPath(path)) continue;
1490
1571
  await requireDirectory(path, kind2 === "set" ? "E_SET_MISSING" : "E_PACK_MISSING");
1491
- const entries = (await readdir3(path, { withFileTypes: true })).sort(
1572
+ const entries = (await readdir4(path, { withFileTypes: true })).sort(
1492
1573
  (a, b) => compare(a.name, b.name)
1493
1574
  );
1494
1575
  for (const entry3 of entries) {
@@ -1526,7 +1607,7 @@ async function listSkills(options = {}) {
1526
1607
  let validDefinitions = 0;
1527
1608
  const catalog = join7(registry.root, "all-skills");
1528
1609
  const query = options.query?.trim().toLowerCase();
1529
- for (const entry3 of (await readdir3(catalog, { withFileTypes: true })).sort(
1610
+ for (const entry3 of (await readdir4(catalog, { withFileTypes: true })).sort(
1530
1611
  (a, b) => compare(a.name, b.name)
1531
1612
  )) {
1532
1613
  if (entry3.name.startsWith(".") || entry3.name.startsWith("_")) continue;
@@ -1575,7 +1656,7 @@ async function showSkill(name, options = {}) {
1575
1656
  }
1576
1657
 
1577
1658
  // src/core/catalog-write.ts
1578
- import { chmod, lstat as lstat8, mkdir as mkdir4, open as open4, readFile as readFile6, realpath as realpath9, symlink } from "node:fs/promises";
1659
+ import { chmod, lstat as lstat8, mkdir as mkdir4, open as open4, readFile as readFile7, realpath as realpath9, symlink } from "node:fs/promises";
1579
1660
  import { homedir as homedir5 } from "node:os";
1580
1661
  import { dirname as dirname6, join as join12, resolve as resolve6 } from "node:path";
1581
1662
  import { stringify } from "yaml";
@@ -1591,8 +1672,8 @@ import {
1591
1672
  lstat as lstat4,
1592
1673
  mkdir as mkdir2,
1593
1674
  open as open2,
1594
- readdir as readdir4,
1595
- readFile as readFile4,
1675
+ readdir as readdir5,
1676
+ readFile as readFile5,
1596
1677
  realpath as realpath5,
1597
1678
  rmdir,
1598
1679
  unlink as unlink2
@@ -1697,7 +1778,7 @@ async function claimFiles(claim2) {
1697
1778
  if (!await sameDirectory(claim2.path, claim2.identity)) return void 0;
1698
1779
  let names2;
1699
1780
  try {
1700
- names2 = await readdir4(claim2.path);
1781
+ names2 = await readdir5(claim2.path);
1701
1782
  } catch (error) {
1702
1783
  if (error.code === "ENOENT") return void 0;
1703
1784
  throw error;
@@ -1730,7 +1811,7 @@ async function readTicket(claim2, resource) {
1730
1811
  if (stat6.size > 4096) stateFailure(path, "Lock ticket is too large to be a valid claim.");
1731
1812
  let raw;
1732
1813
  try {
1733
- raw = JSON.parse(await readFile4(path, "utf8"));
1814
+ raw = JSON.parse(await readFile5(path, "utf8"));
1734
1815
  } catch (error) {
1735
1816
  if (error.code === "ENOENT") return void 0;
1736
1817
  if (error instanceof SyntaxError) stateFailure(path, "Lock ticket is malformed JSON.");
@@ -1762,7 +1843,7 @@ async function removeClaim(claim2, expectedTicket, ownedTicket) {
1762
1843
  if (expectedTicket !== void 0 && names2.includes(ticketFile)) {
1763
1844
  let current;
1764
1845
  try {
1765
- current = await readFile4(join8(claim2.path, ticketFile), "utf8");
1846
+ current = await readFile5(join8(claim2.path, ticketFile), "utf8");
1766
1847
  } catch (error) {
1767
1848
  if (error.code !== "ENOENT") throw error;
1768
1849
  }
@@ -1794,7 +1875,7 @@ async function removeClaim(claim2, expectedTicket, ownedTicket) {
1794
1875
  async function claims(path, directory2, resource, localHostHash) {
1795
1876
  if (!await sameDirectory(path, directory2)) stateFailure(path, "Lock directory disappeared.");
1796
1877
  const result = [];
1797
- for (const name of (await readdir4(path)).sort()) {
1878
+ for (const name of (await readdir5(path)).sort()) {
1798
1879
  const claimPath = join8(path, name);
1799
1880
  const identity5 = identityFrom(name, claimPath);
1800
1881
  const stat6 = await inspect2(claimPath);
@@ -1945,7 +2026,7 @@ import {
1945
2026
  lstat as lstat6,
1946
2027
  mkdir as mkdir3,
1947
2028
  open as open3,
1948
- readdir as readdir6,
2029
+ readdir as readdir7,
1949
2030
  realpath as realpath7,
1950
2031
  rename as rename2,
1951
2032
  rmdir as rmdir2,
@@ -1956,16 +2037,14 @@ import { dirname as dirname5, join as join10, relative as relative3, resolve as
1956
2037
 
1957
2038
  // src/core/content.ts
1958
2039
  import { createHash as createHash3 } from "node:crypto";
1959
- import { lstat as lstat5, readdir as readdir5, readFile as readFile5, readlink, realpath as realpath6 } from "node:fs/promises";
2040
+ import { lstat as lstat5, readdir as readdir6, readFile as readFile6, readlink, realpath as realpath6 } from "node:fs/promises";
1960
2041
  import { dirname as dirname4, isAbsolute as isAbsolute2, join as join9, relative as relative2, sep as sep3 } from "node:path";
1961
2042
  function isWithin(root, path) {
1962
2043
  const child = relative2(root, path);
1963
2044
  return child === "" || !isAbsolute2(child) && child !== ".." && !child.startsWith(`..${sep3}`);
1964
2045
  }
2046
+ var repositoryNames = /* @__PURE__ */ new Set([".git", ".hg", ".svn"]);
1965
2047
  var generatedNames = /* @__PURE__ */ new Set([
1966
- ".git",
1967
- ".hg",
1968
- ".svn",
1969
2048
  ".DS_Store",
1970
2049
  "__pycache__",
1971
2050
  ".pytest_cache",
@@ -1976,8 +2055,11 @@ var generatedNames = /* @__PURE__ */ new Set([
1976
2055
  ".venv",
1977
2056
  "node_modules"
1978
2057
  ]);
2058
+ function generatedName(name) {
2059
+ return generatedNames.has(name) || /\.(?:pyc|pyo|pid|sock|db-wal|db-shm)$/.test(name);
2060
+ }
1979
2061
  function excludedName(name) {
1980
- return generatedNames.has(name) || /(?:\.(?:pyc|pyo|pid|sock|db-wal|db-shm|log|bak|orig)|~)$/.test(name) || /(?:\.bak-|-backup\.)/.test(name) || /^\.env(?:\.|$)/.test(name) && ![".env.op", ".env.example", ".env.sample", ".env.template"].includes(name);
2062
+ return repositoryNames.has(name) || generatedName(name) || /(?:\.(?:log|bak|orig)|~)$/.test(name) || /(?:\.bak-|-backup\.)/.test(name) || /^\.env(?:\.|$)/.test(name) && ![".env.op", ".env.example", ".env.sample", ".env.template"].includes(name);
1981
2063
  }
1982
2064
  function contentFailure(path, message) {
1983
2065
  fail(
@@ -1991,7 +2073,7 @@ async function captureContent(root) {
1991
2073
  const entries = [];
1992
2074
  const excluded = [];
1993
2075
  const visit = async (path) => {
1994
- for (const name of (await readdir5(path)).sort()) {
2076
+ for (const name of (await readdir6(path)).sort()) {
1995
2077
  const source = join9(path, name);
1996
2078
  const item2 = relative2(root, source);
1997
2079
  if (excludedName(name)) {
@@ -2003,7 +2085,7 @@ async function captureContent(root) {
2003
2085
  entries.push({ path: item2, kind: "directory", mode: metadata2.mode & 511 });
2004
2086
  await visit(source);
2005
2087
  } else if (metadata2.isFile()) {
2006
- const bytes = await readFile5(source);
2088
+ const bytes = await readFile6(source);
2007
2089
  const after = await lstat5(source);
2008
2090
  if (metadata2.dev !== after.dev || metadata2.ino !== after.ino || metadata2.mode !== after.mode || metadata2.size !== after.size || metadata2.mtimeMs !== after.mtimeMs) {
2009
2091
  contentFailure(source, `Source changed while being inspected: ${source}`);
@@ -2179,7 +2261,7 @@ async function captureVendorTree(root) {
2179
2261
  const before = await lstat6(directory2, { bigint: true });
2180
2262
  if (!before.isDirectory())
2181
2263
  stateFailure2(directory2, "A content parent became a symlink or non-directory.");
2182
- for (const name of (await readdir6(directory2)).sort()) {
2264
+ for (const name of (await readdir7(directory2)).sort()) {
2183
2265
  const path = join10(directory2, name);
2184
2266
  const info = await lstat6(path, { bigint: true });
2185
2267
  if (!info.isFile() && !info.isDirectory())
@@ -2210,7 +2292,7 @@ async function assertVendorTree(root, expected, allowMissing = false) {
2210
2292
  if (identity5?.kind !== "directory")
2211
2293
  stateFailure2(directory2, "A recovery parent has no directory ownership evidence.");
2212
2294
  await assertVendorIdentity(directory2, identity5);
2213
- for (const name of await readdir6(directory2)) {
2295
+ for (const name of await readdir7(directory2)) {
2214
2296
  const path = join10(directory2, name);
2215
2297
  const item2 = relative3(root, path);
2216
2298
  const entry3 = expectedEntries.get(item2);
@@ -2790,7 +2872,7 @@ async function importSkill(source, name, options = {}) {
2790
2872
  const metadata2 = await readSkillMetadata(sourceRoot);
2791
2873
  for (const name2 of ["SKILL.md", ".source.yaml"]) {
2792
2874
  const captured = content.entries.find((entry3) => entry3.path === name2);
2793
- if (captured?.kind === "file" && !captured.bytes.equals(await readFile6(join12(sourceRoot, name2)))) {
2875
+ if (captured?.kind === "file" && !captured.bytes.equals(await readFile7(join12(sourceRoot, name2)))) {
2794
2876
  fail("E_IMPORT_SOURCE_CHANGED", "Skill metadata changed while import was being planned.", {
2795
2877
  path: join12(sourceRoot, name2),
2796
2878
  fix: "Retry after the source writer has finished."
@@ -2844,12 +2926,12 @@ async function importSkill(source, name, options = {}) {
2844
2926
  }
2845
2927
 
2846
2928
  // src/core/diagnostics.ts
2847
- import { readdir as readdir10, realpath as realpath13 } from "node:fs/promises";
2929
+ import { readdir as readdir11, realpath as realpath13 } from "node:fs/promises";
2848
2930
  import { homedir as homedir6 } from "node:os";
2849
2931
  import { dirname as dirname10, join as join17, parse as parse2, resolve as resolve9, sep as sep5 } from "node:path";
2850
2932
 
2851
2933
  // src/core/activation-ownership.ts
2852
- import { lstat as lstat9, readdir as readdir7, readlink as readlink2 } from "node:fs/promises";
2934
+ import { lstat as lstat9, readdir as readdir8, readlink as readlink2 } from "node:fs/promises";
2853
2935
  import { dirname as dirname7, isAbsolute as isAbsolute3, join as join13, relative as relative4, resolve as resolve7 } from "node:path";
2854
2936
  function refuse(path, message, code = "E_ACTIVATION_CONFLICT") {
2855
2937
  fail(
@@ -2908,7 +2990,7 @@ async function inspectOwnedNode(path, node, missingOkay = false) {
2908
2990
  const actual = await requireIdentity(path, node.identity, missingOkay);
2909
2991
  if (!actual) return false;
2910
2992
  if (node.identity.kind === "directory") {
2911
- for (const name of await readdir7(path)) {
2993
+ for (const name of await readdir8(path)) {
2912
2994
  const expected = node.children?.[name];
2913
2995
  if (!expected)
2914
2996
  refuse(
@@ -2990,14 +3072,14 @@ function lexicalTarget(path, raw) {
2990
3072
  }
2991
3073
 
2992
3074
  // src/core/reconciliation.ts
2993
- import { execFile } from "node:child_process";
3075
+ import { execFile as execFile2 } from "node:child_process";
2994
3076
  import { createHash as createHash5, randomUUID as randomUUID5 } from "node:crypto";
2995
- import { mkdir as mkdir6, readdir as readdir9, realpath as realpath12, rename as rename4, rmdir as rmdir3, symlink as symlink3, unlink as unlink5 } from "node:fs/promises";
3077
+ import { mkdir as mkdir6, readdir as readdir10, realpath as realpath12, rename as rename4, rmdir as rmdir3, symlink as symlink3, unlink as unlink5 } from "node:fs/promises";
2996
3078
  import { basename as basename3, dirname as dirname9, join as join16, relative as relative6, resolve as resolve8, sep as sep4 } from "node:path";
2997
- import { promisify } from "node:util";
3079
+ import { promisify as promisify2 } from "node:util";
2998
3080
 
2999
3081
  // src/core/packs.ts
3000
- import { lstat as lstat11, readdir as readdir8, readFile as readFile8, realpath as realpath11 } from "node:fs/promises";
3082
+ import { lstat as lstat11, readdir as readdir9, readFile as readFile9, realpath as realpath11 } from "node:fs/promises";
3001
3083
  import { join as join15 } from "node:path";
3002
3084
  import { parse as parseToml2, stringify as stringifyToml } from "smol-toml";
3003
3085
 
@@ -3008,7 +3090,7 @@ import {
3008
3090
  lstat as lstat10,
3009
3091
  mkdir as mkdir5,
3010
3092
  open as open5,
3011
- readFile as readFile7,
3093
+ readFile as readFile8,
3012
3094
  readlink as readlink3,
3013
3095
  realpath as realpath10,
3014
3096
  rename as rename3,
@@ -3135,7 +3217,7 @@ async function saveManifest(plan2, changed3) {
3135
3217
  await parents(plan2, manifest.path);
3136
3218
  const info = await inspectPath(manifest.path);
3137
3219
  if (manifest.before) {
3138
- if (!info?.isFile() || info.dev !== manifest.before.info.dev || info.ino !== manifest.before.info.ino || !(await readFile7(manifest.path)).equals(manifest.before.bytes))
3220
+ if (!info?.isFile() || info.dev !== manifest.before.info.dev || info.ino !== manifest.before.info.ino || !(await readFile8(manifest.path)).equals(manifest.before.bytes))
3139
3221
  conflict(manifest.path, "The pack declaration changed while writing was being planned.");
3140
3222
  } else if (info) conflict(manifest.path, "A pack manifest appeared during creation.");
3141
3223
  };
@@ -3301,7 +3383,7 @@ async function readPack(registry, selected) {
3301
3383
  const path = join15(first.path, "pack.toml");
3302
3384
  const info = await lstat11(path);
3303
3385
  if (!info.isFile()) conflict(path, "Pack manifests must be real files.");
3304
- const bytes = await readFile8(path);
3386
+ const bytes = await readFile9(path);
3305
3387
  let raw;
3306
3388
  try {
3307
3389
  raw = parseToml2(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
@@ -3314,7 +3396,7 @@ async function readPack(registry, selected) {
3314
3396
  }
3315
3397
  const inventory = await packInventory(registry, selected);
3316
3398
  const after = await lstat11(path);
3317
- if (inventory.path !== first.path || !after.isFile() || after.dev !== info.dev || after.ino !== info.ino || !(await readFile8(path)).equals(bytes))
3399
+ if (inventory.path !== first.path || !after.isFile() || after.dev !== info.dev || after.ino !== info.ino || !(await readFile9(path)).equals(bytes))
3318
3400
  conflict(path, "The pack declaration changed during inspection.");
3319
3401
  const header = raw.pack;
3320
3402
  const text2 = description(header.description, path);
@@ -3361,7 +3443,7 @@ async function listPacks(options = {}) {
3361
3443
  };
3362
3444
  if (await inspectPath(root)) {
3363
3445
  await requireDirectory(root, "E_PACK_MISSING");
3364
- for (const family of (await readdir8(root, { withFileTypes: true })).sort(
3446
+ for (const family of (await readdir9(root, { withFileTypes: true })).sort(
3365
3447
  (a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0
3366
3448
  )) {
3367
3449
  if (family.name.startsWith(".") || family.name.startsWith("_") || !family.isDirectory() && !family.isSymbolicLink())
@@ -3377,7 +3459,7 @@ async function listPacks(options = {}) {
3377
3459
  await inspect6(named, path);
3378
3460
  inspected += 1;
3379
3461
  }
3380
- for (const entry3 of (await readdir8(path, { withFileTypes: true })).sort(
3462
+ for (const entry3 of (await readdir9(path, { withFileTypes: true })).sort(
3381
3463
  (a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0
3382
3464
  )) {
3383
3465
  if (entry3.name.startsWith(".") || entry3.name.startsWith("_") || !entry3.isDirectory() && !entry3.isSymbolicLink())
@@ -3463,7 +3545,7 @@ async function verifyPack(ref, options = {}) {
3463
3545
  );
3464
3546
  else {
3465
3547
  const names2 = new Set(inventory.names);
3466
- const entries = await readdir8(inventory.skillsRoot, { withFileTypes: true });
3548
+ const entries = await readdir9(inventory.skillsRoot, { withFileTypes: true });
3467
3549
  const present = new Set(entries.map((entry3) => entry3.name));
3468
3550
  for (const name of names2)
3469
3551
  if (!present.has(name))
@@ -3541,7 +3623,7 @@ async function preparePack(selected, names2, operation, options) {
3541
3623
  const root = join15(composition2.path, "skills");
3542
3624
  await planDirectory(plan2, root);
3543
3625
  if (await inspectPath(root)) {
3544
- for (const entry3 of await readdir8(root, { withFileTypes: true })) {
3626
+ for (const entry3 of await readdir9(root, { withFileTypes: true })) {
3545
3627
  const path = join15(root, entry3.name);
3546
3628
  const target2 = targets.get(entry3.name);
3547
3629
  if (target2) await planLink(plan2, path, target2);
@@ -3835,7 +3917,7 @@ async function resolveSelectionWithManifests(options = {}, proposed = /* @__PURE
3835
3917
  }
3836
3918
 
3837
3919
  // src/core/reconciliation.ts
3838
- var runFile = promisify(execFile);
3920
+ var runFile = promisify2(execFile2);
3839
3921
  var lockResource = "skillex:activation:v2";
3840
3922
  function errorResult(command, error) {
3841
3923
  return makeResult(command, null, {
@@ -4129,7 +4211,7 @@ async function buildScope(scope, options, forbiddenRoots) {
4129
4211
  }
4130
4212
  return { identity: owned3, children };
4131
4213
  };
4132
- const awaitableNames = rootEntry?.info.isDirectory() ? await readdir9(physicalPath(root, recovery)) : [];
4214
+ const awaitableNames = rootEntry?.info.isDirectory() ? await readdir10(physicalPath(root, recovery)) : [];
4133
4215
  if (!rootEntry) {
4134
4216
  operations.push({
4135
4217
  path: root,
@@ -4905,7 +4987,7 @@ async function observeScope(location2, resolved, manifest, options, forbiddenRoo
4905
4987
  const entries = [];
4906
4988
  if (observedRoot.observation.reachable && ["directory", "link"].includes(observedRoot.observation.kind)) {
4907
4989
  try {
4908
- const names2 = (await readdir10(root)).sort();
4990
+ const names2 = (await readdir11(root)).sort();
4909
4991
  for (const name of names2) {
4910
4992
  cancelled(options);
4911
4993
  const path = join17(root, name);
@@ -5251,14 +5333,14 @@ async function explainSkill(name, options = {}) {
5251
5333
  }
5252
5334
 
5253
5335
  // src/core/doctor-sources.ts
5254
- import { readdir as readdir12, readFile as readFile9, realpath as realpath15 } from "node:fs/promises";
5336
+ import { readdir as readdir13, readFile as readFile10, realpath as realpath15 } from "node:fs/promises";
5255
5337
  import { basename as basename4, dirname as dirname11, join as join20, relative as relative8, sep as sep7 } from "node:path";
5256
5338
  import { parse as parseToml4 } from "smol-toml";
5257
5339
 
5258
5340
  // src/core/vendor-provenance.ts
5259
5341
  import { createHash as createHash6 } from "node:crypto";
5260
5342
  import { constants as constants4 } from "node:fs";
5261
- import { lstat as lstat13, open as open7, readdir as readdir11 } from "node:fs/promises";
5343
+ import { lstat as lstat13, open as open7, readdir as readdir12 } from "node:fs/promises";
5262
5344
  import { join as join19, relative as relative7, sep as sep6 } from "node:path";
5263
5345
  import { stringify as stringify2 } from "yaml";
5264
5346
 
@@ -5770,7 +5852,7 @@ async function digestVendorTree(skillPath) {
5770
5852
  const before = await lstat13(directory2);
5771
5853
  if (!before.isDirectory())
5772
5854
  unsafe(directory2, "Vendored skill directories must be real directories.");
5773
- for (const name of (await readdir11(directory2)).sort()) {
5855
+ for (const name of (await readdir12(directory2)).sort()) {
5774
5856
  if (directory2 === root && name === ".source.yaml") continue;
5775
5857
  const path = join19(directory2, name);
5776
5858
  if (administration.has(name))
@@ -5822,7 +5904,7 @@ async function digestRecordedSkill(skillPath, provenance) {
5822
5904
  async function appendRegularContent(root, path, entries) {
5823
5905
  const info = await lstat13(path);
5824
5906
  if (info.isDirectory()) {
5825
- for (const name of (await readdir11(path)).sort()) {
5907
+ for (const name of (await readdir12(path)).sort()) {
5826
5908
  if (administration.has(name))
5827
5909
  unsafe(join19(path, name), "Repository administration is not vendored skill content.");
5828
5910
  await appendRegularContent(root, join19(path, name), entries);
@@ -6066,7 +6148,7 @@ async function inspectDoctorSources(registry) {
6066
6148
  };
6067
6149
  await attempt(catalog, async () => {
6068
6150
  await requireDirectory(catalog, "E_NO_REGISTRY");
6069
- for (const name of (await readdir12(catalog)).sort()) {
6151
+ for (const name of (await readdir13(catalog)).sort()) {
6070
6152
  if (name === ".git") continue;
6071
6153
  const path = join20(catalog, name);
6072
6154
  await attempt(path, async () => {
@@ -6097,7 +6179,7 @@ async function inspectDoctorSources(registry) {
6097
6179
  });
6098
6180
  const packManifests = [];
6099
6181
  const walk = async (directory2) => {
6100
- const names2 = await attempt(directory2, () => readdir12(directory2));
6182
+ const names2 = await attempt(directory2, () => readdir13(directory2));
6101
6183
  for (const name of (names2 ?? []).sort()) {
6102
6184
  if (name === ".git") continue;
6103
6185
  const path = join20(directory2, name);
@@ -6132,7 +6214,7 @@ async function inspectDoctorSources(registry) {
6132
6214
  if (!await inspectPath(root)) return;
6133
6215
  await requireDirectory(root, "E_COMPOSITION_ROOT");
6134
6216
  await walk(root);
6135
- for (const name of (await readdir12(root)).sort()) {
6217
+ for (const name of (await readdir13(root)).sort()) {
6136
6218
  if (!isSkillName(name)) continue;
6137
6219
  const path = join20(root, name);
6138
6220
  const info = await inspectPath(path);
@@ -6144,7 +6226,7 @@ async function inspectDoctorSources(registry) {
6144
6226
  if (kind2 !== "sets" || !info.isDirectory()) continue;
6145
6227
  data2.sets++;
6146
6228
  const members2 = await attempt(path, () => setMembers(registry.root, name));
6147
- const names2 = members2?.names ?? (await readdir12(path, { withFileTypes: true })).filter((item2) => item2.isSymbolicLink() && isSkillName(item2.name)).map((item2) => item2.name);
6229
+ const names2 = members2?.names ?? (await readdir13(path, { withFileTypes: true })).filter((item2) => item2.isSymbolicLink() && isSkillName(item2.name)).map((item2) => item2.name);
6148
6230
  for (const member of names2)
6149
6231
  await attempt(join20(path, member), () => setMemberTarget(registry.root, path, member));
6150
6232
  }
@@ -6182,7 +6264,7 @@ async function inspectDoctorSources(registry) {
6182
6264
  return { data: data2, findings, exits };
6183
6265
  }
6184
6266
  async function toml(path, code) {
6185
- const bytes = await readFile9(path);
6267
+ const bytes = await readFile10(path);
6186
6268
  try {
6187
6269
  return parseToml4(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
6188
6270
  } catch {
@@ -6194,8 +6276,8 @@ async function toml(path, code) {
6194
6276
  }
6195
6277
 
6196
6278
  // src/core/doctor-writers.ts
6197
- import { execFile as execFile2 } from "node:child_process";
6198
- import { readdir as readdir13, readFile as readFile10, realpath as realpath16, stat as stat3 } from "node:fs/promises";
6279
+ import { execFile as execFile3 } from "node:child_process";
6280
+ import { readdir as readdir14, readFile as readFile11, realpath as realpath16, stat as stat3 } from "node:fs/promises";
6199
6281
  import { homedir as homedir8 } from "node:os";
6200
6282
  import { basename as basename5, dirname as dirname12, join as join21, resolve as resolve11 } from "node:path";
6201
6283
  import { parse as parseToml5 } from "smol-toml";
@@ -6417,12 +6499,12 @@ async function inspectDoctorWriters(options, registries, scopes) {
6417
6499
  };
6418
6500
  const serviceRoot = join21(configHome, "systemd", "user");
6419
6501
  try {
6420
- for (const entry3 of await readdir13(serviceRoot, { withFileTypes: true })) {
6502
+ for (const entry3 of await readdir14(serviceRoot, { withFileTypes: true })) {
6421
6503
  const path = join21(serviceRoot, entry3.name);
6422
6504
  if (entry3.name.endsWith(".service")) candidates.set(path, "service");
6423
6505
  else if (entry3.isDirectory() && entry3.name.endsWith(".service.d")) {
6424
6506
  try {
6425
- for (const file of await readdir13(path))
6507
+ for (const file of await readdir14(path))
6426
6508
  if (file.endsWith(".conf")) candidates.set(join21(path, file), "service");
6427
6509
  } catch {
6428
6510
  unavailable(path, "Cannot inspect user service overrides.");
@@ -6442,7 +6524,7 @@ async function inspectDoctorWriters(options, registries, scopes) {
6442
6524
  unavailable(path, "Writer configuration is not a bounded regular file.");
6443
6525
  continue;
6444
6526
  }
6445
- const content = new TextDecoder("utf-8", { fatal: true }).decode(await readFile10(path));
6527
+ const content = new TextDecoder("utf-8", { fatal: true }).decode(await readFile11(path));
6446
6528
  const lines = content.split(/\r?\n/);
6447
6529
  if (kind2 === "service") {
6448
6530
  for (const [index, line] of lines.entries()) {
@@ -6520,7 +6602,7 @@ async function inspectDoctorWriters(options, registries, scopes) {
6520
6602
  }
6521
6603
  async function boundedSnapshot(options, env) {
6522
6604
  const observation = options.processSnapshot ? options.processSnapshot() : new Promise((accept, reject) => {
6523
- execFile2(
6605
+ execFile3(
6524
6606
  "ps",
6525
6607
  ["-axo", "pid=,args="],
6526
6608
  { env, timeout: timeoutMs, maxBuffer: maxProcessBytes, encoding: "utf8" },
@@ -6690,14 +6772,14 @@ import { realpath as realpath21, stat as stat4 } from "node:fs/promises";
6690
6772
  // src/core/migration-activation.ts
6691
6773
  import { createHash as createHash8, randomUUID as randomUUID6 } from "node:crypto";
6692
6774
  import { constants as constants6 } from "node:fs";
6693
- import { mkdir as mkdir7, open as open9, readdir as readdir16, realpath as realpath18, rename as rename5, symlink as symlink4 } from "node:fs/promises";
6775
+ import { mkdir as mkdir7, open as open9, readdir as readdir17, realpath as realpath18, rename as rename5, symlink as symlink4 } from "node:fs/promises";
6694
6776
  import { dirname as dirname16, isAbsolute as isAbsolute7, join as join25, parse as parse3, relative as relative10, resolve as resolve14 } from "node:path";
6695
6777
  import { isDeepStrictEqual as isDeepStrictEqual4 } from "node:util";
6696
6778
 
6697
6779
  // src/core/migration-activation-state.ts
6698
6780
  import { createHash as createHash7 } from "node:crypto";
6699
6781
  import { constants as constants5 } from "node:fs";
6700
- import { lstat as lstat14, open as open8, readdir as readdir14, readlink as readlink4, rmdir as rmdir4, unlink as unlink6 } from "node:fs/promises";
6782
+ import { lstat as lstat14, open as open8, readdir as readdir15, readlink as readlink4, rmdir as rmdir4, unlink as unlink6 } from "node:fs/promises";
6701
6783
  import { dirname as dirname13, isAbsolute as isAbsolute5, join as join22, relative as relative9, resolve as resolve12 } from "node:path";
6702
6784
  import { isDeepStrictEqual as isDeepStrictEqual2 } from "node:util";
6703
6785
  import { parseDocument as parseDocument2 } from "yaml";
@@ -6739,7 +6821,7 @@ async function captureMigrationNode(path) {
6739
6821
  const children = {};
6740
6822
  let hash4 = null;
6741
6823
  if (before.isDirectory()) {
6742
- const names2 = await readdir14(path, { encoding: "buffer" });
6824
+ const names2 = await readdir15(path, { encoding: "buffer" });
6743
6825
  if (names2.length > 1e4)
6744
6826
  migrationRefusal(path, "A migration directory exceeds the bounded inventory limit.");
6745
6827
  for (const bytes of names2.sort(Buffer.compare)) {
@@ -6955,7 +7037,7 @@ function migrationAbsolute(value, home, cwd) {
6955
7037
  }
6956
7038
 
6957
7039
  // src/core/profile-discovery.ts
6958
- import { lstat as lstat15, readdir as readdir15, readlink as readlink5, realpath as realpath17 } from "node:fs/promises";
7040
+ import { lstat as lstat15, readdir as readdir16, readlink as readlink5, realpath as realpath17 } from "node:fs/promises";
6959
7041
  import { homedir as homedir9 } from "node:os";
6960
7042
  import { basename as basename6, dirname as dirname14, join as join23, resolve as resolve13 } from "node:path";
6961
7043
  var namePattern = /^[a-z0-9][a-z0-9_-]{0,63}$/;
@@ -7198,7 +7280,7 @@ async function discoverProfiles(options = {}) {
7198
7280
  await canonicalDirectory(directory2, false);
7199
7281
  let names2;
7200
7282
  try {
7201
- names2 = (await readdir15(directory2, { withFileTypes: true })).filter(
7283
+ names2 = (await readdir16(directory2, { withFileTypes: true })).filter(
7202
7284
  (entry3) => entry3.name !== "default" && namePattern.test(entry3.name) && (entry3.isDirectory() || entry3.isSymbolicLink())
7203
7285
  ).map((entry3) => entry3.name).sort();
7204
7286
  } catch (error) {
@@ -7770,7 +7852,7 @@ async function collectArtifacts(plan2) {
7770
7852
  await guard(plan2.target, join25(parent, "child"));
7771
7853
  const current = await entry2(parent);
7772
7854
  if (!current) continue;
7773
- for (const name of await readdir16(parent)) {
7855
+ for (const name of await readdir17(parent)) {
7774
7856
  if (!/^\.skillex-tmp-migration-[a-f0-9-]+-(?:new|old)$/.test(name)) continue;
7775
7857
  const path = join25(parent, name);
7776
7858
  if (path === pending?.stage || path === pending?.parked) continue;
@@ -8313,7 +8395,7 @@ async function finishPending(target2, state, begin = () => {
8313
8395
  verified: state.data.verified
8314
8396
  });
8315
8397
  }
8316
- async function execute(target2, operation, state, mark, begin) {
8398
+ async function execute2(target2, operation, state, mark, begin) {
8317
8399
  check(target2.options);
8318
8400
  await guard(target2, operation.item.path);
8319
8401
  for (const proof of operation.proofs) await assertMigrationNode(proof.path, proof.node);
@@ -8590,7 +8672,7 @@ async function migrateActivation(options = {}) {
8590
8672
  "The migration item did not converge after publication."
8591
8673
  );
8592
8674
  attempted.add(operation.item.id);
8593
- state = await execute(
8675
+ state = await execute2(
8594
8676
  selected,
8595
8677
  operation,
8596
8678
  current.state,
@@ -8857,7 +8939,7 @@ import {
8857
8939
  lstat as lstat16,
8858
8940
  mkdir as mkdir8,
8859
8941
  open as open10,
8860
- readdir as readdir17,
8942
+ readdir as readdir18,
8861
8943
  readlink as readlink6,
8862
8944
  rename as rename6,
8863
8945
  rmdir as rmdir5,
@@ -8952,6 +9034,7 @@ async function captureMigrationTree(root) {
8952
9034
  const initial = await migrationLstat(root);
8953
9035
  if (!initial) return null;
8954
9036
  const entries = [];
9037
+ const excluded = [];
8955
9038
  const evidence2 = [];
8956
9039
  const visit = async (path, relpath) => {
8957
9040
  const before = await lstat16(path, { bigint: true });
@@ -8974,14 +9057,19 @@ async function captureMigrationTree(root) {
8974
9057
  target: target2 ?? null
8975
9058
  });
8976
9059
  if (id.kind === "directory") {
8977
- for (const name of (await readdir17(path)).sort()) {
9060
+ for (const name of (await readdir18(path)).sort()) {
8978
9061
  if ([".git", ".hg", ".svn"].includes(name))
8979
9062
  migrationFailure2(
8980
9063
  join27(path, name),
8981
9064
  "A definition or composition contains repository administration; map its authored content explicitly.",
8982
9065
  "E_MIGRATION_CONTENT"
8983
9066
  );
8984
- await visit(join27(path, name), relpath ? join27(relpath, name) : name);
9067
+ const child = relpath ? join27(relpath, name) : name;
9068
+ if (generatedName(name)) {
9069
+ excluded.push(child);
9070
+ continue;
9071
+ }
9072
+ await visit(join27(path, name), child);
8985
9073
  }
8986
9074
  }
8987
9075
  if (!stable2(before, await lstat16(path, { bigint: true })))
@@ -8992,9 +9080,23 @@ async function captureMigrationTree(root) {
8992
9080
  migrationFailure2(root, "Source root was replaced while it was inspected.");
8993
9081
  return {
8994
9082
  entries,
8995
- evidence: { root: identity3(initial), entries: evidence2, digest: migrationTreeDigest(entries) }
9083
+ evidence: { root: identity3(initial), entries: evidence2, digest: migrationTreeDigest(entries) },
9084
+ excluded
8996
9085
  };
8997
9086
  }
9087
+ function refuseExcludedRemoval(path, tree) {
9088
+ const first = tree.excluded[0];
9089
+ if (first === void 0) return;
9090
+ fail(
9091
+ "E_MIGRATION_RUNTIME_CONTENT",
9092
+ `Migration would remove generated build, cache, or runtime content it never migrates: ${tree.excluded.join(", ")}`,
9093
+ {
9094
+ path: join27(path, first),
9095
+ fix: "Remove only verified generated entries (their tools rebuild them), or move them elsewhere, then rerun the migration preview."
9096
+ },
9097
+ ExitCode.REFUSED
9098
+ );
9099
+ }
8998
9100
  async function assertMigrationIdentity(path, expected) {
8999
9101
  if (!equalIdentity2(await migrationLstat(path), expected))
9000
9102
  migrationFailure2(path, "A migration entry changed identity.");
@@ -9104,6 +9206,7 @@ async function removeMigrationTree(path, expected) {
9104
9206
  const currentTree = await captureMigrationTree(path);
9105
9207
  if (!currentTree) return;
9106
9208
  await assertMigrationIdentity(path, expected.root);
9209
+ refuseExcludedRemoval(path, currentTree);
9107
9210
  for (const current of currentTree.evidence.entries) {
9108
9211
  const known = expected.entries.find((entry3) => entry3.path === current.path);
9109
9212
  if (!known || JSON.stringify(known) !== JSON.stringify(current))
@@ -9210,6 +9313,7 @@ async function publishMigrationOperation(operation) {
9210
9313
  } else {
9211
9314
  if (destination) {
9212
9315
  await assertMigrationTree(operation.path, operation.before);
9316
+ refuseExcludedRemoval(operation.path, destination);
9213
9317
  if (!operation.parked || parked)
9214
9318
  migrationFailure2(operation.path, "Cannot park the original migration entry safely.");
9215
9319
  await assertMigrationTree(operation.parked, null);
@@ -10356,7 +10460,7 @@ async function migrateManifest(options, nameMap = {}) {
10356
10460
 
10357
10461
  // src/core/migration-registry.ts
10358
10462
  import { createHash as createHash10 } from "node:crypto";
10359
- import { lstat as lstat18, readdir as readdir18, realpath as realpath20 } from "node:fs/promises";
10463
+ import { lstat as lstat18, readdir as readdir19, realpath as realpath20 } from "node:fs/promises";
10360
10464
  import { basename as basename8, dirname as dirname19, isAbsolute as isAbsolute10, join as join29, relative as relative13, sep as sep9 } from "node:path";
10361
10465
  import { parse as parseToml7, stringify as stringifyToml2 } from "smol-toml";
10362
10466
  function record8(value) {
@@ -10374,7 +10478,7 @@ function payloadDigest(entries) {
10374
10478
  async function sameCaseOnlyEntry(source, destination, before) {
10375
10479
  if (dirname19(source) !== dirname19(destination) || basename8(source) === basename8(destination) || basename8(source).toLowerCase() !== basename8(destination).toLowerCase())
10376
10480
  return false;
10377
- const names2 = await readdir18(dirname19(source));
10481
+ const names2 = await readdir19(dirname19(source));
10378
10482
  if (!names2.includes(basename8(source)) || names2.includes(basename8(destination))) return false;
10379
10483
  const destinationTree = await captureMigrationTree(destination);
10380
10484
  return JSON.stringify(destinationTree?.evidence) === JSON.stringify(before);
@@ -10454,6 +10558,26 @@ function refuse2(path, code, message) {
10454
10558
  ExitCode.REFUSED
10455
10559
  );
10456
10560
  }
10561
+ var runtimeContentFix = "Remove only verified generated entries (their tools rebuild them), or move them outside the composition, then rerun the migration preview.";
10562
+ function runtimeContentMessage(holder) {
10563
+ return `A ${holder} contains generated build, cache, or runtime content that migration never carries or removes.`;
10564
+ }
10565
+ function hiddenPath(path) {
10566
+ return path.split(sep9).some((part) => part.startsWith(".") || part.startsWith("_"));
10567
+ }
10568
+ function skippedDetail(skipped, where) {
10569
+ return skipped.length ? [
10570
+ `Generated build, cache, or runtime entries ${where} are not definition content: they are not copied, not carried, and stay at the source: ${skipped.join(", ")}`
10571
+ ] : [];
10572
+ }
10573
+ function runtimeContent(path, holder) {
10574
+ fail(
10575
+ "E_MIGRATION_RUNTIME_CONTENT",
10576
+ runtimeContentMessage(holder),
10577
+ { path, fix: runtimeContentFix },
10578
+ ExitCode.REFUSED
10579
+ );
10580
+ }
10457
10581
  function safeKey(value) {
10458
10582
  const parts = value.split("/");
10459
10583
  return !!value && !value.includes("\\") && ![...value].some(
@@ -10588,21 +10712,15 @@ async function importDefinition(plan2, lexicalSource, preferred, selected) {
10588
10712
  if (metadata2.provenance) plan2.provenance[lexicalSource] = metadata2.provenance;
10589
10713
  const tree = selected ? {
10590
10714
  entries: selected,
10591
- evidence: { ...captured.evidence, digest: migrationTreeDigest(selected) }
10715
+ evidence: { ...captured.evidence, digest: migrationTreeDigest(selected) },
10716
+ excluded: captured.excluded
10592
10717
  } : captured;
10593
- const runtime = tree.entries.find(
10594
- (entry3) => entry3.path.split(sep9).some((part) => part === "__pycache__" || /\.py[co]$/.test(part))
10595
- );
10596
- if (runtime)
10597
- fail(
10598
- "E_MIGRATION_RUNTIME_CONTENT",
10599
- "A candidate definition contains generated Python cache content.",
10600
- {
10601
- path: join29(lexicalSource, runtime.path),
10602
- fix: "Remove only verified generated Python cache entries from the source, then rerun the migration preview."
10603
- },
10604
- ExitCode.REFUSED
10605
- );
10718
+ const skipped = selected ? captured.excluded.filter(
10719
+ (item2) => selected.some(
10720
+ (entry3) => entry3.kind === "directory" && entry3.path !== "" && item2.startsWith(`${entry3.path}${sep9}`)
10721
+ )
10722
+ ) : captured.excluded;
10723
+ plan2.skipped.set(lexicalSource, skipped);
10606
10724
  const expected = mapped(plan2.options.mapping?.digests, plan2, lexicalSource) ?? mapped(plan2.options.mapping?.digests, plan2, source);
10607
10725
  if (expected !== void 0 && expected !== tree.evidence.digest)
10608
10726
  refuse2(
@@ -10655,7 +10773,8 @@ async function importDefinition(plan2, lexicalSource, preferred, selected) {
10655
10773
  details: [
10656
10774
  `source: ${lexicalSource}`,
10657
10775
  `canonical name: ${name}`,
10658
- "All captured definition bytes, support entries, modes, and provenance are preserved; internal absolute links are made portable."
10776
+ skipped.length ? "Every authored definition byte, support entry, mode, and provenance is preserved; internal absolute links are made portable." : "All captured definition bytes, support entries, modes, and provenance are preserved; internal absolute links are made portable.",
10777
+ ...skippedDetail(skipped, "at this source")
10659
10778
  ],
10660
10779
  dependsOn: []
10661
10780
  };
@@ -10675,7 +10794,8 @@ async function importDefinition(plan2, lexicalSource, preferred, selected) {
10675
10794
  beforeDigest: tree.evidence.digest,
10676
10795
  afterDigest: reused.digest,
10677
10796
  details: [
10678
- dependency ? "Definition is retained at its canonical destination before its original composition entry is replaced." : "Existing canonical authored payload is identical; differing original provenance is preserved separately in the migration receipt."
10797
+ dependency ? "Definition is retained at its canonical destination before its original composition entry is replaced." : "Existing canonical authored payload is identical; differing original provenance is preserved separately in the migration receipt.",
10798
+ ...skippedDetail(skipped, "at this source")
10679
10799
  ],
10680
10800
  dependsOn: dependency ? [dependency] : []
10681
10801
  });
@@ -10835,6 +10955,8 @@ async function composition(plan2, path, kind2) {
10835
10955
  "E_MIGRATION_REFERENCE",
10836
10956
  "A null reference mapping cannot remove a real definition; name and preserve its content instead."
10837
10957
  );
10958
+ const generated = before.excluded.find((item3) => item3.startsWith(`${definition}${sep9}`));
10959
+ if (generated !== void 0) runtimeContent(join29(path, generated), "candidate definition");
10838
10960
  const skill2 = await importDefinition(plan2, lexical, basename8(definition));
10839
10961
  members2.push({
10840
10962
  relativePath: definition,
@@ -10849,7 +10971,9 @@ async function composition(plan2, path, kind2) {
10849
10971
  }
10850
10972
  }
10851
10973
  for (const entry3 of tree.entries) {
10852
- if (!entry3.path || entry3.kind !== "link" || definitionRoots.some((parent) => entry3.path.startsWith(`${parent}${sep9}`)))
10974
+ if (!entry3.path || entry3.kind !== "link" || // A hidden link is outside the composition's namespace: never a member, never rewritten,
10975
+ // and its referent (often installer-owned) is never imported into the catalog.
10976
+ hiddenPath(entry3.path) || definitionRoots.some((parent) => entry3.path.startsWith(`${parent}${sep9}`)))
10853
10977
  continue;
10854
10978
  const lexical = join29(path, entry3.path);
10855
10979
  const explicitReference = mapped(plan2.options.mapping?.references, plan2, lexical);
@@ -10913,7 +11037,7 @@ async function composition(plan2, path, kind2) {
10913
11037
  if (kind2 === "pack" || dirname19(member.relativePath) !== ".")
10914
11038
  entries.push(memberLink(plan2, destination, member.relativePath, member.name));
10915
11039
  }
10916
- let selected = members2.map((member) => member.name);
11040
+ let selected = members2.filter((member) => !hiddenPath(member.relativePath)).map((member) => member.name);
10917
11041
  if (kind2 === "pack") {
10918
11042
  const declared = [];
10919
11043
  if (raw.freeform !== void 0 && (!record8(raw.freeform) || !Array.isArray(raw.freeform.skills) || !raw.freeform.skills.every((item3) => typeof item3 === "string")))
@@ -11065,6 +11189,18 @@ async function composition(plan2, path, kind2) {
11065
11189
  entries = entries.sort((a, b) => a.path.localeCompare(b.path));
11066
11190
  const afterDigest = migrationTreeDigest(entries);
11067
11191
  const changed3 = destination !== path || before.evidence.digest !== afterDigest;
11192
+ if (changed3)
11193
+ for (const item3 of before.excluded) {
11194
+ if (definitionRoots.some((root) => item3.startsWith(`${root}${sep9}`))) continue;
11195
+ finding(
11196
+ plan2,
11197
+ join29(path, item3),
11198
+ "E_MIGRATION_RUNTIME_CONTENT",
11199
+ runtimeContentMessage("composition"),
11200
+ runtimeContentFix
11201
+ );
11202
+ hasBlocker = true;
11203
+ }
11068
11204
  const dependencies = [
11069
11205
  ...new Set(members2.flatMap((member) => member.dependency ? [member.dependency] : []))
11070
11206
  ];
@@ -11132,12 +11268,13 @@ async function prepare2(registry, options, previousNames = {}, previousProvenanc
11132
11268
  provenance: { ...previousProvenance },
11133
11269
  externalRoots: new Set(previousExternalRoots),
11134
11270
  canonical: /* @__PURE__ */ new Map(),
11135
- imported: /* @__PURE__ */ new Map()
11271
+ imported: /* @__PURE__ */ new Map(),
11272
+ skipped: /* @__PURE__ */ new Map()
11136
11273
  };
11137
11274
  const catalog = join29(registry.root, "all-skills");
11138
11275
  const links = [];
11139
11276
  const retiredAliases = [];
11140
- for (const entry3 of (await readdir18(catalog, { withFileTypes: true })).sort(
11277
+ for (const entry3 of (await readdir19(catalog, { withFileTypes: true })).sort(
11141
11278
  (a, b) => a.name.localeCompare(b.name)
11142
11279
  )) {
11143
11280
  interrupted2(options);
@@ -11210,7 +11347,10 @@ async function prepare2(registry, options, previousNames = {}, previousProvenanc
11210
11347
  state: "ready",
11211
11348
  beforeDigest: before.evidence.digest,
11212
11349
  afterDigest: skill2.digest,
11213
- details: [
11350
+ details: plan2.skipped.get(path)?.length ? [
11351
+ "Identical authored definition content is retained at the canonical target; retire only this exact alias after composition rewrites.",
11352
+ ...skippedDetail(plan2.skipped.get(path) ?? [], "at the alias source")
11353
+ ] : [
11214
11354
  "Identical definition content is retained at the canonical target; retire only this exact alias after composition rewrites."
11215
11355
  ],
11216
11356
  dependsOn: skill2.dependency ? [skill2.dependency] : []
@@ -11240,7 +11380,7 @@ async function prepare2(registry, options, previousNames = {}, previousProvenanc
11240
11380
  blocked3(plan2, root, new Error("Composition family root must be a real directory."));
11241
11381
  continue;
11242
11382
  }
11243
- for (const entry3 of (await readdir18(root, { withFileTypes: true })).sort(
11383
+ for (const entry3 of (await readdir19(root, { withFileTypes: true })).sort(
11244
11384
  (a, b) => a.name.localeCompare(b.name)
11245
11385
  )) {
11246
11386
  const path = join29(root, entry3.name);
@@ -11262,7 +11402,7 @@ async function prepare2(registry, options, previousNames = {}, previousProvenanc
11262
11402
  else if (await inspectPath(join29(path, "pack.toml"))) await composition(plan2, path, "pack");
11263
11403
  else {
11264
11404
  const versions = [];
11265
- for (const child of await readdir18(path, { withFileTypes: true }))
11405
+ for (const child of await readdir19(path, { withFileTypes: true }))
11266
11406
  if ((child.isDirectory() || child.isSymbolicLink()) && await inspectPath(join29(path, child.name, "pack.toml")))
11267
11407
  versions.push(child.name);
11268
11408
  if (versions.length)
@@ -11532,7 +11672,7 @@ async function migrateRegistry(options = {}) {
11532
11672
  // src/core/migration-sources.ts
11533
11673
  import { createHash as createHash11, randomUUID as randomUUID8 } from "node:crypto";
11534
11674
  import { constants as constants9 } from "node:fs";
11535
- import { link as link6, open as open12, readdir as readdir19, unlink as unlink8 } from "node:fs/promises";
11675
+ import { link as link6, open as open12, readdir as readdir20, unlink as unlink8 } from "node:fs/promises";
11536
11676
  import { basename as basename9, join as join30 } from "node:path";
11537
11677
  var binding3 = { namespace: "migrations", targetParts: ["all-skills", "sources.toml"] };
11538
11678
  var prefix = ".skillex-tmp-migrate-sources-";
@@ -11551,7 +11691,7 @@ function refused2(path, message) {
11551
11691
  async function validateProvenance(registry, text2, path) {
11552
11692
  const sources = parseVendorSourcesText(text2, path);
11553
11693
  const catalog = join30(registry.root, "all-skills");
11554
- for (const name of (await readdir19(catalog)).sort()) {
11694
+ for (const name of (await readdir20(catalog)).sort()) {
11555
11695
  const skill2 = join30(catalog, name);
11556
11696
  if (!(await inspectPath(skill2))?.isDirectory() || !await inspectPath(join30(skill2, "SKILL.md")))
11557
11697
  continue;
@@ -11583,7 +11723,7 @@ async function migrateSources(input) {
11583
11723
  const old = snapshot3.document?.data;
11584
11724
  if (old && (old.version !== 1 || typeof old.source !== "string" || typeof old.digest !== "string" || !/^sha256:[a-f0-9]{64}$/.test(old.digest) || !["pending", "verified"].includes(old.phase) || typeof old.stage !== "string" || basename9(old.stage) !== old.stage || !new RegExp(`^${prefix}[a-f0-9-]{36}$`).test(old.stage) || !/^\d+$/.test(old.dev) || !/^\d+$/.test(old.ino)))
11585
11725
  refused2(snapshot3.path, "The source migration receipt is malformed.");
11586
- const artifacts = (await readdir19(catalog)).filter((name) => name.startsWith(prefix));
11726
+ const artifacts = (await readdir20(catalog)).filter((name) => name.startsWith(prefix));
11587
11727
  const unknown = artifacts.filter((name) => name !== old?.stage || old.phase !== "pending");
11588
11728
  if (unknown.length)
11589
11729
  return makeResult("migrate sources", data2, {
@@ -11884,7 +12024,7 @@ async function migrate(input = {}) {
11884
12024
  // src/core/profile-sync.ts
11885
12025
  import { randomUUID as randomUUID9 } from "node:crypto";
11886
12026
  import { constants as constants10 } from "node:fs";
11887
- import { mkdir as mkdir10, open as open13, readdir as readdir20, realpath as realpath22, rename as rename8, symlink as symlink6, unlink as unlink9 } from "node:fs/promises";
12027
+ import { mkdir as mkdir10, open as open13, readdir as readdir21, realpath as realpath22, rename as rename8, symlink as symlink6, unlink as unlink9 } from "node:fs/promises";
11888
12028
  import { join as join31, resolve as resolve17 } from "node:path";
11889
12029
  import { isDeepStrictEqual as isDeepStrictEqual6 } from "node:util";
11890
12030
  function refused3(code, message, path, fix) {
@@ -12000,7 +12140,7 @@ async function observations(profile, state) {
12000
12140
  "Use the explicit migrate workflow to replace this whole-root alias or conflicting file while preserving profile content."
12001
12141
  );
12002
12142
  if (root)
12003
- for (const name of (await readdir20(profile.skillsRoot)).sort()) {
12143
+ for (const name of (await readdir21(profile.skillsRoot)).sort()) {
12004
12144
  const path = join31(profile.skillsRoot, name);
12005
12145
  const actual = await entry2(path);
12006
12146
  if (!actual) continue;
@@ -13443,7 +13583,7 @@ async function setInheritance(enabled, options = {}) {
13443
13583
  }
13444
13584
 
13445
13585
  // src/core/sets.ts
13446
- import { readdir as readdir21 } from "node:fs/promises";
13586
+ import { readdir as readdir22 } from "node:fs/promises";
13447
13587
  import { join as join34 } from "node:path";
13448
13588
  function validateName(name) {
13449
13589
  parseManifest({ sets: [{ name }] }, "set name");
@@ -13466,7 +13606,7 @@ async function listSets(options = {}) {
13466
13606
  const failures = [];
13467
13607
  if (await inspectPath(path)) {
13468
13608
  await requireDirectory(path, "E_SET_MISSING");
13469
- for (const entry3 of (await readdir21(path, { withFileTypes: true })).sort(
13609
+ for (const entry3 of (await readdir22(path, { withFileTypes: true })).sort(
13470
13610
  (a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0
13471
13611
  )) {
13472
13612
  if (entry3.name.startsWith(".") || entry3.name.startsWith("_") || !entry3.isDirectory() && !entry3.isSymbolicLink())
@@ -13530,15 +13670,15 @@ async function removeSetSkills(name, names2, options = {}) {
13530
13670
  }
13531
13671
 
13532
13672
  // src/core/vendor-inspect.ts
13533
- import { readdir as readdir22 } from "node:fs/promises";
13673
+ import { readdir as readdir23 } from "node:fs/promises";
13534
13674
  import { join as join35 } from "node:path";
13535
13675
 
13536
13676
  // src/core/vendor-git.ts
13537
- import { execFile as execFile3 } from "node:child_process";
13677
+ import { execFile as execFile4 } from "node:child_process";
13538
13678
  import { realpath as realpath25 } from "node:fs/promises";
13539
13679
  import { posix } from "node:path";
13540
- import { promisify as promisify2 } from "node:util";
13541
- var execute2 = promisify2(execFile3);
13680
+ import { promisify as promisify3 } from "node:util";
13681
+ var execute3 = promisify3(execFile4);
13542
13682
  var oidPattern = /^(?:[a-f0-9]{40}|[a-f0-9]{64})$/;
13543
13683
  function vendorInterrupted(options) {
13544
13684
  if (options.signal?.aborted) {
@@ -13568,7 +13708,7 @@ function gitEnvironment(options) {
13568
13708
  async function git(root, args2, options, missingRef = false, allowAbsent = false) {
13569
13709
  vendorInterrupted(options);
13570
13710
  try {
13571
- const result = await execute2(
13711
+ const result = await execute3(
13572
13712
  "git",
13573
13713
  ["--no-lazy-fetch", "-c", "protocol.allow=never", "-C", root, ...args2],
13574
13714
  {
@@ -13894,7 +14034,7 @@ async function recordedInventory(manifest, observation, options) {
13894
14034
  const recorded = /* @__PURE__ */ new Map();
13895
14035
  const failed2 = /* @__PURE__ */ new Set();
13896
14036
  const catalog = join35(manifest.registry.root, "all-skills");
13897
- for (const entry3 of (await readdir22(catalog, { withFileTypes: true })).sort(
14037
+ for (const entry3 of (await readdir23(catalog, { withFileTypes: true })).sort(
13898
14038
  (a, b) => a.name.localeCompare(b.name)
13899
14039
  )) {
13900
14040
  checkVendorSignal(options);
@@ -14303,7 +14443,7 @@ async function inspectVendorStatus(options = {}) {
14303
14443
 
14304
14444
  // src/core/vendor-sync.ts
14305
14445
  import { randomUUID as randomUUID11 } from "node:crypto";
14306
- import { chmod as chmod3, lstat as lstat20, mkdir as mkdir12, open as open15, readdir as readdir23, rename as rename10 } from "node:fs/promises";
14446
+ import { chmod as chmod3, lstat as lstat20, mkdir as mkdir12, open as open15, readdir as readdir24, rename as rename10 } from "node:fs/promises";
14307
14447
  import { dirname as dirname22, join as join36 } from "node:path";
14308
14448
  function refuse3(code, message, path, fix) {
14309
14449
  fail(code, message, { path, fix }, ExitCode.REFUSED);
@@ -14501,7 +14641,7 @@ async function prepare4(options, extractedAt) {
14501
14641
  }
14502
14642
  }
14503
14643
  if (options.prune) {
14504
- for (const name of (await readdir23(catalog)).filter(isSkillName).sort()) {
14644
+ for (const name of (await readdir24(catalog)).filter(isSkillName).sort()) {
14505
14645
  if (names2.has(name)) continue;
14506
14646
  const path = join36(catalog, name);
14507
14647
  if (!(await vendorLstat(path))?.isDirectory()) continue;