@hybridlabor-api/aos 4.4.2-beta.0 → 4.4.2-beta.1
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/installer.js +84 -0
- package/package.json +1 -1
package/installer.js
CHANGED
|
@@ -608,6 +608,88 @@ function initSessionManifest(existingManifest, sourceDirs) {
|
|
|
608
608
|
_sessionHashes = buildKnownSourceHashes(sourceDirs);
|
|
609
609
|
}
|
|
610
610
|
|
|
611
|
+
// Skills that left the package in 4.4.2 (Plan 02: migrated to the private
|
|
612
|
+
// aos-internal repo, per ~/dev/_plans/aos-2026-09-14/), by their flattened
|
|
613
|
+
// directory name at a sync destination.
|
|
614
|
+
//
|
|
615
|
+
// This is deliberately a fixed list, not a diff against what the current
|
|
616
|
+
// payload ships. A generic "anything on disk that is not in skills/ right
|
|
617
|
+
// now" pass was tried first and swept up two unrelated things: skill folders
|
|
618
|
+
// that MCP servers bundle inside their own package tree (e.g.
|
|
619
|
+
// mcps/tdmcp/.agents/skills/...), which happen to share the literal path
|
|
620
|
+
// segment "skills" but belong to a different install entirely; and skills
|
|
621
|
+
// under skills/workspace_agents/, which syncSkillsToGlobalHarnesses already
|
|
622
|
+
// deliberately excludes from the six global destinations, so a stray global
|
|
623
|
+
// copy of one says nothing about whether it is safe to delete. Both are real
|
|
624
|
+
// cleanup opportunities, but they are a separate investigation, not a side
|
|
625
|
+
// effect of this migration's beta test.
|
|
626
|
+
const SKILLS_REMOVED_IN_4_4_2 = new Set([
|
|
627
|
+
'bdbsaastraining', 'bdb-dev-os-skill', 'bdbsaashost', 'bdb-ecosystem-health', 'bdbsaas-ops',
|
|
628
|
+
]);
|
|
629
|
+
|
|
630
|
+
// The exact roots syncSkillsToGlobalHarnesses and the Gemini/Antigravity
|
|
631
|
+
// config-skills path write into. Pruning only touches a manifest entry whose
|
|
632
|
+
// path starts under one of these -- never one that merely contains a
|
|
633
|
+
// "skills" segment somewhere deeper, which is what let the MCP-bundle and
|
|
634
|
+
// workspace_agents cases above leak in during testing.
|
|
635
|
+
function globalSkillDestRoots() {
|
|
636
|
+
return [
|
|
637
|
+
path.join(homeDir, '.agents', 'skills'),
|
|
638
|
+
path.join(homeDir, '.claude', 'skills'),
|
|
639
|
+
path.join(homeDir, '.codex', 'skills'),
|
|
640
|
+
path.join(homeDir, '.cursor', 'skills'),
|
|
641
|
+
path.join(homeDir, '.roo', 'skills'),
|
|
642
|
+
path.join(geminiDir, 'config', 'skills'),
|
|
643
|
+
];
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
// syncSkillsToGlobalHarnesses (and its sibling copy loops) only ever add or
|
|
647
|
+
// update -- nothing in that path ever deletes a skill that the current
|
|
648
|
+
// payload no longer ships. That is fine for new skills and updated ones, but
|
|
649
|
+
// it means a skill removed from a release stays on every user's disk
|
|
650
|
+
// forever, through every future update, because nothing after the removal
|
|
651
|
+
// ever looks at what is on disk that no longer has a source. This walks the
|
|
652
|
+
// install manifest -- which already has one entry per file this installer
|
|
653
|
+
// has ever placed -- for the specific skills 4.4.2 removed, under the six
|
|
654
|
+
// known global skill roots, and deletes them. A user-modified file is backed
|
|
655
|
+
// up first, the same way resolveFileConflict backs up a user edit it is
|
|
656
|
+
// about to overwrite, rather than silently deleting local changes.
|
|
657
|
+
function pruneRemovedSkills(manifest) {
|
|
658
|
+
if (!manifest) return;
|
|
659
|
+
const roots = globalSkillDestRoots();
|
|
660
|
+
|
|
661
|
+
const staleDirs = new Set();
|
|
662
|
+
let removedFiles = 0;
|
|
663
|
+
for (const targetPath of Object.keys(manifest)) {
|
|
664
|
+
const root = roots.find((r) => targetPath.startsWith(r + path.sep));
|
|
665
|
+
if (!root) continue;
|
|
666
|
+
const skillDirName = targetPath.slice(root.length + 1).split(path.sep)[0];
|
|
667
|
+
if (!SKILLS_REMOVED_IN_4_4_2.has(skillDirName)) continue;
|
|
668
|
+
|
|
669
|
+
if (fs.existsSync(targetPath)) {
|
|
670
|
+
const diskHash = computeFileHash(targetPath);
|
|
671
|
+
const manifestEntry = manifest[targetPath];
|
|
672
|
+
if (diskHash !== null && manifestEntry && diskHash !== manifestEntry.sha256) {
|
|
673
|
+
const bakPath = `${targetPath}.${timestamp}.bak`;
|
|
674
|
+
try { fs.copyFileSync(targetPath, bakPath); } catch (e) { logDebug(e, 'prune-removed-skill backup'); }
|
|
675
|
+
log.warn(`[manifest] Retired skill left a user-edited file, backed up to ${bakPath} instead of deleting it.`);
|
|
676
|
+
} else {
|
|
677
|
+
try { fs.unlinkSync(targetPath); removedFiles++; } catch (e) { logDebug(e, 'prune-removed-skill unlink'); }
|
|
678
|
+
}
|
|
679
|
+
staleDirs.add(path.join(root, skillDirName));
|
|
680
|
+
}
|
|
681
|
+
delete manifest[targetPath];
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
for (const dir of staleDirs) {
|
|
685
|
+
try { fs.rmSync(dir, { recursive: true, force: true }); } catch (e) { logDebug(e, 'prune-removed-skill rmdir'); }
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
if (staleDirs.size > 0) {
|
|
689
|
+
log.step(`Removed ${removedFiles} file(s) from ${staleDirs.size} retired skill install(s) no longer shipped.`);
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
|
|
611
693
|
function flushSessionManifest() {
|
|
612
694
|
if (_sessionManifest) saveInstallManifest(_sessionManifest);
|
|
613
695
|
}
|
|
@@ -3464,6 +3546,7 @@ async function runQuickUpdate(installState) {
|
|
|
3464
3546
|
}
|
|
3465
3547
|
}
|
|
3466
3548
|
syncSkillsToGlobalHarnesses(excludeSkills);
|
|
3549
|
+
pruneRemovedSkills(_sessionManifest);
|
|
3467
3550
|
s.stop('Skills refreshed');
|
|
3468
3551
|
|
|
3469
3552
|
// Everything injectHarnessRules() delivers -- GEMINI.md, the dispatcher
|
|
@@ -3868,6 +3951,7 @@ async function main() {
|
|
|
3868
3951
|
}
|
|
3869
3952
|
|
|
3870
3953
|
syncSkillsToGlobalHarnesses(excludeSkills);
|
|
3954
|
+
pruneRemovedSkills(_sessionManifest);
|
|
3871
3955
|
s.stop('Skills installed.');
|
|
3872
3956
|
|
|
3873
3957
|
injectHarnessRules();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hybridlabor-api/aos",
|
|
3
|
-
"version": "4.4.2-beta.
|
|
3
|
+
"version": "4.4.2-beta.1",
|
|
4
4
|
"description": "AOS — A Curated AI AGENT OS. Optimized agent skills and add-ons like memB, OpenWiki, Heimdall Token Saver, and Godmode architectures.",
|
|
5
5
|
"main": "installer.js",
|
|
6
6
|
"bin": {
|