@delorenj/skillex 0.4.0 → 0.4.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 +115 -39
- package/dist/core/profile-policy.d.ts +7 -1
- package/dist/index.js +115 -39
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -8620,7 +8620,7 @@ async function buildScope(scope, options, forbiddenRoots, verifySet = verifySele
|
|
|
8620
8620
|
if (!owned4)
|
|
8621
8621
|
refuse3(root, "Whole-root switching requires explicit ownership of the existing root.");
|
|
8622
8622
|
if (owned4.kind === "link") return { identity: owned4 };
|
|
8623
|
-
const
|
|
8623
|
+
const children2 = {};
|
|
8624
8624
|
for (const name of awaitableNames) {
|
|
8625
8625
|
const child = links[join25(root, name)];
|
|
8626
8626
|
if (!child)
|
|
@@ -8628,9 +8628,9 @@ async function buildScope(scope, options, forbiddenRoots, verifySet = verifySele
|
|
|
8628
8628
|
join25(root, name),
|
|
8629
8629
|
"Foreign content prevents a whole-root switch; it will not be removed."
|
|
8630
8630
|
);
|
|
8631
|
-
|
|
8631
|
+
children2[name] = child;
|
|
8632
8632
|
}
|
|
8633
|
-
return { identity: owned4, children };
|
|
8633
|
+
return { identity: owned4, children: children2 };
|
|
8634
8634
|
};
|
|
8635
8635
|
const awaitableNames = rootEntry?.info.isDirectory() ? await readdir16(physicalPath(root, recovery)) : [];
|
|
8636
8636
|
if (!rootEntry) {
|
|
@@ -8969,7 +8969,7 @@ async function publishPrepared(work, staged, destination, node, directories) {
|
|
|
8969
8969
|
async function stageNode(work, operation2, path) {
|
|
8970
8970
|
if (operation2.children !== void 0) {
|
|
8971
8971
|
await mkdir7(path, { mode: 493 });
|
|
8972
|
-
const
|
|
8972
|
+
const children2 = {};
|
|
8973
8973
|
for (const [name, target2] of operation2.children) {
|
|
8974
8974
|
const destination = join25(operation2.path, name);
|
|
8975
8975
|
if (!await canonicalTarget(work, name, target2))
|
|
@@ -8978,11 +8978,11 @@ async function stageNode(work, operation2, path) {
|
|
|
8978
8978
|
await symlink4(relative9(dirname13(destination), target2), child);
|
|
8979
8979
|
const found2 = await entry2(child);
|
|
8980
8980
|
if (!found2) refuse3(child, "Prepared activation link disappeared.");
|
|
8981
|
-
|
|
8981
|
+
children2[name] = identity(found2);
|
|
8982
8982
|
}
|
|
8983
8983
|
const found = await entry2(path);
|
|
8984
8984
|
if (!found) refuse3(path, "Prepared activation directory disappeared.");
|
|
8985
|
-
return { identity: identity(found), children };
|
|
8985
|
+
return { identity: identity(found), children: children2 };
|
|
8986
8986
|
}
|
|
8987
8987
|
if (operation2.target !== void 0) {
|
|
8988
8988
|
if (dirname13(operation2.path) === work.plan.activationRoot && !await canonicalTarget(work, basename5(operation2.path), operation2.target))
|
|
@@ -11417,7 +11417,7 @@ async function captureMigrationNode(path) {
|
|
|
11417
11417
|
mode: Number(before.mode & 0o7777n),
|
|
11418
11418
|
...before.isSymbolicLink() ? { raw: await readlink6(path) } : {}
|
|
11419
11419
|
};
|
|
11420
|
-
const
|
|
11420
|
+
const children2 = {};
|
|
11421
11421
|
let hash5 = null;
|
|
11422
11422
|
if (before.isDirectory()) {
|
|
11423
11423
|
const names2 = await readdir22(path, { encoding: "buffer" });
|
|
@@ -11434,7 +11434,7 @@ async function captureMigrationNode(path) {
|
|
|
11434
11434
|
const child = await captureMigrationNode(join31(path, name));
|
|
11435
11435
|
if (!child)
|
|
11436
11436
|
migrationRefusal(join31(path, name), "Content disappeared during migration inventory.");
|
|
11437
|
-
Object.defineProperty(
|
|
11437
|
+
Object.defineProperty(children2, name, { value: child, enumerable: true });
|
|
11438
11438
|
}
|
|
11439
11439
|
} else if (before.isFile()) {
|
|
11440
11440
|
const handle = await open10(
|
|
@@ -11473,7 +11473,7 @@ async function captureMigrationNode(path) {
|
|
|
11473
11473
|
const after = await lstat20(path, { bigint: true });
|
|
11474
11474
|
if (after.dev !== before.dev || after.ino !== before.ino || after.mode !== before.mode || after.size !== before.size || after.mtimeNs !== before.mtimeNs || after.ctimeNs !== before.ctimeNs)
|
|
11475
11475
|
migrationRefusal(path, "Content changed while its migration inventory was being captured.");
|
|
11476
|
-
return { identity: identity5, hash: hash5, children };
|
|
11476
|
+
return { identity: identity5, hash: hash5, children: children2 };
|
|
11477
11477
|
}
|
|
11478
11478
|
function migrationDigest(node) {
|
|
11479
11479
|
const project = (item2) => ({
|
|
@@ -12574,16 +12574,16 @@ async function prepare2(target2) {
|
|
|
12574
12574
|
shared,
|
|
12575
12575
|
"The old alias points at one skill definition rather than a collection root."
|
|
12576
12576
|
);
|
|
12577
|
-
const
|
|
12577
|
+
const children2 = {};
|
|
12578
12578
|
const claimNames = [];
|
|
12579
12579
|
const proofs = [{ path: shared, node: contents }];
|
|
12580
12580
|
for (const name of Object.keys(contents.children)) {
|
|
12581
12581
|
const path = join34(target2.root, name);
|
|
12582
12582
|
const mapped2 = await canonicalMapping(target2, path);
|
|
12583
12583
|
const output2 = mapped2?.name ?? name;
|
|
12584
|
-
if (Object.hasOwn(
|
|
12584
|
+
if (Object.hasOwn(children2, output2))
|
|
12585
12585
|
migrationRefusal(path, "Two original children map to the same resulting name.");
|
|
12586
|
-
Object.defineProperty(
|
|
12586
|
+
Object.defineProperty(children2, output2, {
|
|
12587
12587
|
value: mapped2?.target ?? join34(shared, name),
|
|
12588
12588
|
enumerable: true
|
|
12589
12589
|
});
|
|
@@ -12598,7 +12598,7 @@ async function prepare2(target2) {
|
|
|
12598
12598
|
[
|
|
12599
12599
|
mapped2 ? "The mapped canonical content is verified." : "The original child remains reachable through a foreign forwarding link; its shared target is untouched."
|
|
12600
12600
|
],
|
|
12601
|
-
|
|
12601
|
+
children2[output2]
|
|
12602
12602
|
)
|
|
12603
12603
|
);
|
|
12604
12604
|
}
|
|
@@ -12607,7 +12607,7 @@ async function prepare2(target2) {
|
|
|
12607
12607
|
"Replace only the old root symlink with a real directory; preserve every inventoried child and leave the shared target untouched."
|
|
12608
12608
|
]),
|
|
12609
12609
|
previous: root,
|
|
12610
|
-
children,
|
|
12610
|
+
children: children2,
|
|
12611
12611
|
claimRoot: true,
|
|
12612
12612
|
claimNames,
|
|
12613
12613
|
proofs
|
|
@@ -18229,14 +18229,14 @@ async function normalizeScope(options = {}) {
|
|
|
18229
18229
|
// src/core/profile-sync.ts
|
|
18230
18230
|
import { randomUUID as randomUUID11 } from "node:crypto";
|
|
18231
18231
|
import { constants as constants13 } from "node:fs";
|
|
18232
|
-
import { mkdir as mkdir12, open as open17, readdir as
|
|
18232
|
+
import { mkdir as mkdir12, open as open17, readdir as readdir30, realpath as realpath32, rename as rename11, symlink as symlink7, unlink as unlink12 } from "node:fs/promises";
|
|
18233
18233
|
import { dirname as dirname27, join as join44, resolve as resolve25 } from "node:path";
|
|
18234
18234
|
import { isDeepStrictEqual as isDeepStrictEqual10 } from "node:util";
|
|
18235
18235
|
|
|
18236
18236
|
// src/core/profile-policy.ts
|
|
18237
18237
|
import { constants as constants12 } from "node:fs";
|
|
18238
|
-
import { open as open16, readFile as readFile18, stat as stat8 } from "node:fs/promises";
|
|
18239
|
-
import { join as join43 } from "node:path";
|
|
18238
|
+
import { open as open16, readdir as readdir29, readFile as readFile18, stat as stat8 } from "node:fs/promises";
|
|
18239
|
+
import { basename as basename13, join as join43 } from "node:path";
|
|
18240
18240
|
import { parseDocument as parseDocument4 } from "yaml";
|
|
18241
18241
|
var metadataFiles = /* @__PURE__ */ new Set([
|
|
18242
18242
|
".usage.json",
|
|
@@ -18248,9 +18248,48 @@ var metadataFiles = /* @__PURE__ */ new Set([
|
|
|
18248
18248
|
".curator_ledger.jsonl"
|
|
18249
18249
|
]);
|
|
18250
18250
|
var metadataDirectories = /* @__PURE__ */ new Set([".curator_backups", ".locks"]);
|
|
18251
|
-
|
|
18251
|
+
var hubFiles = /* @__PURE__ */ new Set(["audit.log", "taps.json", "lock.json"]);
|
|
18252
|
+
async function children(path) {
|
|
18253
|
+
try {
|
|
18254
|
+
return await readdir29(path, { withFileTypes: true });
|
|
18255
|
+
} catch {
|
|
18256
|
+
return null;
|
|
18257
|
+
}
|
|
18258
|
+
}
|
|
18259
|
+
async function categoryStub(item2) {
|
|
18260
|
+
if (item2.kind !== "directory" || item2.shadows) return false;
|
|
18261
|
+
const entries = await children(item2.path);
|
|
18262
|
+
return entries?.length === 1 && entries[0]?.name === "DESCRIPTION.md" && entries[0].isFile();
|
|
18263
|
+
}
|
|
18264
|
+
async function idleHub(item2) {
|
|
18265
|
+
if (item2.kind !== "directory" || item2.name !== ".hub") return false;
|
|
18266
|
+
const entries = await children(item2.path);
|
|
18267
|
+
if (!entries) return false;
|
|
18268
|
+
for (const child of entries) {
|
|
18269
|
+
const path = join43(item2.path, child.name);
|
|
18270
|
+
if (child.isFile() && hubFiles.has(child.name)) {
|
|
18271
|
+
if (child.name !== "lock.json") continue;
|
|
18272
|
+
try {
|
|
18273
|
+
const lock = JSON.parse(await readFile18(path, "utf8"));
|
|
18274
|
+
const installed = lock?.installed;
|
|
18275
|
+
if (!installed || typeof installed !== "object" || Object.keys(installed).length)
|
|
18276
|
+
return false;
|
|
18277
|
+
} catch {
|
|
18278
|
+
return false;
|
|
18279
|
+
}
|
|
18280
|
+
} else if (child.isDirectory() && child.name === "quarantine") {
|
|
18281
|
+
if ((await children(path))?.length !== 0) return false;
|
|
18282
|
+
} else if (child.isDirectory() && child.name === "index-cache") {
|
|
18283
|
+
const cached2 = await children(path);
|
|
18284
|
+
if (!cached2 || cached2.some((entry3) => !entry3.isFile())) return false;
|
|
18285
|
+
} else return false;
|
|
18286
|
+
}
|
|
18287
|
+
return true;
|
|
18288
|
+
}
|
|
18289
|
+
async function hermesMetadata(item2) {
|
|
18252
18290
|
if (item2.kind === "file") return metadataFiles.has(item2.name);
|
|
18253
|
-
if (item2.kind === "directory")
|
|
18291
|
+
if (item2.kind === "directory")
|
|
18292
|
+
return metadataDirectories.has(item2.name) || await idleHub(item2) || await categoryStub(item2);
|
|
18254
18293
|
return false;
|
|
18255
18294
|
}
|
|
18256
18295
|
function refuse5(path, message) {
|
|
@@ -18285,11 +18324,38 @@ async function profileInheritsGlobal(profile) {
|
|
|
18285
18324
|
refuse5(path, "Profile skills.inherit_global must be boolean.");
|
|
18286
18325
|
return inherit !== false;
|
|
18287
18326
|
}
|
|
18288
|
-
|
|
18327
|
+
var learnedScanLimit = 2e4;
|
|
18328
|
+
async function learnedSkills(item2) {
|
|
18329
|
+
if (item2.kind !== "directory" || item2.name.startsWith(".")) return null;
|
|
18330
|
+
const skills = [];
|
|
18331
|
+
const pending = [item2.path];
|
|
18332
|
+
let seen = 0;
|
|
18333
|
+
while (pending.length) {
|
|
18334
|
+
const directory2 = pending.pop();
|
|
18335
|
+
const entries = await children(directory2);
|
|
18336
|
+
if (!entries) return null;
|
|
18337
|
+
for (const child of entries) {
|
|
18338
|
+
if (++seen > learnedScanLimit) return null;
|
|
18339
|
+
if (child.isDirectory()) pending.push(join43(directory2, child.name));
|
|
18340
|
+
else if (!child.isFile()) return null;
|
|
18341
|
+
else if (child.name === "SKILL.md") skills.push(basename13(directory2));
|
|
18342
|
+
}
|
|
18343
|
+
}
|
|
18344
|
+
return skills;
|
|
18345
|
+
}
|
|
18346
|
+
async function assertStrictProfile(profile, options, local, desired = /* @__PURE__ */ new Set()) {
|
|
18289
18347
|
if (!await strictProfile(profile, options)) return false;
|
|
18290
|
-
for (const item2 of local)
|
|
18291
|
-
if (
|
|
18292
|
-
|
|
18348
|
+
for (const item2 of local) {
|
|
18349
|
+
if (await hermesMetadata(item2)) continue;
|
|
18350
|
+
const learned = await learnedSkills(item2);
|
|
18351
|
+
if (!learned) refuse5(item2.path, `Skillex-only profile contains unowned entry ${item2.name}.`);
|
|
18352
|
+
const clash = [item2.name, ...learned].find((name) => desired.has(name));
|
|
18353
|
+
if (clash !== void 0)
|
|
18354
|
+
refuse5(
|
|
18355
|
+
item2.path,
|
|
18356
|
+
`Agent-written skill ${clash} in ${item2.name} shares its name with a selected skill.`
|
|
18357
|
+
);
|
|
18358
|
+
}
|
|
18293
18359
|
const path = join43(profile.root, "config.yaml");
|
|
18294
18360
|
const config = await entry2(path);
|
|
18295
18361
|
if (config) {
|
|
@@ -18461,7 +18527,7 @@ async function observations(profile, state) {
|
|
|
18461
18527
|
"Use the explicit migrate workflow to replace this whole-root alias or conflicting file while preserving profile content."
|
|
18462
18528
|
);
|
|
18463
18529
|
if (root)
|
|
18464
|
-
for (const name of (await
|
|
18530
|
+
for (const name of (await readdir30(profile.skillsRoot)).sort()) {
|
|
18465
18531
|
const path = join44(profile.skillsRoot, name);
|
|
18466
18532
|
const actual = await entry2(path);
|
|
18467
18533
|
if (!actual) continue;
|
|
@@ -18534,7 +18600,12 @@ async function buildWork(profile, state, options) {
|
|
|
18534
18600
|
);
|
|
18535
18601
|
state = await readProfileState(profile, receiptOptions(profile, options, projection.scopes));
|
|
18536
18602
|
const observed = await observations(profile, state);
|
|
18537
|
-
await assertStrictProfile(
|
|
18603
|
+
await assertStrictProfile(
|
|
18604
|
+
profile,
|
|
18605
|
+
options,
|
|
18606
|
+
observed.local,
|
|
18607
|
+
new Set(projection.desired.map((desired) => desired.name))
|
|
18608
|
+
);
|
|
18538
18609
|
const links = { ...state.data.links };
|
|
18539
18610
|
const changes = [];
|
|
18540
18611
|
if (!observed.root) changes.push({ action: "mkdir", path: profile.skillsRoot });
|
|
@@ -19010,7 +19081,12 @@ async function runProfileSync(name, options) {
|
|
|
19010
19081
|
});
|
|
19011
19082
|
}
|
|
19012
19083
|
await assertProfileIdentity(selected);
|
|
19013
|
-
if (await assertStrictProfile(
|
|
19084
|
+
if (await assertStrictProfile(
|
|
19085
|
+
selected,
|
|
19086
|
+
options,
|
|
19087
|
+
(await observations(selected, state)).local,
|
|
19088
|
+
new Set(work.projection.desired.map((desired) => desired.name))
|
|
19089
|
+
))
|
|
19014
19090
|
await publishStrictPolicy(selected);
|
|
19015
19091
|
const currentProfile = await discoverProfile(name, options);
|
|
19016
19092
|
if (currentProfile.root !== selected.root || currentProfile.skillsRoot !== selected.skillsRoot)
|
|
@@ -19652,7 +19728,7 @@ import { randomUUID as randomUUID13 } from "node:crypto";
|
|
|
19652
19728
|
import { constants as constants14 } from "node:fs";
|
|
19653
19729
|
import { mkdir as mkdir13, open as open19, realpath as realpath34, rename as rename13, symlink as symlink8 } from "node:fs/promises";
|
|
19654
19730
|
import { homedir as homedir16 } from "node:os";
|
|
19655
|
-
import { basename as
|
|
19731
|
+
import { basename as basename14, dirname as dirname29, join as join46, parse as parse6, resolve as resolve27 } from "node:path";
|
|
19656
19732
|
import { isDeepStrictEqual as isDeepStrictEqual12 } from "node:util";
|
|
19657
19733
|
import { valid as valid3 } from "semver";
|
|
19658
19734
|
var binding5 = { namespace: "migrations", targetParts: [".agents", "root-adoption"] };
|
|
@@ -19852,7 +19928,7 @@ async function guard2(context2, journal) {
|
|
|
19852
19928
|
function paths2(snapshot3, id) {
|
|
19853
19929
|
const prefix2 = join46(
|
|
19854
19930
|
dirname29(snapshot3.path),
|
|
19855
|
-
`${
|
|
19931
|
+
`${basename14(snapshot3.path, ".json")}.root-cutover-${id}`
|
|
19856
19932
|
);
|
|
19857
19933
|
return { archive: `${prefix2}-old`, stage: `${prefix2}-new` };
|
|
19858
19934
|
}
|
|
@@ -19964,8 +20040,8 @@ function journalData(snapshot3, context2) {
|
|
|
19964
20040
|
)))
|
|
19965
20041
|
refuse7(snapshot3.path, "The staged root does not match its canonical inventory.");
|
|
19966
20042
|
for (const stage2 of raw.preservedStages) {
|
|
19967
|
-
const prefix2 = `${
|
|
19968
|
-
if (typeof stage2 !== "string" || dirname29(stage2) !== dirname29(snapshot3.path) || !
|
|
20043
|
+
const prefix2 = `${basename14(snapshot3.path, ".json")}.root-cutover-`;
|
|
20044
|
+
if (typeof stage2 !== "string" || dirname29(stage2) !== dirname29(snapshot3.path) || !basename14(stage2).startsWith(prefix2) || !uuid.test(basename14(stage2).slice(prefix2.length, -4)) || !stage2.endsWith("-new"))
|
|
19969
20045
|
refuse7(snapshot3.path, "A preserved stage has an invalid quarantine path.");
|
|
19970
20046
|
}
|
|
19971
20047
|
const data2 = raw;
|
|
@@ -20006,7 +20082,7 @@ async function ownerFor2(context2, allowed) {
|
|
|
20006
20082
|
]) {
|
|
20007
20083
|
if (allowed && (path === context2.root || dirname29(path) === context2.root)) {
|
|
20008
20084
|
const candidates = allowed.map(
|
|
20009
|
-
(node) => path === context2.root ? node : node.children[
|
|
20085
|
+
(node) => path === context2.root ? node : node.children[basename14(path)]
|
|
20010
20086
|
);
|
|
20011
20087
|
if (!candidates.some(
|
|
20012
20088
|
(node) => node && ["link", "directory"].includes(node.identity.kind) && isDeepStrictEqual12(nodeIdentity(node), expected)
|
|
@@ -20669,7 +20745,7 @@ async function adoptRoot(options = {}) {
|
|
|
20669
20745
|
}
|
|
20670
20746
|
|
|
20671
20747
|
// src/core/sets.ts
|
|
20672
|
-
import { readdir as
|
|
20748
|
+
import { readdir as readdir31 } from "node:fs/promises";
|
|
20673
20749
|
import { join as join47 } from "node:path";
|
|
20674
20750
|
function validateName(name) {
|
|
20675
20751
|
parseManifest({ sets: [{ name }] }, "set name");
|
|
@@ -20692,7 +20768,7 @@ async function listSets(options = {}) {
|
|
|
20692
20768
|
const failures = [];
|
|
20693
20769
|
if (await inspectPath(path)) {
|
|
20694
20770
|
await requireDirectory(path, "E_SET_MISSING");
|
|
20695
|
-
for (const entry3 of (await
|
|
20771
|
+
for (const entry3 of (await readdir31(path, { withFileTypes: true })).sort(
|
|
20696
20772
|
(a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0
|
|
20697
20773
|
)) {
|
|
20698
20774
|
if (entry3.name.startsWith(".") || entry3.name.startsWith("_") || !entry3.isDirectory() && !entry3.isSymbolicLink())
|
|
@@ -20834,7 +20910,7 @@ async function removeSetSkills(name, names2, options = {}) {
|
|
|
20834
20910
|
}
|
|
20835
20911
|
|
|
20836
20912
|
// src/core/vendor-inspect.ts
|
|
20837
|
-
import { readdir as
|
|
20913
|
+
import { readdir as readdir32 } from "node:fs/promises";
|
|
20838
20914
|
import { join as join48 } from "node:path";
|
|
20839
20915
|
|
|
20840
20916
|
// src/core/vendor-git.ts
|
|
@@ -21126,8 +21202,8 @@ async function readVendorGitSource(source, checkoutRoot, options = {}) {
|
|
|
21126
21202
|
checkout
|
|
21127
21203
|
).trim();
|
|
21128
21204
|
const base = await treeAt(checkout, rootTree, source.subdir, options);
|
|
21129
|
-
const
|
|
21130
|
-
const declarations = source.membership === "explicit" ? source.skills :
|
|
21205
|
+
const children2 = await treeEntries(checkout, base, options);
|
|
21206
|
+
const declarations = source.membership === "explicit" ? source.skills : children2.filter(
|
|
21131
21207
|
(entry3) => !entry3.name.startsWith(".") && !entry3.name.startsWith("_") && (entry3.type === "tree" || entry3.mode === "120000" || entry3.mode === "160000")
|
|
21132
21208
|
).map((entry3) => ({ name: entry3.name, dir: entry3.name }));
|
|
21133
21209
|
const selected = declarations.filter(
|
|
@@ -21199,7 +21275,7 @@ async function recordedInventory(manifest, observation, options) {
|
|
|
21199
21275
|
const recorded = /* @__PURE__ */ new Map();
|
|
21200
21276
|
const failed2 = /* @__PURE__ */ new Set();
|
|
21201
21277
|
const catalog = join48(manifest.registry.root, "all-skills");
|
|
21202
|
-
for (const entry3 of (await
|
|
21278
|
+
for (const entry3 of (await readdir32(catalog, { withFileTypes: true })).sort(
|
|
21203
21279
|
(a, b) => a.name.localeCompare(b.name)
|
|
21204
21280
|
)) {
|
|
21205
21281
|
checkVendorSignal(options);
|
|
@@ -21672,7 +21748,7 @@ async function inspectVendorStatus(options = {}) {
|
|
|
21672
21748
|
|
|
21673
21749
|
// src/core/vendor-sync.ts
|
|
21674
21750
|
import { randomUUID as randomUUID14 } from "node:crypto";
|
|
21675
|
-
import { chmod as chmod4, lstat as lstat27, mkdir as mkdir14, open as open20, readdir as
|
|
21751
|
+
import { chmod as chmod4, lstat as lstat27, mkdir as mkdir14, open as open20, readdir as readdir33, rename as rename14 } from "node:fs/promises";
|
|
21676
21752
|
import { dirname as dirname30, join as join49 } from "node:path";
|
|
21677
21753
|
function refuse8(code, message, path, fix) {
|
|
21678
21754
|
fail(code, message, { path, fix }, ExitCode.REFUSED);
|
|
@@ -21899,7 +21975,7 @@ async function prepare6(options, extractedAt) {
|
|
|
21899
21975
|
}
|
|
21900
21976
|
}
|
|
21901
21977
|
if (options.prune) {
|
|
21902
|
-
for (const name of (await
|
|
21978
|
+
for (const name of (await readdir33(catalog)).filter(isSkillName).sort()) {
|
|
21903
21979
|
if (names2.has(name)) continue;
|
|
21904
21980
|
const path = join49(catalog, name);
|
|
21905
21981
|
if (!(await vendorLstat(path))?.isDirectory()) continue;
|
|
@@ -2,5 +2,11 @@ import type { ProfileLocalEntry, ProfileLocation, ProfileOptions } from "./profi
|
|
|
2
2
|
export declare function strictProfile(profile: ProfileLocation, options: ProfileOptions): Promise<boolean>;
|
|
3
3
|
/** Persist a profile's selection boundary independently of the caller's HOME. */
|
|
4
4
|
export declare function profileInheritsGlobal(profile: ProfileLocation): Promise<boolean>;
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Strict (Skillex-only) policy: Skillex owns every link it projects. Hermes bookkeeping and the
|
|
7
|
+
* skills a desk's own agent wrote may sit beside those links (operator decision 2026-11-06,
|
|
8
|
+
* SKRILL-35); a learned skill named like a selected one, a foreign link, a stray file, an
|
|
9
|
+
* archive or a hub install is still refused. `desired` names the skills Skillex will project.
|
|
10
|
+
*/
|
|
11
|
+
export declare function assertStrictProfile(profile: ProfileLocation, options: ProfileOptions, local: readonly ProfileLocalEntry[], desired?: ReadonlySet<string>): Promise<boolean>;
|
|
6
12
|
export declare function publishStrictPolicy(profile: ProfileLocation): Promise<void>;
|
package/dist/index.js
CHANGED
|
@@ -8618,7 +8618,7 @@ async function buildScope(scope, options, forbiddenRoots, verifySet = verifySele
|
|
|
8618
8618
|
if (!owned4)
|
|
8619
8619
|
refuse3(root, "Whole-root switching requires explicit ownership of the existing root.");
|
|
8620
8620
|
if (owned4.kind === "link") return { identity: owned4 };
|
|
8621
|
-
const
|
|
8621
|
+
const children2 = {};
|
|
8622
8622
|
for (const name of awaitableNames) {
|
|
8623
8623
|
const child = links[join25(root, name)];
|
|
8624
8624
|
if (!child)
|
|
@@ -8626,9 +8626,9 @@ async function buildScope(scope, options, forbiddenRoots, verifySet = verifySele
|
|
|
8626
8626
|
join25(root, name),
|
|
8627
8627
|
"Foreign content prevents a whole-root switch; it will not be removed."
|
|
8628
8628
|
);
|
|
8629
|
-
|
|
8629
|
+
children2[name] = child;
|
|
8630
8630
|
}
|
|
8631
|
-
return { identity: owned4, children };
|
|
8631
|
+
return { identity: owned4, children: children2 };
|
|
8632
8632
|
};
|
|
8633
8633
|
const awaitableNames = rootEntry?.info.isDirectory() ? await readdir16(physicalPath(root, recovery)) : [];
|
|
8634
8634
|
if (!rootEntry) {
|
|
@@ -8967,7 +8967,7 @@ async function publishPrepared(work, staged, destination, node, directories) {
|
|
|
8967
8967
|
async function stageNode(work, operation2, path) {
|
|
8968
8968
|
if (operation2.children !== void 0) {
|
|
8969
8969
|
await mkdir7(path, { mode: 493 });
|
|
8970
|
-
const
|
|
8970
|
+
const children2 = {};
|
|
8971
8971
|
for (const [name, target2] of operation2.children) {
|
|
8972
8972
|
const destination = join25(operation2.path, name);
|
|
8973
8973
|
if (!await canonicalTarget(work, name, target2))
|
|
@@ -8976,11 +8976,11 @@ async function stageNode(work, operation2, path) {
|
|
|
8976
8976
|
await symlink4(relative9(dirname13(destination), target2), child);
|
|
8977
8977
|
const found2 = await entry2(child);
|
|
8978
8978
|
if (!found2) refuse3(child, "Prepared activation link disappeared.");
|
|
8979
|
-
|
|
8979
|
+
children2[name] = identity(found2);
|
|
8980
8980
|
}
|
|
8981
8981
|
const found = await entry2(path);
|
|
8982
8982
|
if (!found) refuse3(path, "Prepared activation directory disappeared.");
|
|
8983
|
-
return { identity: identity(found), children };
|
|
8983
|
+
return { identity: identity(found), children: children2 };
|
|
8984
8984
|
}
|
|
8985
8985
|
if (operation2.target !== void 0) {
|
|
8986
8986
|
if (dirname13(operation2.path) === work.plan.activationRoot && !await canonicalTarget(work, basename5(operation2.path), operation2.target))
|
|
@@ -11415,7 +11415,7 @@ async function captureMigrationNode(path) {
|
|
|
11415
11415
|
mode: Number(before.mode & 0o7777n),
|
|
11416
11416
|
...before.isSymbolicLink() ? { raw: await readlink6(path) } : {}
|
|
11417
11417
|
};
|
|
11418
|
-
const
|
|
11418
|
+
const children2 = {};
|
|
11419
11419
|
let hash5 = null;
|
|
11420
11420
|
if (before.isDirectory()) {
|
|
11421
11421
|
const names2 = await readdir22(path, { encoding: "buffer" });
|
|
@@ -11432,7 +11432,7 @@ async function captureMigrationNode(path) {
|
|
|
11432
11432
|
const child = await captureMigrationNode(join31(path, name));
|
|
11433
11433
|
if (!child)
|
|
11434
11434
|
migrationRefusal(join31(path, name), "Content disappeared during migration inventory.");
|
|
11435
|
-
Object.defineProperty(
|
|
11435
|
+
Object.defineProperty(children2, name, { value: child, enumerable: true });
|
|
11436
11436
|
}
|
|
11437
11437
|
} else if (before.isFile()) {
|
|
11438
11438
|
const handle = await open10(
|
|
@@ -11471,7 +11471,7 @@ async function captureMigrationNode(path) {
|
|
|
11471
11471
|
const after = await lstat20(path, { bigint: true });
|
|
11472
11472
|
if (after.dev !== before.dev || after.ino !== before.ino || after.mode !== before.mode || after.size !== before.size || after.mtimeNs !== before.mtimeNs || after.ctimeNs !== before.ctimeNs)
|
|
11473
11473
|
migrationRefusal(path, "Content changed while its migration inventory was being captured.");
|
|
11474
|
-
return { identity: identity4, hash: hash5, children };
|
|
11474
|
+
return { identity: identity4, hash: hash5, children: children2 };
|
|
11475
11475
|
}
|
|
11476
11476
|
function migrationDigest(node) {
|
|
11477
11477
|
const project = (item2) => ({
|
|
@@ -12572,16 +12572,16 @@ async function prepare2(target2) {
|
|
|
12572
12572
|
shared,
|
|
12573
12573
|
"The old alias points at one skill definition rather than a collection root."
|
|
12574
12574
|
);
|
|
12575
|
-
const
|
|
12575
|
+
const children2 = {};
|
|
12576
12576
|
const claimNames = [];
|
|
12577
12577
|
const proofs = [{ path: shared, node: contents }];
|
|
12578
12578
|
for (const name of Object.keys(contents.children)) {
|
|
12579
12579
|
const path = join34(target2.root, name);
|
|
12580
12580
|
const mapped2 = await canonicalMapping(target2, path);
|
|
12581
12581
|
const output = mapped2?.name ?? name;
|
|
12582
|
-
if (Object.hasOwn(
|
|
12582
|
+
if (Object.hasOwn(children2, output))
|
|
12583
12583
|
migrationRefusal(path, "Two original children map to the same resulting name.");
|
|
12584
|
-
Object.defineProperty(
|
|
12584
|
+
Object.defineProperty(children2, output, {
|
|
12585
12585
|
value: mapped2?.target ?? join34(shared, name),
|
|
12586
12586
|
enumerable: true
|
|
12587
12587
|
});
|
|
@@ -12596,7 +12596,7 @@ async function prepare2(target2) {
|
|
|
12596
12596
|
[
|
|
12597
12597
|
mapped2 ? "The mapped canonical content is verified." : "The original child remains reachable through a foreign forwarding link; its shared target is untouched."
|
|
12598
12598
|
],
|
|
12599
|
-
|
|
12599
|
+
children2[output]
|
|
12600
12600
|
)
|
|
12601
12601
|
);
|
|
12602
12602
|
}
|
|
@@ -12605,7 +12605,7 @@ async function prepare2(target2) {
|
|
|
12605
12605
|
"Replace only the old root symlink with a real directory; preserve every inventoried child and leave the shared target untouched."
|
|
12606
12606
|
]),
|
|
12607
12607
|
previous: root,
|
|
12608
|
-
children,
|
|
12608
|
+
children: children2,
|
|
12609
12609
|
claimRoot: true,
|
|
12610
12610
|
claimNames,
|
|
12611
12611
|
proofs
|
|
@@ -18227,14 +18227,14 @@ async function normalizeScope(options = {}) {
|
|
|
18227
18227
|
// src/core/profile-sync.ts
|
|
18228
18228
|
import { randomUUID as randomUUID11 } from "node:crypto";
|
|
18229
18229
|
import { constants as constants13 } from "node:fs";
|
|
18230
|
-
import { mkdir as mkdir12, open as open17, readdir as
|
|
18230
|
+
import { mkdir as mkdir12, open as open17, readdir as readdir30, realpath as realpath32, rename as rename11, symlink as symlink7, unlink as unlink12 } from "node:fs/promises";
|
|
18231
18231
|
import { dirname as dirname27, join as join44, resolve as resolve25 } from "node:path";
|
|
18232
18232
|
import { isDeepStrictEqual as isDeepStrictEqual10 } from "node:util";
|
|
18233
18233
|
|
|
18234
18234
|
// src/core/profile-policy.ts
|
|
18235
18235
|
import { constants as constants12 } from "node:fs";
|
|
18236
|
-
import { open as open16, readFile as readFile18, stat as stat8 } from "node:fs/promises";
|
|
18237
|
-
import { join as join43 } from "node:path";
|
|
18236
|
+
import { open as open16, readdir as readdir29, readFile as readFile18, stat as stat8 } from "node:fs/promises";
|
|
18237
|
+
import { basename as basename13, join as join43 } from "node:path";
|
|
18238
18238
|
import { parseDocument as parseDocument4 } from "yaml";
|
|
18239
18239
|
var metadataFiles = /* @__PURE__ */ new Set([
|
|
18240
18240
|
".usage.json",
|
|
@@ -18246,9 +18246,48 @@ var metadataFiles = /* @__PURE__ */ new Set([
|
|
|
18246
18246
|
".curator_ledger.jsonl"
|
|
18247
18247
|
]);
|
|
18248
18248
|
var metadataDirectories = /* @__PURE__ */ new Set([".curator_backups", ".locks"]);
|
|
18249
|
-
|
|
18249
|
+
var hubFiles = /* @__PURE__ */ new Set(["audit.log", "taps.json", "lock.json"]);
|
|
18250
|
+
async function children(path) {
|
|
18251
|
+
try {
|
|
18252
|
+
return await readdir29(path, { withFileTypes: true });
|
|
18253
|
+
} catch {
|
|
18254
|
+
return null;
|
|
18255
|
+
}
|
|
18256
|
+
}
|
|
18257
|
+
async function categoryStub(item2) {
|
|
18258
|
+
if (item2.kind !== "directory" || item2.shadows) return false;
|
|
18259
|
+
const entries = await children(item2.path);
|
|
18260
|
+
return entries?.length === 1 && entries[0]?.name === "DESCRIPTION.md" && entries[0].isFile();
|
|
18261
|
+
}
|
|
18262
|
+
async function idleHub(item2) {
|
|
18263
|
+
if (item2.kind !== "directory" || item2.name !== ".hub") return false;
|
|
18264
|
+
const entries = await children(item2.path);
|
|
18265
|
+
if (!entries) return false;
|
|
18266
|
+
for (const child of entries) {
|
|
18267
|
+
const path = join43(item2.path, child.name);
|
|
18268
|
+
if (child.isFile() && hubFiles.has(child.name)) {
|
|
18269
|
+
if (child.name !== "lock.json") continue;
|
|
18270
|
+
try {
|
|
18271
|
+
const lock = JSON.parse(await readFile18(path, "utf8"));
|
|
18272
|
+
const installed = lock?.installed;
|
|
18273
|
+
if (!installed || typeof installed !== "object" || Object.keys(installed).length)
|
|
18274
|
+
return false;
|
|
18275
|
+
} catch {
|
|
18276
|
+
return false;
|
|
18277
|
+
}
|
|
18278
|
+
} else if (child.isDirectory() && child.name === "quarantine") {
|
|
18279
|
+
if ((await children(path))?.length !== 0) return false;
|
|
18280
|
+
} else if (child.isDirectory() && child.name === "index-cache") {
|
|
18281
|
+
const cached2 = await children(path);
|
|
18282
|
+
if (!cached2 || cached2.some((entry3) => !entry3.isFile())) return false;
|
|
18283
|
+
} else return false;
|
|
18284
|
+
}
|
|
18285
|
+
return true;
|
|
18286
|
+
}
|
|
18287
|
+
async function hermesMetadata(item2) {
|
|
18250
18288
|
if (item2.kind === "file") return metadataFiles.has(item2.name);
|
|
18251
|
-
if (item2.kind === "directory")
|
|
18289
|
+
if (item2.kind === "directory")
|
|
18290
|
+
return metadataDirectories.has(item2.name) || await idleHub(item2) || await categoryStub(item2);
|
|
18252
18291
|
return false;
|
|
18253
18292
|
}
|
|
18254
18293
|
function refuse5(path, message) {
|
|
@@ -18283,11 +18322,38 @@ async function profileInheritsGlobal(profile) {
|
|
|
18283
18322
|
refuse5(path, "Profile skills.inherit_global must be boolean.");
|
|
18284
18323
|
return inherit !== false;
|
|
18285
18324
|
}
|
|
18286
|
-
|
|
18325
|
+
var learnedScanLimit = 2e4;
|
|
18326
|
+
async function learnedSkills(item2) {
|
|
18327
|
+
if (item2.kind !== "directory" || item2.name.startsWith(".")) return null;
|
|
18328
|
+
const skills = [];
|
|
18329
|
+
const pending = [item2.path];
|
|
18330
|
+
let seen = 0;
|
|
18331
|
+
while (pending.length) {
|
|
18332
|
+
const directory2 = pending.pop();
|
|
18333
|
+
const entries = await children(directory2);
|
|
18334
|
+
if (!entries) return null;
|
|
18335
|
+
for (const child of entries) {
|
|
18336
|
+
if (++seen > learnedScanLimit) return null;
|
|
18337
|
+
if (child.isDirectory()) pending.push(join43(directory2, child.name));
|
|
18338
|
+
else if (!child.isFile()) return null;
|
|
18339
|
+
else if (child.name === "SKILL.md") skills.push(basename13(directory2));
|
|
18340
|
+
}
|
|
18341
|
+
}
|
|
18342
|
+
return skills;
|
|
18343
|
+
}
|
|
18344
|
+
async function assertStrictProfile(profile, options, local, desired = /* @__PURE__ */ new Set()) {
|
|
18287
18345
|
if (!await strictProfile(profile, options)) return false;
|
|
18288
|
-
for (const item2 of local)
|
|
18289
|
-
if (
|
|
18290
|
-
|
|
18346
|
+
for (const item2 of local) {
|
|
18347
|
+
if (await hermesMetadata(item2)) continue;
|
|
18348
|
+
const learned = await learnedSkills(item2);
|
|
18349
|
+
if (!learned) refuse5(item2.path, `Skillex-only profile contains unowned entry ${item2.name}.`);
|
|
18350
|
+
const clash = [item2.name, ...learned].find((name) => desired.has(name));
|
|
18351
|
+
if (clash !== void 0)
|
|
18352
|
+
refuse5(
|
|
18353
|
+
item2.path,
|
|
18354
|
+
`Agent-written skill ${clash} in ${item2.name} shares its name with a selected skill.`
|
|
18355
|
+
);
|
|
18356
|
+
}
|
|
18291
18357
|
const path = join43(profile.root, "config.yaml");
|
|
18292
18358
|
const config = await entry2(path);
|
|
18293
18359
|
if (config) {
|
|
@@ -18459,7 +18525,7 @@ async function observations(profile, state) {
|
|
|
18459
18525
|
"Use the explicit migrate workflow to replace this whole-root alias or conflicting file while preserving profile content."
|
|
18460
18526
|
);
|
|
18461
18527
|
if (root)
|
|
18462
|
-
for (const name of (await
|
|
18528
|
+
for (const name of (await readdir30(profile.skillsRoot)).sort()) {
|
|
18463
18529
|
const path = join44(profile.skillsRoot, name);
|
|
18464
18530
|
const actual = await entry2(path);
|
|
18465
18531
|
if (!actual) continue;
|
|
@@ -18532,7 +18598,12 @@ async function buildWork(profile, state, options) {
|
|
|
18532
18598
|
);
|
|
18533
18599
|
state = await readProfileState(profile, receiptOptions(profile, options, projection.scopes));
|
|
18534
18600
|
const observed = await observations(profile, state);
|
|
18535
|
-
await assertStrictProfile(
|
|
18601
|
+
await assertStrictProfile(
|
|
18602
|
+
profile,
|
|
18603
|
+
options,
|
|
18604
|
+
observed.local,
|
|
18605
|
+
new Set(projection.desired.map((desired) => desired.name))
|
|
18606
|
+
);
|
|
18536
18607
|
const links = { ...state.data.links };
|
|
18537
18608
|
const changes = [];
|
|
18538
18609
|
if (!observed.root) changes.push({ action: "mkdir", path: profile.skillsRoot });
|
|
@@ -19008,7 +19079,12 @@ async function runProfileSync(name, options) {
|
|
|
19008
19079
|
});
|
|
19009
19080
|
}
|
|
19010
19081
|
await assertProfileIdentity(selected);
|
|
19011
|
-
if (await assertStrictProfile(
|
|
19082
|
+
if (await assertStrictProfile(
|
|
19083
|
+
selected,
|
|
19084
|
+
options,
|
|
19085
|
+
(await observations(selected, state)).local,
|
|
19086
|
+
new Set(work.projection.desired.map((desired) => desired.name))
|
|
19087
|
+
))
|
|
19012
19088
|
await publishStrictPolicy(selected);
|
|
19013
19089
|
const currentProfile = await discoverProfile(name, options);
|
|
19014
19090
|
if (currentProfile.root !== selected.root || currentProfile.skillsRoot !== selected.skillsRoot)
|
|
@@ -19650,7 +19726,7 @@ import { randomUUID as randomUUID13 } from "node:crypto";
|
|
|
19650
19726
|
import { constants as constants14 } from "node:fs";
|
|
19651
19727
|
import { mkdir as mkdir13, open as open19, realpath as realpath34, rename as rename13, symlink as symlink8 } from "node:fs/promises";
|
|
19652
19728
|
import { homedir as homedir16 } from "node:os";
|
|
19653
|
-
import { basename as
|
|
19729
|
+
import { basename as basename14, dirname as dirname29, join as join46, parse as parse6, resolve as resolve27 } from "node:path";
|
|
19654
19730
|
import { isDeepStrictEqual as isDeepStrictEqual12 } from "node:util";
|
|
19655
19731
|
import { valid as valid3 } from "semver";
|
|
19656
19732
|
var binding5 = { namespace: "migrations", targetParts: [".agents", "root-adoption"] };
|
|
@@ -19850,7 +19926,7 @@ async function guard2(context2, journal) {
|
|
|
19850
19926
|
function paths2(snapshot3, id) {
|
|
19851
19927
|
const prefix2 = join46(
|
|
19852
19928
|
dirname29(snapshot3.path),
|
|
19853
|
-
`${
|
|
19929
|
+
`${basename14(snapshot3.path, ".json")}.root-cutover-${id}`
|
|
19854
19930
|
);
|
|
19855
19931
|
return { archive: `${prefix2}-old`, stage: `${prefix2}-new` };
|
|
19856
19932
|
}
|
|
@@ -19962,8 +20038,8 @@ function journalData(snapshot3, context2) {
|
|
|
19962
20038
|
)))
|
|
19963
20039
|
refuse7(snapshot3.path, "The staged root does not match its canonical inventory.");
|
|
19964
20040
|
for (const stage2 of raw.preservedStages) {
|
|
19965
|
-
const prefix2 = `${
|
|
19966
|
-
if (typeof stage2 !== "string" || dirname29(stage2) !== dirname29(snapshot3.path) || !
|
|
20041
|
+
const prefix2 = `${basename14(snapshot3.path, ".json")}.root-cutover-`;
|
|
20042
|
+
if (typeof stage2 !== "string" || dirname29(stage2) !== dirname29(snapshot3.path) || !basename14(stage2).startsWith(prefix2) || !uuid.test(basename14(stage2).slice(prefix2.length, -4)) || !stage2.endsWith("-new"))
|
|
19967
20043
|
refuse7(snapshot3.path, "A preserved stage has an invalid quarantine path.");
|
|
19968
20044
|
}
|
|
19969
20045
|
const data2 = raw;
|
|
@@ -20004,7 +20080,7 @@ async function ownerFor2(context2, allowed) {
|
|
|
20004
20080
|
]) {
|
|
20005
20081
|
if (allowed && (path === context2.root || dirname29(path) === context2.root)) {
|
|
20006
20082
|
const candidates = allowed.map(
|
|
20007
|
-
(node) => path === context2.root ? node : node.children[
|
|
20083
|
+
(node) => path === context2.root ? node : node.children[basename14(path)]
|
|
20008
20084
|
);
|
|
20009
20085
|
if (!candidates.some(
|
|
20010
20086
|
(node) => node && ["link", "directory"].includes(node.identity.kind) && isDeepStrictEqual12(nodeIdentity(node), expected)
|
|
@@ -20667,7 +20743,7 @@ async function adoptRoot(options = {}) {
|
|
|
20667
20743
|
}
|
|
20668
20744
|
|
|
20669
20745
|
// src/core/sets.ts
|
|
20670
|
-
import { readdir as
|
|
20746
|
+
import { readdir as readdir31 } from "node:fs/promises";
|
|
20671
20747
|
import { join as join47 } from "node:path";
|
|
20672
20748
|
function validateName(name) {
|
|
20673
20749
|
parseManifest({ sets: [{ name }] }, "set name");
|
|
@@ -20690,7 +20766,7 @@ async function listSets(options = {}) {
|
|
|
20690
20766
|
const failures = [];
|
|
20691
20767
|
if (await inspectPath(path)) {
|
|
20692
20768
|
await requireDirectory(path, "E_SET_MISSING");
|
|
20693
|
-
for (const entry3 of (await
|
|
20769
|
+
for (const entry3 of (await readdir31(path, { withFileTypes: true })).sort(
|
|
20694
20770
|
(a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0
|
|
20695
20771
|
)) {
|
|
20696
20772
|
if (entry3.name.startsWith(".") || entry3.name.startsWith("_") || !entry3.isDirectory() && !entry3.isSymbolicLink())
|
|
@@ -20832,7 +20908,7 @@ async function removeSetSkills(name, names2, options = {}) {
|
|
|
20832
20908
|
}
|
|
20833
20909
|
|
|
20834
20910
|
// src/core/vendor-inspect.ts
|
|
20835
|
-
import { readdir as
|
|
20911
|
+
import { readdir as readdir32 } from "node:fs/promises";
|
|
20836
20912
|
import { join as join48 } from "node:path";
|
|
20837
20913
|
|
|
20838
20914
|
// src/core/vendor-git.ts
|
|
@@ -21124,8 +21200,8 @@ async function readVendorGitSource(source, checkoutRoot, options = {}) {
|
|
|
21124
21200
|
checkout
|
|
21125
21201
|
).trim();
|
|
21126
21202
|
const base = await treeAt(checkout, rootTree, source.subdir, options);
|
|
21127
|
-
const
|
|
21128
|
-
const declarations = source.membership === "explicit" ? source.skills :
|
|
21203
|
+
const children2 = await treeEntries(checkout, base, options);
|
|
21204
|
+
const declarations = source.membership === "explicit" ? source.skills : children2.filter(
|
|
21129
21205
|
(entry3) => !entry3.name.startsWith(".") && !entry3.name.startsWith("_") && (entry3.type === "tree" || entry3.mode === "120000" || entry3.mode === "160000")
|
|
21130
21206
|
).map((entry3) => ({ name: entry3.name, dir: entry3.name }));
|
|
21131
21207
|
const selected = declarations.filter(
|
|
@@ -21197,7 +21273,7 @@ async function recordedInventory(manifest, observation, options) {
|
|
|
21197
21273
|
const recorded = /* @__PURE__ */ new Map();
|
|
21198
21274
|
const failed2 = /* @__PURE__ */ new Set();
|
|
21199
21275
|
const catalog = join48(manifest.registry.root, "all-skills");
|
|
21200
|
-
for (const entry3 of (await
|
|
21276
|
+
for (const entry3 of (await readdir32(catalog, { withFileTypes: true })).sort(
|
|
21201
21277
|
(a, b) => a.name.localeCompare(b.name)
|
|
21202
21278
|
)) {
|
|
21203
21279
|
checkVendorSignal(options);
|
|
@@ -21670,7 +21746,7 @@ async function inspectVendorStatus(options = {}) {
|
|
|
21670
21746
|
|
|
21671
21747
|
// src/core/vendor-sync.ts
|
|
21672
21748
|
import { randomUUID as randomUUID14 } from "node:crypto";
|
|
21673
|
-
import { chmod as chmod4, lstat as lstat27, mkdir as mkdir14, open as open20, readdir as
|
|
21749
|
+
import { chmod as chmod4, lstat as lstat27, mkdir as mkdir14, open as open20, readdir as readdir33, rename as rename14 } from "node:fs/promises";
|
|
21674
21750
|
import { dirname as dirname30, join as join49 } from "node:path";
|
|
21675
21751
|
function refuse8(code, message, path, fix) {
|
|
21676
21752
|
fail(code, message, { path, fix }, ExitCode.REFUSED);
|
|
@@ -21897,7 +21973,7 @@ async function prepare6(options, extractedAt) {
|
|
|
21897
21973
|
}
|
|
21898
21974
|
}
|
|
21899
21975
|
if (options.prune) {
|
|
21900
|
-
for (const name of (await
|
|
21976
|
+
for (const name of (await readdir33(catalog)).filter(isSkillName).sort()) {
|
|
21901
21977
|
if (names2.has(name)) continue;
|
|
21902
21978
|
const path = join49(catalog, name);
|
|
21903
21979
|
if (!(await vendorLstat(path))?.isDirectory()) continue;
|