@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 +253 -113
- package/dist/core/aliases.d.ts +1 -1
- package/dist/core/content.d.ts +7 -0
- package/dist/core/migration-registry-state.d.ts +20 -1
- package/dist/index.js +253 -113
- package/package.json +1 -1
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
|
|
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 {
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
1595
|
-
readFile as
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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, () =>
|
|
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
|
|
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
|
|
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
|
|
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
|
|
6198
|
-
import { readdir as
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
10594
|
-
(
|
|
10595
|
-
|
|
10596
|
-
|
|
10597
|
-
|
|
10598
|
-
|
|
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" ||
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
13541
|
-
var
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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;
|