moluoxixi-ai-rules 0.2.1 → 0.2.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/scripts/lib/tool.js
CHANGED
|
@@ -4,7 +4,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
4
4
|
import { HOST_IDS, resolveHostId } from '../../constants/hosts.js';
|
|
5
5
|
import { ensureGlobalSkillLink, ensureInstallRoot, getDefaultInstallPaths, projectHostById, runSkillSetupCommands, } from './install.js';
|
|
6
6
|
import { resolveRoleManifestPath } from './roles.js';
|
|
7
|
-
import { rebuildVendorAssets } from './vendor-staging.js';
|
|
7
|
+
import { cleanupEmptyVendorSkillDirectories, rebuildVendorAssets } from './vendor-staging.js';
|
|
8
8
|
import { ensureVendorRepo, verifyVendorRepoRevision } from './vendor-sync.js';
|
|
9
9
|
import { loadVendorManifest } from './vendors.js';
|
|
10
10
|
import { verifyGlobalAgentSkills, verifyHost } from './verify.js';
|
|
@@ -105,6 +105,7 @@ export async function syncToHosts(options) {
|
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
|
+
cleanupEmptyVendorSkillDirectories(paths.moluoHome);
|
|
108
109
|
if (failedHosts.length > 0) {
|
|
109
110
|
throw new Error(`Host verification failed: ${failedHosts.join(', ')}`);
|
|
110
111
|
}
|
|
@@ -8,4 +8,5 @@ export interface RebuildVendorAssetsOptions {
|
|
|
8
8
|
role: string;
|
|
9
9
|
manifestPath: string;
|
|
10
10
|
}
|
|
11
|
+
export declare function cleanupEmptyVendorSkillDirectories(homeDir: string): void;
|
|
11
12
|
export declare function rebuildVendorAssets(options: RebuildVendorAssetsOptions): Promise<VendorAssetInventory>;
|
|
@@ -412,38 +412,43 @@ function rollbackManagedEntries(entries) {
|
|
|
412
412
|
}
|
|
413
413
|
return rollbackErrors;
|
|
414
414
|
}
|
|
415
|
-
function managedChildNames(currentRoot, nextRoot) {
|
|
415
|
+
function managedChildNames(currentRoot, nextRoot, label) {
|
|
416
416
|
const names = new Map();
|
|
417
417
|
for (const root of [currentRoot, nextRoot]) {
|
|
418
418
|
if (!fs.existsSync(root))
|
|
419
419
|
continue;
|
|
420
|
-
requirePlainDirectoryOrMissing(root,
|
|
420
|
+
requirePlainDirectoryOrMissing(root, label);
|
|
421
421
|
for (const entry of fs.readdirSync(root, { withFileTypes: true })) {
|
|
422
422
|
if (!entry.isDirectory() && !entry.isFile())
|
|
423
|
-
throw new Error(
|
|
423
|
+
throw new Error(`${label} has unsupported filesystem type: ${path.join(root, entry.name)}`);
|
|
424
424
|
const key = entry.name.toLowerCase();
|
|
425
425
|
const previous = names.get(key);
|
|
426
426
|
if (previous !== undefined && previous !== entry.name)
|
|
427
|
-
throw new Error(
|
|
427
|
+
throw new Error(`${label} names differ only by case: ${previous}, ${entry.name}`);
|
|
428
428
|
names.set(key, entry.name);
|
|
429
429
|
}
|
|
430
430
|
}
|
|
431
431
|
return [...names.values()].sort(compareStable);
|
|
432
432
|
}
|
|
433
|
-
function
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
return;
|
|
440
|
-
fs.mkdirSync(spec.current, { recursive: true });
|
|
441
|
-
createdRoots.push(spec.current);
|
|
442
|
-
}
|
|
433
|
+
function isPlainDirectory(target) {
|
|
434
|
+
const stats = fs.lstatSync(target, { throwIfNoEntry: false });
|
|
435
|
+
return stats !== undefined && stats.isDirectory() && !stats.isSymbolicLink();
|
|
436
|
+
}
|
|
437
|
+
function commitDirectoryContents(currentRoot, nextRoot, backupRoot, committedEntries, emptiedRoots) {
|
|
438
|
+
const childNames = managedChildNames(currentRoot, nextRoot, 'Managed vendor skill directory');
|
|
443
439
|
for (const name of childNames) {
|
|
440
|
+
const currentChild = path.join(currentRoot, name);
|
|
441
|
+
const nextChild = path.join(nextRoot, name);
|
|
442
|
+
const hasNextChild = fs.existsSync(nextChild);
|
|
443
|
+
if (isPlainDirectory(currentChild) && (!hasNextChild || isPlainDirectory(nextChild))) {
|
|
444
|
+
commitDirectoryContents(currentChild, nextChild, path.join(backupRoot, name), committedEntries, emptiedRoots);
|
|
445
|
+
if (!hasNextChild)
|
|
446
|
+
emptiedRoots.push(currentChild);
|
|
447
|
+
continue;
|
|
448
|
+
}
|
|
444
449
|
const entry = {
|
|
445
|
-
current:
|
|
446
|
-
backup: path.join(
|
|
450
|
+
current: currentChild,
|
|
451
|
+
backup: path.join(backupRoot, name),
|
|
447
452
|
movedCurrent: false,
|
|
448
453
|
installedNext: false,
|
|
449
454
|
};
|
|
@@ -453,13 +458,25 @@ function commitManagedChildren(spec, committedEntries, createdRoots) {
|
|
|
453
458
|
fs.renameSync(entry.current, entry.backup);
|
|
454
459
|
entry.movedCurrent = true;
|
|
455
460
|
}
|
|
456
|
-
const nextChild = path.join(spec.next, name);
|
|
457
461
|
if (fs.existsSync(nextChild)) {
|
|
458
462
|
fs.renameSync(nextChild, entry.current);
|
|
459
463
|
entry.installedNext = true;
|
|
460
464
|
}
|
|
461
465
|
}
|
|
462
466
|
}
|
|
467
|
+
function commitManagedChildren(spec, committedEntries, createdRoots, emptiedRoots) {
|
|
468
|
+
requirePlainDirectoryOrMissing(spec.current, 'Managed vendor skills root');
|
|
469
|
+
requirePlainDirectoryOrMissing(spec.next, 'Staged vendor skills root');
|
|
470
|
+
const childNames = managedChildNames(spec.current, spec.next, 'Managed vendor skill');
|
|
471
|
+
if (!fs.existsSync(spec.current)) {
|
|
472
|
+
if (!fs.existsSync(spec.next))
|
|
473
|
+
return;
|
|
474
|
+
fs.mkdirSync(spec.current, { recursive: true });
|
|
475
|
+
createdRoots.push(spec.current);
|
|
476
|
+
}
|
|
477
|
+
if (childNames.length > 0)
|
|
478
|
+
commitDirectoryContents(spec.current, spec.next, spec.backup, committedEntries, emptiedRoots);
|
|
479
|
+
}
|
|
463
480
|
async function commitManagedEntries(stagingRoot, roleStagingRoot, homeDir, role) {
|
|
464
481
|
const resolvedHome = path.resolve(homeDir);
|
|
465
482
|
const vendorRoot = path.join(resolvedHome, 'vendor');
|
|
@@ -478,6 +495,7 @@ async function commitManagedEntries(stagingRoot, roleStagingRoot, homeDir, role)
|
|
|
478
495
|
const backupRoot = fs.mkdtempSync(path.join(resolvedHome, '.airules-vendor-backup-'));
|
|
479
496
|
const committedEntries = [];
|
|
480
497
|
const createdRoots = [];
|
|
498
|
+
const emptiedRoots = [];
|
|
481
499
|
try {
|
|
482
500
|
fs.mkdirSync(nextRoot);
|
|
483
501
|
fs.cpSync(stagingRoot, nextRoot, { recursive: true, dereference: true });
|
|
@@ -499,7 +517,7 @@ async function commitManagedEntries(stagingRoot, roleStagingRoot, homeDir, role)
|
|
|
499
517
|
}
|
|
500
518
|
for (const spec of specs) {
|
|
501
519
|
if (spec.preserveRoot) {
|
|
502
|
-
commitManagedChildren(spec, committedEntries, createdRoots);
|
|
520
|
+
commitManagedChildren(spec, committedEntries, createdRoots, emptiedRoots);
|
|
503
521
|
continue;
|
|
504
522
|
}
|
|
505
523
|
const entry = {
|
|
@@ -538,9 +556,36 @@ async function commitManagedEntries(stagingRoot, roleStagingRoot, homeDir, role)
|
|
|
538
556
|
removeBestEffort(backupRoot);
|
|
539
557
|
throw new Error(`Role and vendor staging commit failed; previous managed assets restored: ${String(error)}`, { cause: error });
|
|
540
558
|
}
|
|
559
|
+
for (const root of emptiedRoots)
|
|
560
|
+
removeEmptyDirectoryBestEffort(root);
|
|
541
561
|
removeBestEffort(nextWorkspace);
|
|
542
562
|
removeBestEffort(backupRoot);
|
|
543
563
|
}
|
|
564
|
+
function removeEmptyDirectoryBestEffort(target) {
|
|
565
|
+
try {
|
|
566
|
+
fs.rmdirSync(target);
|
|
567
|
+
}
|
|
568
|
+
catch {
|
|
569
|
+
// Host junctions can keep an empty skill directory locked until projection finishes.
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
function cleanupEmptyDirectoryTree(root) {
|
|
573
|
+
for (const entry of fs.readdirSync(root, { withFileTypes: true })) {
|
|
574
|
+
if (entry.isDirectory())
|
|
575
|
+
cleanupEmptyDirectoryTree(path.join(root, entry.name));
|
|
576
|
+
}
|
|
577
|
+
removeEmptyDirectoryBestEffort(root);
|
|
578
|
+
}
|
|
579
|
+
export function cleanupEmptyVendorSkillDirectories(homeDir) {
|
|
580
|
+
const skillsRoot = path.resolve(homeDir, 'vendor', 'skills');
|
|
581
|
+
if (!fs.existsSync(skillsRoot))
|
|
582
|
+
return;
|
|
583
|
+
requirePlainDirectoryOrMissing(skillsRoot, 'Managed vendor skills root');
|
|
584
|
+
for (const entry of fs.readdirSync(skillsRoot, { withFileTypes: true })) {
|
|
585
|
+
if (entry.isDirectory())
|
|
586
|
+
cleanupEmptyDirectoryTree(path.join(skillsRoot, entry.name));
|
|
587
|
+
}
|
|
588
|
+
}
|
|
544
589
|
export async function rebuildVendorAssets(options) {
|
|
545
590
|
const role = requireRoleName(options.role);
|
|
546
591
|
const manifest = await loadVendorManifest(options.manifestPath);
|
package/package.json
CHANGED