@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/index.js CHANGED
@@ -515,7 +515,8 @@ var PROJECT_CLI_ALIASES = Object.freeze([
515
515
  ".gemini/skills",
516
516
  ".copilot/skills",
517
517
  ".opencode/skills",
518
- ".kimi-code/skills"
518
+ ".kimi-code/skills",
519
+ ".zcode/skills"
519
520
  ]);
520
521
  var NEVER_TOUCH = Object.freeze([".hermes", ".augment", ".cursor", ".crush"]);
521
522
  function aliasPaths(base, scope) {
@@ -526,7 +527,7 @@ function aliasPaths(base, scope) {
526
527
  }
527
528
 
528
529
  // src/core/catalog.ts
529
- import { readdir as readdir3 } from "node:fs/promises";
530
+ import { readdir as readdir4 } from "node:fs/promises";
530
531
  import { join as join7 } from "node:path";
531
532
 
532
533
  // src/core/composition.ts
@@ -949,10 +950,12 @@ async function packInventory(registry, selection2) {
949
950
  }
950
951
 
951
952
  // src/core/discovery.ts
952
- import { lstat as lstat3, realpath as realpath4, stat } from "node:fs/promises";
953
+ import { execFile } from "node:child_process";
954
+ import { lstat as lstat3, readdir as readdir3, readFile as readFile3, realpath as realpath4, stat } from "node:fs/promises";
953
955
  import { homedir as homedir2 } from "node:os";
954
956
  import { dirname as dirname2, join as join5, parse, resolve as resolve3 } from "node:path";
955
957
  import { fileURLToPath } from "node:url";
958
+ import { promisify } from "node:util";
956
959
  var manifestParts = [".agents", "skills.json"];
957
960
  function errorMessage(error) {
958
961
  return error instanceof Error ? error.message : String(error);
@@ -1102,7 +1105,70 @@ async function installedPackageRoot() {
1102
1105
  current = parent;
1103
1106
  }
1104
1107
  }
1105
- async function catalogRoot(path, required) {
1108
+ var execute = promisify(execFile);
1109
+ async function recordedCatalog(root) {
1110
+ const env = {};
1111
+ for (const [key2, value] of Object.entries(process.env))
1112
+ if (!key2.startsWith("GIT_")) env[key2] = value;
1113
+ let stdout;
1114
+ try {
1115
+ ({ stdout } = await execute(
1116
+ "git",
1117
+ ["-C", root, "ls-files", "--stage", "--full-name", "-z", "--", "all-skills"],
1118
+ {
1119
+ encoding: "utf8",
1120
+ maxBuffer: 64 * 1024 * 1024,
1121
+ env: {
1122
+ ...env,
1123
+ GIT_OPTIONAL_LOCKS: "0",
1124
+ GIT_TERMINAL_PROMPT: "0",
1125
+ GIT_CONFIG_NOSYSTEM: "1",
1126
+ GIT_CONFIG_GLOBAL: "/dev/null"
1127
+ }
1128
+ }
1129
+ ));
1130
+ } catch {
1131
+ return void 0;
1132
+ }
1133
+ const records = stdout.split("\0").filter(Boolean);
1134
+ if (records.some((record9) => /^160000 [0-9a-f]+ \d\tall-skills$/.test(record9))) return "gitlink";
1135
+ if (records.some((record9) => /^\d{6} [0-9a-f]+ \d\tall-skills\//.test(record9))) return "tree";
1136
+ return void 0;
1137
+ }
1138
+ async function holdsDefinition(catalog, names2) {
1139
+ for (const name of names2) {
1140
+ try {
1141
+ if ((await stat(join5(catalog, name, "SKILL.md"))).isFile()) return true;
1142
+ } catch {
1143
+ }
1144
+ }
1145
+ return false;
1146
+ }
1147
+ async function uninitializedCatalog(root, catalog) {
1148
+ let declaration;
1149
+ try {
1150
+ declaration = await readFile3(join5(root, ".gitmodules"), "utf8");
1151
+ } catch (error) {
1152
+ if (["ENOENT", "ENOTDIR"].includes(error.code ?? "")) {
1153
+ return void 0;
1154
+ }
1155
+ return ioFailure2(join5(root, ".gitmodules"), error);
1156
+ }
1157
+ if (!/^[\t ]*path[\t ]*=[\t ]*"?all-skills\/?"?[\t ]*$/m.test(declaration)) return void 0;
1158
+ if (await entry(join5(catalog, ".git"))) return void 0;
1159
+ let names2;
1160
+ try {
1161
+ names2 = (await readdir3(catalog)).sort();
1162
+ } catch (error) {
1163
+ return ioFailure2(catalog, error);
1164
+ }
1165
+ if (!names2.length) return names2;
1166
+ const recorded = await recordedCatalog(root);
1167
+ if (recorded === "gitlink") return names2;
1168
+ if (recorded === "tree") return void 0;
1169
+ return await holdsDefinition(catalog, names2) ? void 0 : names2;
1170
+ }
1171
+ async function catalogRoot(path, required, source) {
1106
1172
  const found = await entry(path);
1107
1173
  if (!found) {
1108
1174
  if (!required) return void 0;
@@ -1133,6 +1199,21 @@ async function catalogRoot(path, required) {
1133
1199
  fix: "Select the owning catalog checkout, or run skillex migrate to repair its topology."
1134
1200
  });
1135
1201
  }
1202
+ const leftovers = await uninitializedCatalog(root, catalog);
1203
+ if (leftovers) {
1204
+ const quoted = JSON.stringify(root);
1205
+ const more = leftovers.length > 8 ? `, and ${leftovers.length - 8} more` : "";
1206
+ 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 ` : "";
1207
+ const step = (text2) => clear ? `${clear}${text2}` : `${text2.charAt(0).toUpperCase()}${text2.slice(1)}`;
1208
+ fail(
1209
+ "E_REGISTRY_ROOT",
1210
+ `The registry's all-skills/ catalog is an uninitialized git submodule: ${catalog}`,
1211
+ {
1212
+ path: catalog,
1213
+ 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.`
1214
+ }
1215
+ );
1216
+ }
1136
1217
  return root;
1137
1218
  }
1138
1219
  async function discoverRegistry(options = {}) {
@@ -1144,7 +1225,7 @@ async function discoverRegistry(options = {}) {
1144
1225
  const path = absolutePath(value, cwd, home, "E_REGISTRY_ROOT", "registry root");
1145
1226
  if (searched.includes(path)) return void 0;
1146
1227
  searched.push(path);
1147
- const root = await catalogRoot(path, required);
1228
+ const root = await catalogRoot(path, required, source);
1148
1229
  return root ? { root, source, searched: [...searched] } : void 0;
1149
1230
  };
1150
1231
  if (options.registryRoot !== void 0) {
@@ -1190,7 +1271,7 @@ async function discoverRegistry(options = {}) {
1190
1271
  }
1191
1272
 
1192
1273
  // src/core/metadata.ts
1193
- import { readFile as readFile3 } from "node:fs/promises";
1274
+ import { readFile as readFile4 } from "node:fs/promises";
1194
1275
  import { join as join6 } from "node:path";
1195
1276
  import { parseDocument } from "yaml";
1196
1277
  function mapping(value) {
@@ -1233,7 +1314,7 @@ async function textFile(path, missing) {
1233
1314
  }
1234
1315
  let bytes;
1235
1316
  try {
1236
- bytes = await readFile3(path);
1317
+ bytes = await readFile4(path);
1237
1318
  } catch {
1238
1319
  fail(
1239
1320
  "E_IO",
@@ -1438,7 +1519,7 @@ async function compositionReferences(registry, findings) {
1438
1519
  await inspectPack(name, path);
1439
1520
  inspected += 1;
1440
1521
  }
1441
- for (const entry3 of (await readdir3(path, { withFileTypes: true })).sort(
1522
+ for (const entry3 of (await readdir4(path, { withFileTypes: true })).sort(
1442
1523
  (a, b) => compare(a.name, b.name)
1443
1524
  )) {
1444
1525
  if (entry3.name.startsWith(".") || entry3.name.startsWith("_")) continue;
@@ -1483,7 +1564,7 @@ async function compositionReferences(registry, findings) {
1483
1564
  try {
1484
1565
  if (!await inspectPath(path)) continue;
1485
1566
  await requireDirectory(path, kind2 === "set" ? "E_SET_MISSING" : "E_PACK_MISSING");
1486
- const entries = (await readdir3(path, { withFileTypes: true })).sort(
1567
+ const entries = (await readdir4(path, { withFileTypes: true })).sort(
1487
1568
  (a, b) => compare(a.name, b.name)
1488
1569
  );
1489
1570
  for (const entry3 of entries) {
@@ -1521,7 +1602,7 @@ async function listSkills(options = {}) {
1521
1602
  let validDefinitions = 0;
1522
1603
  const catalog = join7(registry.root, "all-skills");
1523
1604
  const query = options.query?.trim().toLowerCase();
1524
- for (const entry3 of (await readdir3(catalog, { withFileTypes: true })).sort(
1605
+ for (const entry3 of (await readdir4(catalog, { withFileTypes: true })).sort(
1525
1606
  (a, b) => compare(a.name, b.name)
1526
1607
  )) {
1527
1608
  if (entry3.name.startsWith(".") || entry3.name.startsWith("_")) continue;
@@ -1570,7 +1651,7 @@ async function showSkill(name, options = {}) {
1570
1651
  }
1571
1652
 
1572
1653
  // src/core/catalog-write.ts
1573
- import { chmod, lstat as lstat8, mkdir as mkdir4, open as open4, readFile as readFile6, realpath as realpath9, symlink } from "node:fs/promises";
1654
+ import { chmod, lstat as lstat8, mkdir as mkdir4, open as open4, readFile as readFile7, realpath as realpath9, symlink } from "node:fs/promises";
1574
1655
  import { homedir as homedir5 } from "node:os";
1575
1656
  import { dirname as dirname6, join as join12, resolve as resolve6 } from "node:path";
1576
1657
  import { stringify } from "yaml";
@@ -1586,8 +1667,8 @@ import {
1586
1667
  lstat as lstat4,
1587
1668
  mkdir as mkdir2,
1588
1669
  open as open2,
1589
- readdir as readdir4,
1590
- readFile as readFile4,
1670
+ readdir as readdir5,
1671
+ readFile as readFile5,
1591
1672
  realpath as realpath5,
1592
1673
  rmdir,
1593
1674
  unlink as unlink2
@@ -1692,7 +1773,7 @@ async function claimFiles(claim2) {
1692
1773
  if (!await sameDirectory(claim2.path, claim2.identity)) return void 0;
1693
1774
  let names2;
1694
1775
  try {
1695
- names2 = await readdir4(claim2.path);
1776
+ names2 = await readdir5(claim2.path);
1696
1777
  } catch (error) {
1697
1778
  if (error.code === "ENOENT") return void 0;
1698
1779
  throw error;
@@ -1725,7 +1806,7 @@ async function readTicket(claim2, resource) {
1725
1806
  if (stat6.size > 4096) stateFailure(path, "Lock ticket is too large to be a valid claim.");
1726
1807
  let raw;
1727
1808
  try {
1728
- raw = JSON.parse(await readFile4(path, "utf8"));
1809
+ raw = JSON.parse(await readFile5(path, "utf8"));
1729
1810
  } catch (error) {
1730
1811
  if (error.code === "ENOENT") return void 0;
1731
1812
  if (error instanceof SyntaxError) stateFailure(path, "Lock ticket is malformed JSON.");
@@ -1757,7 +1838,7 @@ async function removeClaim(claim2, expectedTicket, ownedTicket) {
1757
1838
  if (expectedTicket !== void 0 && names2.includes(ticketFile)) {
1758
1839
  let current;
1759
1840
  try {
1760
- current = await readFile4(join8(claim2.path, ticketFile), "utf8");
1841
+ current = await readFile5(join8(claim2.path, ticketFile), "utf8");
1761
1842
  } catch (error) {
1762
1843
  if (error.code !== "ENOENT") throw error;
1763
1844
  }
@@ -1789,7 +1870,7 @@ async function removeClaim(claim2, expectedTicket, ownedTicket) {
1789
1870
  async function claims(path, directory2, resource, localHostHash) {
1790
1871
  if (!await sameDirectory(path, directory2)) stateFailure(path, "Lock directory disappeared.");
1791
1872
  const result = [];
1792
- for (const name of (await readdir4(path)).sort()) {
1873
+ for (const name of (await readdir5(path)).sort()) {
1793
1874
  const claimPath = join8(path, name);
1794
1875
  const identity4 = identityFrom(name, claimPath);
1795
1876
  const stat6 = await inspect2(claimPath);
@@ -1940,7 +2021,7 @@ import {
1940
2021
  lstat as lstat6,
1941
2022
  mkdir as mkdir3,
1942
2023
  open as open3,
1943
- readdir as readdir6,
2024
+ readdir as readdir7,
1944
2025
  realpath as realpath7,
1945
2026
  rename as rename2,
1946
2027
  rmdir as rmdir2,
@@ -1951,16 +2032,14 @@ import { dirname as dirname5, join as join10, relative as relative3, resolve as
1951
2032
 
1952
2033
  // src/core/content.ts
1953
2034
  import { createHash as createHash3 } from "node:crypto";
1954
- import { lstat as lstat5, readdir as readdir5, readFile as readFile5, readlink, realpath as realpath6 } from "node:fs/promises";
2035
+ import { lstat as lstat5, readdir as readdir6, readFile as readFile6, readlink, realpath as realpath6 } from "node:fs/promises";
1955
2036
  import { dirname as dirname4, isAbsolute as isAbsolute2, join as join9, relative as relative2, sep as sep3 } from "node:path";
1956
2037
  function isWithin(root, path) {
1957
2038
  const child = relative2(root, path);
1958
2039
  return child === "" || !isAbsolute2(child) && child !== ".." && !child.startsWith(`..${sep3}`);
1959
2040
  }
2041
+ var repositoryNames = /* @__PURE__ */ new Set([".git", ".hg", ".svn"]);
1960
2042
  var generatedNames = /* @__PURE__ */ new Set([
1961
- ".git",
1962
- ".hg",
1963
- ".svn",
1964
2043
  ".DS_Store",
1965
2044
  "__pycache__",
1966
2045
  ".pytest_cache",
@@ -1971,8 +2050,11 @@ var generatedNames = /* @__PURE__ */ new Set([
1971
2050
  ".venv",
1972
2051
  "node_modules"
1973
2052
  ]);
2053
+ function generatedName(name) {
2054
+ return generatedNames.has(name) || /\.(?:pyc|pyo|pid|sock|db-wal|db-shm)$/.test(name);
2055
+ }
1974
2056
  function excludedName(name) {
1975
- 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);
2057
+ 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);
1976
2058
  }
1977
2059
  function contentFailure(path, message) {
1978
2060
  fail(
@@ -1986,7 +2068,7 @@ async function captureContent(root) {
1986
2068
  const entries = [];
1987
2069
  const excluded = [];
1988
2070
  const visit = async (path) => {
1989
- for (const name of (await readdir5(path)).sort()) {
2071
+ for (const name of (await readdir6(path)).sort()) {
1990
2072
  const source = join9(path, name);
1991
2073
  const item2 = relative2(root, source);
1992
2074
  if (excludedName(name)) {
@@ -1998,7 +2080,7 @@ async function captureContent(root) {
1998
2080
  entries.push({ path: item2, kind: "directory", mode: metadata2.mode & 511 });
1999
2081
  await visit(source);
2000
2082
  } else if (metadata2.isFile()) {
2001
- const bytes = await readFile5(source);
2083
+ const bytes = await readFile6(source);
2002
2084
  const after = await lstat5(source);
2003
2085
  if (metadata2.dev !== after.dev || metadata2.ino !== after.ino || metadata2.mode !== after.mode || metadata2.size !== after.size || metadata2.mtimeMs !== after.mtimeMs) {
2004
2086
  contentFailure(source, `Source changed while being inspected: ${source}`);
@@ -2174,7 +2256,7 @@ async function captureVendorTree(root) {
2174
2256
  const before = await lstat6(directory2, { bigint: true });
2175
2257
  if (!before.isDirectory())
2176
2258
  stateFailure2(directory2, "A content parent became a symlink or non-directory.");
2177
- for (const name of (await readdir6(directory2)).sort()) {
2259
+ for (const name of (await readdir7(directory2)).sort()) {
2178
2260
  const path = join10(directory2, name);
2179
2261
  const info = await lstat6(path, { bigint: true });
2180
2262
  if (!info.isFile() && !info.isDirectory())
@@ -2205,7 +2287,7 @@ async function assertVendorTree(root, expected, allowMissing = false) {
2205
2287
  if (identity4?.kind !== "directory")
2206
2288
  stateFailure2(directory2, "A recovery parent has no directory ownership evidence.");
2207
2289
  await assertVendorIdentity(directory2, identity4);
2208
- for (const name of await readdir6(directory2)) {
2290
+ for (const name of await readdir7(directory2)) {
2209
2291
  const path = join10(directory2, name);
2210
2292
  const item2 = relative3(root, path);
2211
2293
  const entry3 = expectedEntries.get(item2);
@@ -2785,7 +2867,7 @@ async function importSkill(source, name, options = {}) {
2785
2867
  const metadata2 = await readSkillMetadata(sourceRoot);
2786
2868
  for (const name2 of ["SKILL.md", ".source.yaml"]) {
2787
2869
  const captured = content.entries.find((entry3) => entry3.path === name2);
2788
- if (captured?.kind === "file" && !captured.bytes.equals(await readFile6(join12(sourceRoot, name2)))) {
2870
+ if (captured?.kind === "file" && !captured.bytes.equals(await readFile7(join12(sourceRoot, name2)))) {
2789
2871
  fail("E_IMPORT_SOURCE_CHANGED", "Skill metadata changed while import was being planned.", {
2790
2872
  path: join12(sourceRoot, name2),
2791
2873
  fix: "Retry after the source writer has finished."
@@ -2839,12 +2921,12 @@ async function importSkill(source, name, options = {}) {
2839
2921
  }
2840
2922
 
2841
2923
  // src/core/diagnostics.ts
2842
- import { readdir as readdir10, realpath as realpath13 } from "node:fs/promises";
2924
+ import { readdir as readdir11, realpath as realpath13 } from "node:fs/promises";
2843
2925
  import { homedir as homedir6 } from "node:os";
2844
2926
  import { dirname as dirname10, join as join17, parse as parse2, resolve as resolve9, sep as sep5 } from "node:path";
2845
2927
 
2846
2928
  // src/core/activation-ownership.ts
2847
- import { lstat as lstat9, readdir as readdir7, readlink as readlink2 } from "node:fs/promises";
2929
+ import { lstat as lstat9, readdir as readdir8, readlink as readlink2 } from "node:fs/promises";
2848
2930
  import { dirname as dirname7, isAbsolute as isAbsolute3, join as join13, relative as relative4, resolve as resolve7 } from "node:path";
2849
2931
  function refuse(path, message, code = "E_ACTIVATION_CONFLICT") {
2850
2932
  fail(
@@ -2903,7 +2985,7 @@ async function inspectOwnedNode(path, node, missingOkay = false) {
2903
2985
  const actual = await requireIdentity(path, node.identity, missingOkay);
2904
2986
  if (!actual) return false;
2905
2987
  if (node.identity.kind === "directory") {
2906
- for (const name of await readdir7(path)) {
2988
+ for (const name of await readdir8(path)) {
2907
2989
  const expected = node.children?.[name];
2908
2990
  if (!expected)
2909
2991
  refuse(
@@ -2985,14 +3067,14 @@ function lexicalTarget(path, raw) {
2985
3067
  }
2986
3068
 
2987
3069
  // src/core/reconciliation.ts
2988
- import { execFile } from "node:child_process";
3070
+ import { execFile as execFile2 } from "node:child_process";
2989
3071
  import { createHash as createHash5, randomUUID as randomUUID5 } from "node:crypto";
2990
- 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";
3072
+ 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";
2991
3073
  import { basename as basename3, dirname as dirname9, join as join16, relative as relative6, resolve as resolve8, sep as sep4 } from "node:path";
2992
- import { promisify } from "node:util";
3074
+ import { promisify as promisify2 } from "node:util";
2993
3075
 
2994
3076
  // src/core/packs.ts
2995
- import { lstat as lstat11, readdir as readdir8, readFile as readFile8, realpath as realpath11 } from "node:fs/promises";
3077
+ import { lstat as lstat11, readdir as readdir9, readFile as readFile9, realpath as realpath11 } from "node:fs/promises";
2996
3078
  import { join as join15 } from "node:path";
2997
3079
  import { parse as parseToml2, stringify as stringifyToml } from "smol-toml";
2998
3080
 
@@ -3003,7 +3085,7 @@ import {
3003
3085
  lstat as lstat10,
3004
3086
  mkdir as mkdir5,
3005
3087
  open as open5,
3006
- readFile as readFile7,
3088
+ readFile as readFile8,
3007
3089
  readlink as readlink3,
3008
3090
  realpath as realpath10,
3009
3091
  rename as rename3,
@@ -3130,7 +3212,7 @@ async function saveManifest(plan2, changed3) {
3130
3212
  await parents(plan2, manifest.path);
3131
3213
  const info = await inspectPath(manifest.path);
3132
3214
  if (manifest.before) {
3133
- if (!info?.isFile() || info.dev !== manifest.before.info.dev || info.ino !== manifest.before.info.ino || !(await readFile7(manifest.path)).equals(manifest.before.bytes))
3215
+ if (!info?.isFile() || info.dev !== manifest.before.info.dev || info.ino !== manifest.before.info.ino || !(await readFile8(manifest.path)).equals(manifest.before.bytes))
3134
3216
  conflict(manifest.path, "The pack declaration changed while writing was being planned.");
3135
3217
  } else if (info) conflict(manifest.path, "A pack manifest appeared during creation.");
3136
3218
  };
@@ -3296,7 +3378,7 @@ async function readPack(registry, selected) {
3296
3378
  const path = join15(first.path, "pack.toml");
3297
3379
  const info = await lstat11(path);
3298
3380
  if (!info.isFile()) conflict(path, "Pack manifests must be real files.");
3299
- const bytes = await readFile8(path);
3381
+ const bytes = await readFile9(path);
3300
3382
  let raw;
3301
3383
  try {
3302
3384
  raw = parseToml2(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
@@ -3309,7 +3391,7 @@ async function readPack(registry, selected) {
3309
3391
  }
3310
3392
  const inventory = await packInventory(registry, selected);
3311
3393
  const after = await lstat11(path);
3312
- if (inventory.path !== first.path || !after.isFile() || after.dev !== info.dev || after.ino !== info.ino || !(await readFile8(path)).equals(bytes))
3394
+ if (inventory.path !== first.path || !after.isFile() || after.dev !== info.dev || after.ino !== info.ino || !(await readFile9(path)).equals(bytes))
3313
3395
  conflict(path, "The pack declaration changed during inspection.");
3314
3396
  const header = raw.pack;
3315
3397
  const text2 = description(header.description, path);
@@ -3356,7 +3438,7 @@ async function listPacks(options = {}) {
3356
3438
  };
3357
3439
  if (await inspectPath(root)) {
3358
3440
  await requireDirectory(root, "E_PACK_MISSING");
3359
- for (const family of (await readdir8(root, { withFileTypes: true })).sort(
3441
+ for (const family of (await readdir9(root, { withFileTypes: true })).sort(
3360
3442
  (a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0
3361
3443
  )) {
3362
3444
  if (family.name.startsWith(".") || family.name.startsWith("_") || !family.isDirectory() && !family.isSymbolicLink())
@@ -3372,7 +3454,7 @@ async function listPacks(options = {}) {
3372
3454
  await inspect6(named, path);
3373
3455
  inspected += 1;
3374
3456
  }
3375
- for (const entry3 of (await readdir8(path, { withFileTypes: true })).sort(
3457
+ for (const entry3 of (await readdir9(path, { withFileTypes: true })).sort(
3376
3458
  (a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0
3377
3459
  )) {
3378
3460
  if (entry3.name.startsWith(".") || entry3.name.startsWith("_") || !entry3.isDirectory() && !entry3.isSymbolicLink())
@@ -3458,7 +3540,7 @@ async function verifyPack(ref, options = {}) {
3458
3540
  );
3459
3541
  else {
3460
3542
  const names2 = new Set(inventory.names);
3461
- const entries = await readdir8(inventory.skillsRoot, { withFileTypes: true });
3543
+ const entries = await readdir9(inventory.skillsRoot, { withFileTypes: true });
3462
3544
  const present = new Set(entries.map((entry3) => entry3.name));
3463
3545
  for (const name of names2)
3464
3546
  if (!present.has(name))
@@ -3536,7 +3618,7 @@ async function preparePack(selected, names2, operation, options) {
3536
3618
  const root = join15(composition2.path, "skills");
3537
3619
  await planDirectory(plan2, root);
3538
3620
  if (await inspectPath(root)) {
3539
- for (const entry3 of await readdir8(root, { withFileTypes: true })) {
3621
+ for (const entry3 of await readdir9(root, { withFileTypes: true })) {
3540
3622
  const path = join15(root, entry3.name);
3541
3623
  const target2 = targets.get(entry3.name);
3542
3624
  if (target2) await planLink(plan2, path, target2);
@@ -3830,7 +3912,7 @@ async function resolveSelectionWithManifests(options = {}, proposed = /* @__PURE
3830
3912
  }
3831
3913
 
3832
3914
  // src/core/reconciliation.ts
3833
- var runFile = promisify(execFile);
3915
+ var runFile = promisify2(execFile2);
3834
3916
  var lockResource = "skillex:activation:v2";
3835
3917
  function errorResult(command, error) {
3836
3918
  return makeResult(command, null, {
@@ -4124,7 +4206,7 @@ async function buildScope(scope, options, forbiddenRoots) {
4124
4206
  }
4125
4207
  return { identity: owned3, children };
4126
4208
  };
4127
- const awaitableNames = rootEntry?.info.isDirectory() ? await readdir9(physicalPath(root, recovery)) : [];
4209
+ const awaitableNames = rootEntry?.info.isDirectory() ? await readdir10(physicalPath(root, recovery)) : [];
4128
4210
  if (!rootEntry) {
4129
4211
  operations.push({
4130
4212
  path: root,
@@ -4900,7 +4982,7 @@ async function observeScope(location2, resolved, manifest, options, forbiddenRoo
4900
4982
  const entries = [];
4901
4983
  if (observedRoot.observation.reachable && ["directory", "link"].includes(observedRoot.observation.kind)) {
4902
4984
  try {
4903
- const names2 = (await readdir10(root)).sort();
4985
+ const names2 = (await readdir11(root)).sort();
4904
4986
  for (const name of names2) {
4905
4987
  cancelled(options);
4906
4988
  const path = join17(root, name);
@@ -5246,14 +5328,14 @@ async function explainSkill(name, options = {}) {
5246
5328
  }
5247
5329
 
5248
5330
  // src/core/doctor-sources.ts
5249
- import { readdir as readdir12, readFile as readFile9, realpath as realpath15 } from "node:fs/promises";
5331
+ import { readdir as readdir13, readFile as readFile10, realpath as realpath15 } from "node:fs/promises";
5250
5332
  import { basename as basename4, dirname as dirname11, join as join20, relative as relative8, sep as sep7 } from "node:path";
5251
5333
  import { parse as parseToml4 } from "smol-toml";
5252
5334
 
5253
5335
  // src/core/vendor-provenance.ts
5254
5336
  import { createHash as createHash6 } from "node:crypto";
5255
5337
  import { constants as constants4 } from "node:fs";
5256
- import { lstat as lstat13, open as open7, readdir as readdir11 } from "node:fs/promises";
5338
+ import { lstat as lstat13, open as open7, readdir as readdir12 } from "node:fs/promises";
5257
5339
  import { join as join19, relative as relative7, sep as sep6 } from "node:path";
5258
5340
  import { stringify as stringify2 } from "yaml";
5259
5341
 
@@ -5765,7 +5847,7 @@ async function digestVendorTree(skillPath) {
5765
5847
  const before = await lstat13(directory2);
5766
5848
  if (!before.isDirectory())
5767
5849
  unsafe(directory2, "Vendored skill directories must be real directories.");
5768
- for (const name of (await readdir11(directory2)).sort()) {
5850
+ for (const name of (await readdir12(directory2)).sort()) {
5769
5851
  if (directory2 === root && name === ".source.yaml") continue;
5770
5852
  const path = join19(directory2, name);
5771
5853
  if (administration.has(name))
@@ -5817,7 +5899,7 @@ async function digestRecordedSkill(skillPath, provenance) {
5817
5899
  async function appendRegularContent(root, path, entries) {
5818
5900
  const info = await lstat13(path);
5819
5901
  if (info.isDirectory()) {
5820
- for (const name of (await readdir11(path)).sort()) {
5902
+ for (const name of (await readdir12(path)).sort()) {
5821
5903
  if (administration.has(name))
5822
5904
  unsafe(join19(path, name), "Repository administration is not vendored skill content.");
5823
5905
  await appendRegularContent(root, join19(path, name), entries);
@@ -6061,7 +6143,7 @@ async function inspectDoctorSources(registry) {
6061
6143
  };
6062
6144
  await attempt(catalog, async () => {
6063
6145
  await requireDirectory(catalog, "E_NO_REGISTRY");
6064
- for (const name of (await readdir12(catalog)).sort()) {
6146
+ for (const name of (await readdir13(catalog)).sort()) {
6065
6147
  if (name === ".git") continue;
6066
6148
  const path = join20(catalog, name);
6067
6149
  await attempt(path, async () => {
@@ -6092,7 +6174,7 @@ async function inspectDoctorSources(registry) {
6092
6174
  });
6093
6175
  const packManifests = [];
6094
6176
  const walk = async (directory2) => {
6095
- const names2 = await attempt(directory2, () => readdir12(directory2));
6177
+ const names2 = await attempt(directory2, () => readdir13(directory2));
6096
6178
  for (const name of (names2 ?? []).sort()) {
6097
6179
  if (name === ".git") continue;
6098
6180
  const path = join20(directory2, name);
@@ -6127,7 +6209,7 @@ async function inspectDoctorSources(registry) {
6127
6209
  if (!await inspectPath(root)) return;
6128
6210
  await requireDirectory(root, "E_COMPOSITION_ROOT");
6129
6211
  await walk(root);
6130
- for (const name of (await readdir12(root)).sort()) {
6212
+ for (const name of (await readdir13(root)).sort()) {
6131
6213
  if (!isSkillName(name)) continue;
6132
6214
  const path = join20(root, name);
6133
6215
  const info = await inspectPath(path);
@@ -6139,7 +6221,7 @@ async function inspectDoctorSources(registry) {
6139
6221
  if (kind2 !== "sets" || !info.isDirectory()) continue;
6140
6222
  data2.sets++;
6141
6223
  const members2 = await attempt(path, () => setMembers(registry.root, name));
6142
- const names2 = members2?.names ?? (await readdir12(path, { withFileTypes: true })).filter((item2) => item2.isSymbolicLink() && isSkillName(item2.name)).map((item2) => item2.name);
6224
+ const names2 = members2?.names ?? (await readdir13(path, { withFileTypes: true })).filter((item2) => item2.isSymbolicLink() && isSkillName(item2.name)).map((item2) => item2.name);
6143
6225
  for (const member of names2)
6144
6226
  await attempt(join20(path, member), () => setMemberTarget(registry.root, path, member));
6145
6227
  }
@@ -6177,7 +6259,7 @@ async function inspectDoctorSources(registry) {
6177
6259
  return { data: data2, findings, exits };
6178
6260
  }
6179
6261
  async function toml(path, code) {
6180
- const bytes = await readFile9(path);
6262
+ const bytes = await readFile10(path);
6181
6263
  try {
6182
6264
  return parseToml4(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
6183
6265
  } catch {
@@ -6189,8 +6271,8 @@ async function toml(path, code) {
6189
6271
  }
6190
6272
 
6191
6273
  // src/core/doctor-writers.ts
6192
- import { execFile as execFile2 } from "node:child_process";
6193
- import { readdir as readdir13, readFile as readFile10, realpath as realpath16, stat as stat3 } from "node:fs/promises";
6274
+ import { execFile as execFile3 } from "node:child_process";
6275
+ import { readdir as readdir14, readFile as readFile11, realpath as realpath16, stat as stat3 } from "node:fs/promises";
6194
6276
  import { homedir as homedir8 } from "node:os";
6195
6277
  import { basename as basename5, dirname as dirname12, join as join21, resolve as resolve11 } from "node:path";
6196
6278
  import { parse as parseToml5 } from "smol-toml";
@@ -6412,12 +6494,12 @@ async function inspectDoctorWriters(options, registries, scopes) {
6412
6494
  };
6413
6495
  const serviceRoot = join21(configHome, "systemd", "user");
6414
6496
  try {
6415
- for (const entry3 of await readdir13(serviceRoot, { withFileTypes: true })) {
6497
+ for (const entry3 of await readdir14(serviceRoot, { withFileTypes: true })) {
6416
6498
  const path = join21(serviceRoot, entry3.name);
6417
6499
  if (entry3.name.endsWith(".service")) candidates.set(path, "service");
6418
6500
  else if (entry3.isDirectory() && entry3.name.endsWith(".service.d")) {
6419
6501
  try {
6420
- for (const file of await readdir13(path))
6502
+ for (const file of await readdir14(path))
6421
6503
  if (file.endsWith(".conf")) candidates.set(join21(path, file), "service");
6422
6504
  } catch {
6423
6505
  unavailable(path, "Cannot inspect user service overrides.");
@@ -6437,7 +6519,7 @@ async function inspectDoctorWriters(options, registries, scopes) {
6437
6519
  unavailable(path, "Writer configuration is not a bounded regular file.");
6438
6520
  continue;
6439
6521
  }
6440
- const content = new TextDecoder("utf-8", { fatal: true }).decode(await readFile10(path));
6522
+ const content = new TextDecoder("utf-8", { fatal: true }).decode(await readFile11(path));
6441
6523
  const lines = content.split(/\r?\n/);
6442
6524
  if (kind2 === "service") {
6443
6525
  for (const [index, line] of lines.entries()) {
@@ -6515,7 +6597,7 @@ async function inspectDoctorWriters(options, registries, scopes) {
6515
6597
  }
6516
6598
  async function boundedSnapshot(options, env) {
6517
6599
  const observation = options.processSnapshot ? options.processSnapshot() : new Promise((accept, reject) => {
6518
- execFile2(
6600
+ execFile3(
6519
6601
  "ps",
6520
6602
  ["-axo", "pid=,args="],
6521
6603
  { env, timeout: timeoutMs, maxBuffer: maxProcessBytes, encoding: "utf8" },
@@ -6685,14 +6767,14 @@ import { realpath as realpath21, stat as stat4 } from "node:fs/promises";
6685
6767
  // src/core/migration-activation.ts
6686
6768
  import { createHash as createHash8, randomUUID as randomUUID6 } from "node:crypto";
6687
6769
  import { constants as constants6 } from "node:fs";
6688
- import { mkdir as mkdir7, open as open9, readdir as readdir16, realpath as realpath18, rename as rename5, symlink as symlink4 } from "node:fs/promises";
6770
+ import { mkdir as mkdir7, open as open9, readdir as readdir17, realpath as realpath18, rename as rename5, symlink as symlink4 } from "node:fs/promises";
6689
6771
  import { dirname as dirname16, isAbsolute as isAbsolute7, join as join25, parse as parse3, relative as relative10, resolve as resolve14 } from "node:path";
6690
6772
  import { isDeepStrictEqual as isDeepStrictEqual4 } from "node:util";
6691
6773
 
6692
6774
  // src/core/migration-activation-state.ts
6693
6775
  import { createHash as createHash7 } from "node:crypto";
6694
6776
  import { constants as constants5 } from "node:fs";
6695
- import { lstat as lstat14, open as open8, readdir as readdir14, readlink as readlink4, rmdir as rmdir4, unlink as unlink6 } from "node:fs/promises";
6777
+ import { lstat as lstat14, open as open8, readdir as readdir15, readlink as readlink4, rmdir as rmdir4, unlink as unlink6 } from "node:fs/promises";
6696
6778
  import { dirname as dirname13, isAbsolute as isAbsolute5, join as join22, relative as relative9, resolve as resolve12 } from "node:path";
6697
6779
  import { isDeepStrictEqual as isDeepStrictEqual2 } from "node:util";
6698
6780
  import { parseDocument as parseDocument2 } from "yaml";
@@ -6734,7 +6816,7 @@ async function captureMigrationNode(path) {
6734
6816
  const children = {};
6735
6817
  let hash4 = null;
6736
6818
  if (before.isDirectory()) {
6737
- const names2 = await readdir14(path, { encoding: "buffer" });
6819
+ const names2 = await readdir15(path, { encoding: "buffer" });
6738
6820
  if (names2.length > 1e4)
6739
6821
  migrationRefusal(path, "A migration directory exceeds the bounded inventory limit.");
6740
6822
  for (const bytes of names2.sort(Buffer.compare)) {
@@ -6950,7 +7032,7 @@ function migrationAbsolute(value, home, cwd) {
6950
7032
  }
6951
7033
 
6952
7034
  // src/core/profile-discovery.ts
6953
- import { lstat as lstat15, readdir as readdir15, readlink as readlink5, realpath as realpath17 } from "node:fs/promises";
7035
+ import { lstat as lstat15, readdir as readdir16, readlink as readlink5, realpath as realpath17 } from "node:fs/promises";
6954
7036
  import { homedir as homedir9 } from "node:os";
6955
7037
  import { basename as basename6, dirname as dirname14, join as join23, resolve as resolve13 } from "node:path";
6956
7038
  var namePattern = /^[a-z0-9][a-z0-9_-]{0,63}$/;
@@ -7193,7 +7275,7 @@ async function discoverProfiles(options = {}) {
7193
7275
  await canonicalDirectory(directory2, false);
7194
7276
  let names2;
7195
7277
  try {
7196
- names2 = (await readdir15(directory2, { withFileTypes: true })).filter(
7278
+ names2 = (await readdir16(directory2, { withFileTypes: true })).filter(
7197
7279
  (entry3) => entry3.name !== "default" && namePattern.test(entry3.name) && (entry3.isDirectory() || entry3.isSymbolicLink())
7198
7280
  ).map((entry3) => entry3.name).sort();
7199
7281
  } catch (error) {
@@ -7765,7 +7847,7 @@ async function collectArtifacts(plan2) {
7765
7847
  await guard(plan2.target, join25(parent, "child"));
7766
7848
  const current = await entry2(parent);
7767
7849
  if (!current) continue;
7768
- for (const name of await readdir16(parent)) {
7850
+ for (const name of await readdir17(parent)) {
7769
7851
  if (!/^\.skillex-tmp-migration-[a-f0-9-]+-(?:new|old)$/.test(name)) continue;
7770
7852
  const path = join25(parent, name);
7771
7853
  if (path === pending?.stage || path === pending?.parked) continue;
@@ -8308,7 +8390,7 @@ async function finishPending(target2, state, begin = () => {
8308
8390
  verified: state.data.verified
8309
8391
  });
8310
8392
  }
8311
- async function execute(target2, operation, state, mark, begin) {
8393
+ async function execute2(target2, operation, state, mark, begin) {
8312
8394
  check(target2.options);
8313
8395
  await guard(target2, operation.item.path);
8314
8396
  for (const proof of operation.proofs) await assertMigrationNode(proof.path, proof.node);
@@ -8585,7 +8667,7 @@ async function migrateActivation(options = {}) {
8585
8667
  "The migration item did not converge after publication."
8586
8668
  );
8587
8669
  attempted.add(operation.item.id);
8588
- state = await execute(
8670
+ state = await execute2(
8589
8671
  selected,
8590
8672
  operation,
8591
8673
  current.state,
@@ -8852,7 +8934,7 @@ import {
8852
8934
  lstat as lstat16,
8853
8935
  mkdir as mkdir8,
8854
8936
  open as open10,
8855
- readdir as readdir17,
8937
+ readdir as readdir18,
8856
8938
  readlink as readlink6,
8857
8939
  rename as rename6,
8858
8940
  rmdir as rmdir5,
@@ -8947,6 +9029,7 @@ async function captureMigrationTree(root) {
8947
9029
  const initial = await migrationLstat(root);
8948
9030
  if (!initial) return null;
8949
9031
  const entries = [];
9032
+ const excluded = [];
8950
9033
  const evidence2 = [];
8951
9034
  const visit = async (path, relpath) => {
8952
9035
  const before = await lstat16(path, { bigint: true });
@@ -8969,14 +9052,19 @@ async function captureMigrationTree(root) {
8969
9052
  target: target2 ?? null
8970
9053
  });
8971
9054
  if (id.kind === "directory") {
8972
- for (const name of (await readdir17(path)).sort()) {
9055
+ for (const name of (await readdir18(path)).sort()) {
8973
9056
  if ([".git", ".hg", ".svn"].includes(name))
8974
9057
  migrationFailure2(
8975
9058
  join27(path, name),
8976
9059
  "A definition or composition contains repository administration; map its authored content explicitly.",
8977
9060
  "E_MIGRATION_CONTENT"
8978
9061
  );
8979
- await visit(join27(path, name), relpath ? join27(relpath, name) : name);
9062
+ const child = relpath ? join27(relpath, name) : name;
9063
+ if (generatedName(name)) {
9064
+ excluded.push(child);
9065
+ continue;
9066
+ }
9067
+ await visit(join27(path, name), child);
8980
9068
  }
8981
9069
  }
8982
9070
  if (!stable2(before, await lstat16(path, { bigint: true })))
@@ -8987,9 +9075,23 @@ async function captureMigrationTree(root) {
8987
9075
  migrationFailure2(root, "Source root was replaced while it was inspected.");
8988
9076
  return {
8989
9077
  entries,
8990
- evidence: { root: identity3(initial), entries: evidence2, digest: migrationTreeDigest(entries) }
9078
+ evidence: { root: identity3(initial), entries: evidence2, digest: migrationTreeDigest(entries) },
9079
+ excluded
8991
9080
  };
8992
9081
  }
9082
+ function refuseExcludedRemoval(path, tree) {
9083
+ const first = tree.excluded[0];
9084
+ if (first === void 0) return;
9085
+ fail(
9086
+ "E_MIGRATION_RUNTIME_CONTENT",
9087
+ `Migration would remove generated build, cache, or runtime content it never migrates: ${tree.excluded.join(", ")}`,
9088
+ {
9089
+ path: join27(path, first),
9090
+ fix: "Remove only verified generated entries (their tools rebuild them), or move them elsewhere, then rerun the migration preview."
9091
+ },
9092
+ ExitCode.REFUSED
9093
+ );
9094
+ }
8993
9095
  async function assertMigrationIdentity(path, expected) {
8994
9096
  if (!equalIdentity2(await migrationLstat(path), expected))
8995
9097
  migrationFailure2(path, "A migration entry changed identity.");
@@ -9099,6 +9201,7 @@ async function removeMigrationTree(path, expected) {
9099
9201
  const currentTree = await captureMigrationTree(path);
9100
9202
  if (!currentTree) return;
9101
9203
  await assertMigrationIdentity(path, expected.root);
9204
+ refuseExcludedRemoval(path, currentTree);
9102
9205
  for (const current of currentTree.evidence.entries) {
9103
9206
  const known = expected.entries.find((entry3) => entry3.path === current.path);
9104
9207
  if (!known || JSON.stringify(known) !== JSON.stringify(current))
@@ -9205,6 +9308,7 @@ async function publishMigrationOperation(operation) {
9205
9308
  } else {
9206
9309
  if (destination) {
9207
9310
  await assertMigrationTree(operation.path, operation.before);
9311
+ refuseExcludedRemoval(operation.path, destination);
9208
9312
  if (!operation.parked || parked)
9209
9313
  migrationFailure2(operation.path, "Cannot park the original migration entry safely.");
9210
9314
  await assertMigrationTree(operation.parked, null);
@@ -10351,7 +10455,7 @@ async function migrateManifest(options, nameMap = {}) {
10351
10455
 
10352
10456
  // src/core/migration-registry.ts
10353
10457
  import { createHash as createHash10 } from "node:crypto";
10354
- import { lstat as lstat18, readdir as readdir18, realpath as realpath20 } from "node:fs/promises";
10458
+ import { lstat as lstat18, readdir as readdir19, realpath as realpath20 } from "node:fs/promises";
10355
10459
  import { basename as basename8, dirname as dirname19, isAbsolute as isAbsolute10, join as join29, relative as relative13, sep as sep9 } from "node:path";
10356
10460
  import { parse as parseToml7, stringify as stringifyToml2 } from "smol-toml";
10357
10461
  function record8(value) {
@@ -10369,7 +10473,7 @@ function payloadDigest(entries) {
10369
10473
  async function sameCaseOnlyEntry(source, destination, before) {
10370
10474
  if (dirname19(source) !== dirname19(destination) || basename8(source) === basename8(destination) || basename8(source).toLowerCase() !== basename8(destination).toLowerCase())
10371
10475
  return false;
10372
- const names2 = await readdir18(dirname19(source));
10476
+ const names2 = await readdir19(dirname19(source));
10373
10477
  if (!names2.includes(basename8(source)) || names2.includes(basename8(destination))) return false;
10374
10478
  const destinationTree = await captureMigrationTree(destination);
10375
10479
  return JSON.stringify(destinationTree?.evidence) === JSON.stringify(before);
@@ -10449,6 +10553,26 @@ function refuse2(path, code, message) {
10449
10553
  ExitCode.REFUSED
10450
10554
  );
10451
10555
  }
10556
+ var runtimeContentFix = "Remove only verified generated entries (their tools rebuild them), or move them outside the composition, then rerun the migration preview.";
10557
+ function runtimeContentMessage(holder) {
10558
+ return `A ${holder} contains generated build, cache, or runtime content that migration never carries or removes.`;
10559
+ }
10560
+ function hiddenPath(path) {
10561
+ return path.split(sep9).some((part) => part.startsWith(".") || part.startsWith("_"));
10562
+ }
10563
+ function skippedDetail(skipped, where) {
10564
+ return skipped.length ? [
10565
+ `Generated build, cache, or runtime entries ${where} are not definition content: they are not copied, not carried, and stay at the source: ${skipped.join(", ")}`
10566
+ ] : [];
10567
+ }
10568
+ function runtimeContent(path, holder) {
10569
+ fail(
10570
+ "E_MIGRATION_RUNTIME_CONTENT",
10571
+ runtimeContentMessage(holder),
10572
+ { path, fix: runtimeContentFix },
10573
+ ExitCode.REFUSED
10574
+ );
10575
+ }
10452
10576
  function safeKey(value) {
10453
10577
  const parts = value.split("/");
10454
10578
  return !!value && !value.includes("\\") && ![...value].some(
@@ -10583,21 +10707,15 @@ async function importDefinition(plan2, lexicalSource, preferred, selected) {
10583
10707
  if (metadata2.provenance) plan2.provenance[lexicalSource] = metadata2.provenance;
10584
10708
  const tree = selected ? {
10585
10709
  entries: selected,
10586
- evidence: { ...captured.evidence, digest: migrationTreeDigest(selected) }
10710
+ evidence: { ...captured.evidence, digest: migrationTreeDigest(selected) },
10711
+ excluded: captured.excluded
10587
10712
  } : captured;
10588
- const runtime = tree.entries.find(
10589
- (entry3) => entry3.path.split(sep9).some((part) => part === "__pycache__" || /\.py[co]$/.test(part))
10590
- );
10591
- if (runtime)
10592
- fail(
10593
- "E_MIGRATION_RUNTIME_CONTENT",
10594
- "A candidate definition contains generated Python cache content.",
10595
- {
10596
- path: join29(lexicalSource, runtime.path),
10597
- fix: "Remove only verified generated Python cache entries from the source, then rerun the migration preview."
10598
- },
10599
- ExitCode.REFUSED
10600
- );
10713
+ const skipped = selected ? captured.excluded.filter(
10714
+ (item2) => selected.some(
10715
+ (entry3) => entry3.kind === "directory" && entry3.path !== "" && item2.startsWith(`${entry3.path}${sep9}`)
10716
+ )
10717
+ ) : captured.excluded;
10718
+ plan2.skipped.set(lexicalSource, skipped);
10601
10719
  const expected = mapped(plan2.options.mapping?.digests, plan2, lexicalSource) ?? mapped(plan2.options.mapping?.digests, plan2, source);
10602
10720
  if (expected !== void 0 && expected !== tree.evidence.digest)
10603
10721
  refuse2(
@@ -10650,7 +10768,8 @@ async function importDefinition(plan2, lexicalSource, preferred, selected) {
10650
10768
  details: [
10651
10769
  `source: ${lexicalSource}`,
10652
10770
  `canonical name: ${name}`,
10653
- "All captured definition bytes, support entries, modes, and provenance are preserved; internal absolute links are made portable."
10771
+ 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.",
10772
+ ...skippedDetail(skipped, "at this source")
10654
10773
  ],
10655
10774
  dependsOn: []
10656
10775
  };
@@ -10670,7 +10789,8 @@ async function importDefinition(plan2, lexicalSource, preferred, selected) {
10670
10789
  beforeDigest: tree.evidence.digest,
10671
10790
  afterDigest: reused.digest,
10672
10791
  details: [
10673
- 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."
10792
+ 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.",
10793
+ ...skippedDetail(skipped, "at this source")
10674
10794
  ],
10675
10795
  dependsOn: dependency ? [dependency] : []
10676
10796
  });
@@ -10830,6 +10950,8 @@ async function composition(plan2, path, kind2) {
10830
10950
  "E_MIGRATION_REFERENCE",
10831
10951
  "A null reference mapping cannot remove a real definition; name and preserve its content instead."
10832
10952
  );
10953
+ const generated = before.excluded.find((item3) => item3.startsWith(`${definition}${sep9}`));
10954
+ if (generated !== void 0) runtimeContent(join29(path, generated), "candidate definition");
10833
10955
  const skill = await importDefinition(plan2, lexical, basename8(definition));
10834
10956
  members2.push({
10835
10957
  relativePath: definition,
@@ -10844,7 +10966,9 @@ async function composition(plan2, path, kind2) {
10844
10966
  }
10845
10967
  }
10846
10968
  for (const entry3 of tree.entries) {
10847
- if (!entry3.path || entry3.kind !== "link" || definitionRoots.some((parent) => entry3.path.startsWith(`${parent}${sep9}`)))
10969
+ if (!entry3.path || entry3.kind !== "link" || // A hidden link is outside the composition's namespace: never a member, never rewritten,
10970
+ // and its referent (often installer-owned) is never imported into the catalog.
10971
+ hiddenPath(entry3.path) || definitionRoots.some((parent) => entry3.path.startsWith(`${parent}${sep9}`)))
10848
10972
  continue;
10849
10973
  const lexical = join29(path, entry3.path);
10850
10974
  const explicitReference = mapped(plan2.options.mapping?.references, plan2, lexical);
@@ -10908,7 +11032,7 @@ async function composition(plan2, path, kind2) {
10908
11032
  if (kind2 === "pack" || dirname19(member.relativePath) !== ".")
10909
11033
  entries.push(memberLink(plan2, destination, member.relativePath, member.name));
10910
11034
  }
10911
- let selected = members2.map((member) => member.name);
11035
+ let selected = members2.filter((member) => !hiddenPath(member.relativePath)).map((member) => member.name);
10912
11036
  if (kind2 === "pack") {
10913
11037
  const declared = [];
10914
11038
  if (raw.freeform !== void 0 && (!record8(raw.freeform) || !Array.isArray(raw.freeform.skills) || !raw.freeform.skills.every((item3) => typeof item3 === "string")))
@@ -11060,6 +11184,18 @@ async function composition(plan2, path, kind2) {
11060
11184
  entries = entries.sort((a, b) => a.path.localeCompare(b.path));
11061
11185
  const afterDigest = migrationTreeDigest(entries);
11062
11186
  const changed3 = destination !== path || before.evidence.digest !== afterDigest;
11187
+ if (changed3)
11188
+ for (const item3 of before.excluded) {
11189
+ if (definitionRoots.some((root) => item3.startsWith(`${root}${sep9}`))) continue;
11190
+ finding(
11191
+ plan2,
11192
+ join29(path, item3),
11193
+ "E_MIGRATION_RUNTIME_CONTENT",
11194
+ runtimeContentMessage("composition"),
11195
+ runtimeContentFix
11196
+ );
11197
+ hasBlocker = true;
11198
+ }
11063
11199
  const dependencies = [
11064
11200
  ...new Set(members2.flatMap((member) => member.dependency ? [member.dependency] : []))
11065
11201
  ];
@@ -11127,12 +11263,13 @@ async function prepare2(registry, options, previousNames = {}, previousProvenanc
11127
11263
  provenance: { ...previousProvenance },
11128
11264
  externalRoots: new Set(previousExternalRoots),
11129
11265
  canonical: /* @__PURE__ */ new Map(),
11130
- imported: /* @__PURE__ */ new Map()
11266
+ imported: /* @__PURE__ */ new Map(),
11267
+ skipped: /* @__PURE__ */ new Map()
11131
11268
  };
11132
11269
  const catalog = join29(registry.root, "all-skills");
11133
11270
  const links = [];
11134
11271
  const retiredAliases = [];
11135
- for (const entry3 of (await readdir18(catalog, { withFileTypes: true })).sort(
11272
+ for (const entry3 of (await readdir19(catalog, { withFileTypes: true })).sort(
11136
11273
  (a, b) => a.name.localeCompare(b.name)
11137
11274
  )) {
11138
11275
  interrupted2(options);
@@ -11205,7 +11342,10 @@ async function prepare2(registry, options, previousNames = {}, previousProvenanc
11205
11342
  state: "ready",
11206
11343
  beforeDigest: before.evidence.digest,
11207
11344
  afterDigest: skill.digest,
11208
- details: [
11345
+ details: plan2.skipped.get(path)?.length ? [
11346
+ "Identical authored definition content is retained at the canonical target; retire only this exact alias after composition rewrites.",
11347
+ ...skippedDetail(plan2.skipped.get(path) ?? [], "at the alias source")
11348
+ ] : [
11209
11349
  "Identical definition content is retained at the canonical target; retire only this exact alias after composition rewrites."
11210
11350
  ],
11211
11351
  dependsOn: skill.dependency ? [skill.dependency] : []
@@ -11235,7 +11375,7 @@ async function prepare2(registry, options, previousNames = {}, previousProvenanc
11235
11375
  blocked3(plan2, root, new Error("Composition family root must be a real directory."));
11236
11376
  continue;
11237
11377
  }
11238
- for (const entry3 of (await readdir18(root, { withFileTypes: true })).sort(
11378
+ for (const entry3 of (await readdir19(root, { withFileTypes: true })).sort(
11239
11379
  (a, b) => a.name.localeCompare(b.name)
11240
11380
  )) {
11241
11381
  const path = join29(root, entry3.name);
@@ -11257,7 +11397,7 @@ async function prepare2(registry, options, previousNames = {}, previousProvenanc
11257
11397
  else if (await inspectPath(join29(path, "pack.toml"))) await composition(plan2, path, "pack");
11258
11398
  else {
11259
11399
  const versions = [];
11260
- for (const child of await readdir18(path, { withFileTypes: true }))
11400
+ for (const child of await readdir19(path, { withFileTypes: true }))
11261
11401
  if ((child.isDirectory() || child.isSymbolicLink()) && await inspectPath(join29(path, child.name, "pack.toml")))
11262
11402
  versions.push(child.name);
11263
11403
  if (versions.length)
@@ -11527,7 +11667,7 @@ async function migrateRegistry(options = {}) {
11527
11667
  // src/core/migration-sources.ts
11528
11668
  import { createHash as createHash11, randomUUID as randomUUID8 } from "node:crypto";
11529
11669
  import { constants as constants9 } from "node:fs";
11530
- import { link as link6, open as open12, readdir as readdir19, unlink as unlink8 } from "node:fs/promises";
11670
+ import { link as link6, open as open12, readdir as readdir20, unlink as unlink8 } from "node:fs/promises";
11531
11671
  import { basename as basename9, join as join30 } from "node:path";
11532
11672
  var binding3 = { namespace: "migrations", targetParts: ["all-skills", "sources.toml"] };
11533
11673
  var prefix = ".skillex-tmp-migrate-sources-";
@@ -11546,7 +11686,7 @@ function refused2(path, message) {
11546
11686
  async function validateProvenance(registry, text2, path) {
11547
11687
  const sources = parseVendorSourcesText(text2, path);
11548
11688
  const catalog = join30(registry.root, "all-skills");
11549
- for (const name of (await readdir19(catalog)).sort()) {
11689
+ for (const name of (await readdir20(catalog)).sort()) {
11550
11690
  const skill = join30(catalog, name);
11551
11691
  if (!(await inspectPath(skill))?.isDirectory() || !await inspectPath(join30(skill, "SKILL.md")))
11552
11692
  continue;
@@ -11578,7 +11718,7 @@ async function migrateSources(input) {
11578
11718
  const old = snapshot3.document?.data;
11579
11719
  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)))
11580
11720
  refused2(snapshot3.path, "The source migration receipt is malformed.");
11581
- const artifacts = (await readdir19(catalog)).filter((name) => name.startsWith(prefix));
11721
+ const artifacts = (await readdir20(catalog)).filter((name) => name.startsWith(prefix));
11582
11722
  const unknown = artifacts.filter((name) => name !== old?.stage || old.phase !== "pending");
11583
11723
  if (unknown.length)
11584
11724
  return makeResult("migrate sources", data2, {
@@ -11879,7 +12019,7 @@ async function migrate(input = {}) {
11879
12019
  // src/core/profile-sync.ts
11880
12020
  import { randomUUID as randomUUID9 } from "node:crypto";
11881
12021
  import { constants as constants10 } from "node:fs";
11882
- 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";
12022
+ 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";
11883
12023
  import { join as join31, resolve as resolve17 } from "node:path";
11884
12024
  import { isDeepStrictEqual as isDeepStrictEqual6 } from "node:util";
11885
12025
  function refused3(code, message, path, fix) {
@@ -11995,7 +12135,7 @@ async function observations(profile, state) {
11995
12135
  "Use the explicit migrate workflow to replace this whole-root alias or conflicting file while preserving profile content."
11996
12136
  );
11997
12137
  if (root)
11998
- for (const name of (await readdir20(profile.skillsRoot)).sort()) {
12138
+ for (const name of (await readdir21(profile.skillsRoot)).sort()) {
11999
12139
  const path = join31(profile.skillsRoot, name);
12000
12140
  const actual = await entry2(path);
12001
12141
  if (!actual) continue;
@@ -13438,7 +13578,7 @@ async function setInheritance(enabled, options = {}) {
13438
13578
  }
13439
13579
 
13440
13580
  // src/core/sets.ts
13441
- import { readdir as readdir21 } from "node:fs/promises";
13581
+ import { readdir as readdir22 } from "node:fs/promises";
13442
13582
  import { join as join34 } from "node:path";
13443
13583
  function validateName(name) {
13444
13584
  parseManifest({ sets: [{ name }] }, "set name");
@@ -13461,7 +13601,7 @@ async function listSets(options = {}) {
13461
13601
  const failures = [];
13462
13602
  if (await inspectPath(path)) {
13463
13603
  await requireDirectory(path, "E_SET_MISSING");
13464
- for (const entry3 of (await readdir21(path, { withFileTypes: true })).sort(
13604
+ for (const entry3 of (await readdir22(path, { withFileTypes: true })).sort(
13465
13605
  (a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0
13466
13606
  )) {
13467
13607
  if (entry3.name.startsWith(".") || entry3.name.startsWith("_") || !entry3.isDirectory() && !entry3.isSymbolicLink())
@@ -13525,15 +13665,15 @@ async function removeSetSkills(name, names2, options = {}) {
13525
13665
  }
13526
13666
 
13527
13667
  // src/core/vendor-inspect.ts
13528
- import { readdir as readdir22 } from "node:fs/promises";
13668
+ import { readdir as readdir23 } from "node:fs/promises";
13529
13669
  import { join as join35 } from "node:path";
13530
13670
 
13531
13671
  // src/core/vendor-git.ts
13532
- import { execFile as execFile3 } from "node:child_process";
13672
+ import { execFile as execFile4 } from "node:child_process";
13533
13673
  import { realpath as realpath25 } from "node:fs/promises";
13534
13674
  import { posix } from "node:path";
13535
- import { promisify as promisify2 } from "node:util";
13536
- var execute2 = promisify2(execFile3);
13675
+ import { promisify as promisify3 } from "node:util";
13676
+ var execute3 = promisify3(execFile4);
13537
13677
  var oidPattern = /^(?:[a-f0-9]{40}|[a-f0-9]{64})$/;
13538
13678
  function vendorInterrupted(options) {
13539
13679
  if (options.signal?.aborted) {
@@ -13563,7 +13703,7 @@ function gitEnvironment(options) {
13563
13703
  async function git(root, args, options, missingRef = false, allowAbsent = false) {
13564
13704
  vendorInterrupted(options);
13565
13705
  try {
13566
- const result = await execute2(
13706
+ const result = await execute3(
13567
13707
  "git",
13568
13708
  ["--no-lazy-fetch", "-c", "protocol.allow=never", "-C", root, ...args],
13569
13709
  {
@@ -13889,7 +14029,7 @@ async function recordedInventory(manifest, observation, options) {
13889
14029
  const recorded = /* @__PURE__ */ new Map();
13890
14030
  const failed2 = /* @__PURE__ */ new Set();
13891
14031
  const catalog = join35(manifest.registry.root, "all-skills");
13892
- for (const entry3 of (await readdir22(catalog, { withFileTypes: true })).sort(
14032
+ for (const entry3 of (await readdir23(catalog, { withFileTypes: true })).sort(
13893
14033
  (a, b) => a.name.localeCompare(b.name)
13894
14034
  )) {
13895
14035
  checkVendorSignal(options);
@@ -14298,7 +14438,7 @@ async function inspectVendorStatus(options = {}) {
14298
14438
 
14299
14439
  // src/core/vendor-sync.ts
14300
14440
  import { randomUUID as randomUUID11 } from "node:crypto";
14301
- import { chmod as chmod3, lstat as lstat20, mkdir as mkdir12, open as open15, readdir as readdir23, rename as rename10 } from "node:fs/promises";
14441
+ import { chmod as chmod3, lstat as lstat20, mkdir as mkdir12, open as open15, readdir as readdir24, rename as rename10 } from "node:fs/promises";
14302
14442
  import { dirname as dirname22, join as join36 } from "node:path";
14303
14443
  function refuse3(code, message, path, fix) {
14304
14444
  fail(code, message, { path, fix }, ExitCode.REFUSED);
@@ -14496,7 +14636,7 @@ async function prepare4(options, extractedAt) {
14496
14636
  }
14497
14637
  }
14498
14638
  if (options.prune) {
14499
- for (const name of (await readdir23(catalog)).filter(isSkillName).sort()) {
14639
+ for (const name of (await readdir24(catalog)).filter(isSkillName).sort()) {
14500
14640
  if (names2.has(name)) continue;
14501
14641
  const path = join36(catalog, name);
14502
14642
  if (!(await vendorLstat(path))?.isDirectory()) continue;