@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/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
|
|
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 {
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
1590
|
-
readFile as
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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, () =>
|
|
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
|
|
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
|
|
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
|
|
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
|
|
6193
|
-
import { readdir as
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
10589
|
-
(
|
|
10590
|
-
|
|
10591
|
-
|
|
10592
|
-
|
|
10593
|
-
|
|
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" ||
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
13536
|
-
var
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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;
|