@hybridlabor-api/aos 4.4.2-beta.0 → 4.4.2-beta.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/CLAUDE.md +52 -0
- package/installer.js +99 -0
- package/package.json +1 -1
package/CLAUDE.md
CHANGED
|
@@ -616,6 +616,58 @@ must not do.
|
|
|
616
616
|
|
|
617
617
|
## Headless timeouts
|
|
618
618
|
|
|
619
|
+
A trivial headless `agy` prompt was measured at **605s** in 2026-09.
|
|
620
|
+
`agy-delegate` defaults to `--print-timeout 5m`, so it aborts at 300s and
|
|
621
|
+
reports an empty body while the answer is still arriving. Pass `--timeout 15m`
|
|
622
|
+
for anything non-trivial. A short timeout does not read as "slow", it reads as
|
|
623
|
+
"broken".
|
|
624
|
+
|
|
625
|
+
# AOS — Antigravity / Gemini
|
|
626
|
+
|
|
627
|
+
**Read [AGENTS.md](AGENTS.md) first.** It holds every rule that applies to all
|
|
628
|
+
harnesses: the non-negotiables, the release gate, Conventional Commits, the
|
|
629
|
+
skill contract and category routing, the pipeline variants, and the delegation
|
|
630
|
+
policy. Nothing from it is repeated here — a rule that lives in two files is a
|
|
631
|
+
rule that will eventually disagree with itself.
|
|
632
|
+
|
|
633
|
+
This file covers only what is specific to running AOS under Antigravity.
|
|
634
|
+
|
|
635
|
+
## Nothing enforces the gate here — you are the enforcement
|
|
636
|
+
|
|
637
|
+
`.claude/hooks/go-gate.mjs` is a Claude Code hook and does not run on this
|
|
638
|
+
harness. Not one of the four release commands is mechanically blocked for you,
|
|
639
|
+
and neither is anything else.
|
|
640
|
+
|
|
641
|
+
So the full rule in AGENTS.md applies here in its entirety, not just its
|
|
642
|
+
hook-enforced subset: when the user asks for a plan, review, audit or
|
|
643
|
+
multi-step action, you are read-only until they answer with the literal **GO**
|
|
644
|
+
— including file writes and `git commit`. On Claude Code a hook would catch the
|
|
645
|
+
four worst cases if discipline failed. Here there is no backstop, which makes
|
|
646
|
+
this the harness where the rule matters most, not least.
|
|
647
|
+
|
|
648
|
+
## Model routing
|
|
649
|
+
|
|
650
|
+
The tier names in `agy-delegate` map to models that go stale — the built-in
|
|
651
|
+
`flash` still points at Gemini 3.7 while 3.8 ships. Re-check against
|
|
652
|
+
`agy models` after every upgrade; the id carries both the version and the
|
|
653
|
+
effort suffix.
|
|
654
|
+
|
|
655
|
+
| Work | Model |
|
|
656
|
+
|---|---|
|
|
657
|
+
| Media, fast or mechanical coding, boilerplate | `Gemini 3.8 Flash (Medium)` |
|
|
658
|
+
| Trivial one-liners | `Gemini 3.8 Flash (Low)` |
|
|
659
|
+
| Review, architecture, hard reasoning | `Claude Sonnet 4.6 (Thinking)` |
|
|
660
|
+
|
|
661
|
+
Set these once via `CLAUDE_PLUGIN_OPTION_TIER_{FLASH,FLASH_LO,PRO}` in
|
|
662
|
+
`~/.zshenv` — **not** `~/.zshrc`, which non-interactive tool shells never
|
|
663
|
+
source.
|
|
664
|
+
|
|
665
|
+
Adversarial review is the case that most repays the stronger model: a Flash
|
|
666
|
+
tier tends to agree with what it is shown, which is the one thing a reviewer
|
|
667
|
+
must not do.
|
|
668
|
+
|
|
669
|
+
## Headless timeouts
|
|
670
|
+
|
|
619
671
|
A trivial headless `agy` prompt was measured at **605s** in 2026-09.
|
|
620
672
|
`agy-delegate` defaults to `--print-timeout 5m`, so it aborts at 300s and
|
|
621
673
|
reports an empty body while the answer is still arriving. Pass `--timeout 15m`
|
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
|
|
@@ -3579,12 +3662,14 @@ async function main() {
|
|
|
3579
3662
|
{ value: 'quick', label: `⚡ Quick Update (v${installState.localVersion} ➔ v${installState.currentVersion})`, hint: 'refresh skills, templates & daemons' },
|
|
3580
3663
|
{ value: 'project', label: '📁 Drop Local Project Harness', hint: 'copy dispatcher contract to cwd' },
|
|
3581
3664
|
{ value: 'reconfigure', label: '🛠️ Reconfigure System', hint: 'change targets, tier or options' },
|
|
3665
|
+
{ value: 'uninstall', label: '🗑️ Uninstall AOS', hint: 'remove what this installer placed; your data stays' },
|
|
3582
3666
|
{ value: 'cancel', label: '❌ Exit' }
|
|
3583
3667
|
]
|
|
3584
3668
|
: [
|
|
3585
3669
|
{ value: 'project', label: '📁 Drop Local Project Harness', hint: 'copy dispatcher contract to cwd' },
|
|
3586
3670
|
{ value: 'quick', label: '🔄 Verify & Refresh All Skills', hint: 're-sync and health check' },
|
|
3587
3671
|
{ value: 'reconfigure', label: '🛠️ Reconfigure System', hint: 'switch tier or targets' },
|
|
3672
|
+
{ value: 'uninstall', label: '🗑️ Uninstall AOS', hint: 'remove what this installer placed; your data stays' },
|
|
3588
3673
|
{ value: 'cancel', label: '❌ Exit' }
|
|
3589
3674
|
];
|
|
3590
3675
|
|
|
@@ -3608,6 +3693,19 @@ async function main() {
|
|
|
3608
3693
|
outro('Quick Update complete.');
|
|
3609
3694
|
return;
|
|
3610
3695
|
}
|
|
3696
|
+
if (action === 'uninstall') {
|
|
3697
|
+
// aos-uninstall.mjs is its own script, not a function of this file --
|
|
3698
|
+
// it is ESM (installer.js is CommonJS) and drives its own readline
|
|
3699
|
+
// confirmation prompt, so it runs as a real child process with
|
|
3700
|
+
// inherited stdio rather than being imported in-process.
|
|
3701
|
+
const uninstallScript = path.join(srcDir, 'bin', 'aos-uninstall.mjs');
|
|
3702
|
+
if (!fs.existsSync(uninstallScript)) {
|
|
3703
|
+
log.error(`Uninstaller not found at ${uninstallScript} -- run it directly: npx @hybridlabor-api/aos-uninstall`);
|
|
3704
|
+
return;
|
|
3705
|
+
}
|
|
3706
|
+
spawnSync('node', [uninstallScript], { stdio: 'inherit' });
|
|
3707
|
+
return;
|
|
3708
|
+
}
|
|
3611
3709
|
}
|
|
3612
3710
|
|
|
3613
3711
|
const detectedNames = detections.map(d => d.name).join(', ');
|
|
@@ -3868,6 +3966,7 @@ async function main() {
|
|
|
3868
3966
|
}
|
|
3869
3967
|
|
|
3870
3968
|
syncSkillsToGlobalHarnesses(excludeSkills);
|
|
3969
|
+
pruneRemovedSkills(_sessionManifest);
|
|
3871
3970
|
s.stop('Skills installed.');
|
|
3872
3971
|
|
|
3873
3972
|
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.2",
|
|
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": {
|