@hybridlabor-api/aos 4.7.2 โ 4.9.0
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/.agents/agents.md +1 -1
- package/.agents/nodes.json +1 -1
- package/.agents/vendor-manifest.json +23 -1
- package/.claude/agents/godmode-media-eventtech.md +1 -1
- package/.claude/hooks/conventional-commits.mjs +125 -0
- package/.claude/hooks/env-file-protection.mjs +105 -0
- package/.claude/hooks/go-gate.mjs +101 -81
- package/.claude/settings.json +13 -0
- package/.opencode/agents/godmode-media-eventtech.md +1 -1
- package/.opencode/plugins/bdb-aos.js +31 -4
- package/README.de.md +1 -1
- package/README.md +1 -1
- package/README.pt.md +1 -1
- package/THIRD_PARTY_NOTICES.md +88 -0
- package/docs/skills_table.md +1 -1
- package/installer.js +309 -101
- package/package.json +6 -2
- package/packages/aos-cli/README.md +80 -0
- package/packages/aos-cli/bin/aos-cli.mjs +134 -0
- package/packages/aos-cli/core-skills.json +12 -0
- package/packages/aos-cli/extensions/aos.ts +321 -0
- package/packages/aos-cli/package-lock.json +1923 -0
- package/packages/aos-cli/package.json +29 -0
- package/packages/aos-cli/scripts/check-theme.mjs +63 -0
- package/packages/aos-cli/themes/aos.json +97 -0
- package/scripts/build-plugin-manifest.mjs +131 -0
- package/scripts/validate-skills.mjs +81 -6
- package/skills/basic/ao-orchestrator/SKILL.md +116 -0
- package/skills/global_config/agenttrail/SKILL.md +6 -1
- package/skills/global_config/ask-tim/SKILL.md +4 -4
- package/skills/global_config/bash-script-generator/SKILL.md +201 -0
- package/skills/global_config/bash-script-generator/assets/templates/standard-template.sh +96 -0
- package/skills/global_config/bash-script-generator/docs/bash-scripting-guide.md +729 -0
- package/skills/global_config/bash-script-generator/docs/generation-best-practices.md +193 -0
- package/skills/global_config/bash-script-generator/docs/script-patterns.md +566 -0
- package/skills/global_config/bash-script-generator/docs/text-processing-guide.md +437 -0
- package/skills/global_config/bash-script-generator/examples/log-analyzer.sh +92 -0
- package/skills/global_config/bash-script-generator/scripts/generate_script_template.sh +123 -0
- package/skills/global_config/bash-script-generator/scripts/run_ci_checks.sh +172 -0
- package/skills/global_config/bash-script-generator/scripts/test_generator.sh +413 -0
- package/skills/global_config/bash-script-validator/SKILL.md +249 -0
- package/skills/global_config/bash-script-validator/docs/awk-reference.md +449 -0
- package/skills/global_config/bash-script-validator/docs/bash-reference.md +468 -0
- package/skills/global_config/bash-script-validator/docs/common-mistakes.md +623 -0
- package/skills/global_config/bash-script-validator/docs/grep-reference.md +395 -0
- package/skills/global_config/bash-script-validator/docs/regex-reference.md +391 -0
- package/skills/global_config/bash-script-validator/docs/sed-reference.md +454 -0
- package/skills/global_config/bash-script-validator/docs/shell-reference.md +463 -0
- package/skills/global_config/bash-script-validator/docs/shellcheck-reference.md +399 -0
- package/skills/global_config/bash-script-validator/examples/bad-bash.sh +55 -0
- package/skills/global_config/bash-script-validator/examples/bad-shell.sh +54 -0
- package/skills/global_config/bash-script-validator/examples/good-bash.sh +71 -0
- package/skills/global_config/bash-script-validator/examples/good-shell.sh +69 -0
- package/skills/global_config/bash-script-validator/scripts/run_ci_checks.sh +23 -0
- package/skills/global_config/bash-script-validator/scripts/shellcheck_wrapper.sh +174 -0
- package/skills/global_config/bash-script-validator/scripts/test_validate.sh +446 -0
- package/skills/global_config/bash-script-validator/scripts/validate.sh +512 -0
- package/skills/global_config/ci-pipeline/SKILL.md +135 -0
- package/skills/global_config/dispatching-parallel-agents/SKILL.md +170 -0
- package/skills/global_config/dockerfile-generator/SKILL.md +1038 -0
- package/skills/global_config/dockerfile-generator/examples/example.dockerignore +95 -0
- package/skills/global_config/dockerfile-generator/examples/golang-distroless.Dockerfile +34 -0
- package/skills/global_config/dockerfile-generator/examples/java-springboot.Dockerfile +45 -0
- package/skills/global_config/dockerfile-generator/examples/nextjs-production.Dockerfile +49 -0
- package/skills/global_config/dockerfile-generator/examples/nodejs-multistage.Dockerfile +55 -0
- package/skills/global_config/dockerfile-generator/examples/python-fastapi.Dockerfile +48 -0
- package/skills/global_config/dockerfile-generator/references/language_specific_guides.md +510 -0
- package/skills/global_config/dockerfile-generator/references/multistage_builds.md +570 -0
- package/skills/global_config/dockerfile-generator/references/optimization_patterns.md +492 -0
- package/skills/global_config/dockerfile-generator/references/security_best_practices.md +375 -0
- package/skills/global_config/dockerfile-generator/scripts/generate_dockerignore.sh +199 -0
- package/skills/global_config/dockerfile-generator/scripts/generate_golang.sh +172 -0
- package/skills/global_config/dockerfile-generator/scripts/generate_java.sh +185 -0
- package/skills/global_config/dockerfile-generator/scripts/generate_nodejs.sh +279 -0
- package/skills/global_config/dockerfile-generator/scripts/generate_python.sh +218 -0
- package/skills/global_config/dockerfile-generator/scripts/test_generator.sh +210 -0
- package/skills/global_config/dockerfile-validator/SKILL.md +300 -0
- package/skills/global_config/dockerfile-validator/examples/.dockerignore.example +34 -0
- package/skills/global_config/dockerfile-validator/examples/bad-example.Dockerfile +37 -0
- package/skills/global_config/dockerfile-validator/examples/golang-distroless.Dockerfile +50 -0
- package/skills/global_config/dockerfile-validator/examples/good-example.Dockerfile +52 -0
- package/skills/global_config/dockerfile-validator/examples/python-optimized.Dockerfile +53 -0
- package/skills/global_config/dockerfile-validator/examples/security-issues.Dockerfile +42 -0
- package/skills/global_config/dockerfile-validator/references/docker_best_practices.md +348 -0
- package/skills/global_config/dockerfile-validator/references/optimization_guide.md +473 -0
- package/skills/global_config/dockerfile-validator/references/security_checklist.md +208 -0
- package/skills/global_config/dockerfile-validator/scripts/dockerfile-validate.sh +699 -0
- package/skills/global_config/dockerfile-validator/scripts/test_validate.sh +35 -0
- package/skills/global_config/dockerfile-validator/tests/fixtures/copy-before-yarn-lock-read.Dockerfile +6 -0
- package/skills/global_config/dockerfile-validator/tests/fixtures/copy-before-yarn.Dockerfile +6 -0
- package/skills/global_config/dockerfile-validator/tests/fixtures/from-platform-nonroot.Dockerfile +7 -0
- package/skills/global_config/dockerfile-validator/tests/test_regression.sh +164 -0
- package/skills/global_config/finishing-a-development-branch/SKILL.md +228 -0
- package/skills/global_config/github-actions-generator/SKILL.md +353 -0
- package/skills/global_config/github-actions-generator/assets/templates/action/composite/action.yml +82 -0
- package/skills/global_config/github-actions-generator/assets/templates/action/docker/Dockerfile +25 -0
- package/skills/global_config/github-actions-generator/assets/templates/action/docker/action.yml +42 -0
- package/skills/global_config/github-actions-generator/assets/templates/action/docker/entrypoint.sh +27 -0
- package/skills/global_config/github-actions-generator/assets/templates/action/javascript/action.yml +33 -0
- package/skills/global_config/github-actions-generator/assets/templates/action/javascript/index.js +50 -0
- package/skills/global_config/github-actions-generator/assets/templates/action/javascript/package.json +27 -0
- package/skills/global_config/github-actions-generator/assets/templates/workflow/basic_workflow.yml +242 -0
- package/skills/global_config/github-actions-generator/assets/templates/workflow/reusable_workflow.yml +106 -0
- package/skills/global_config/github-actions-generator/examples/README.md +147 -0
- package/skills/global_config/github-actions-generator/examples/actions/setup-node-cached/action.yml +93 -0
- package/skills/global_config/github-actions-generator/examples/caching/docker-buildkit.yml +256 -0
- package/skills/global_config/github-actions-generator/examples/security/dependency-review.yml +62 -0
- package/skills/global_config/github-actions-generator/examples/security/sbom-attestation.yml +119 -0
- package/skills/global_config/github-actions-generator/examples/triggers/chatops-commands.yml +475 -0
- package/skills/global_config/github-actions-generator/examples/triggers/repository-dispatch.yml +418 -0
- package/skills/global_config/github-actions-generator/examples/triggers/workflow-orchestration.yml +404 -0
- package/skills/global_config/github-actions-generator/examples/workflows/docker-build-push.yml +68 -0
- package/skills/global_config/github-actions-generator/examples/workflows/go-ci.yml +161 -0
- package/skills/global_config/github-actions-generator/examples/workflows/monorepo-ci.yml +340 -0
- package/skills/global_config/github-actions-generator/examples/workflows/multi-environment-deploy.yml +406 -0
- package/skills/global_config/github-actions-generator/examples/workflows/nodejs-ci.yml +122 -0
- package/skills/global_config/github-actions-generator/examples/workflows/python-ci.yml +157 -0
- package/skills/global_config/github-actions-generator/examples/workflows/scheduled-tasks.yml +376 -0
- package/skills/global_config/github-actions-generator/references/advanced-triggers.md +917 -0
- package/skills/global_config/github-actions-generator/references/best-practices.md +755 -0
- package/skills/global_config/github-actions-generator/references/common-actions.md +715 -0
- package/skills/global_config/github-actions-generator/references/custom-actions.md +320 -0
- package/skills/global_config/github-actions-generator/references/expressions-and-contexts.md +688 -0
- package/skills/global_config/github-actions-generator/references/modern-features.md +421 -0
- package/skills/global_config/github-actions-generator/scripts/test_generator.sh +344 -0
- package/skills/global_config/github-actions-templates/SKILL.md +7 -0
- package/skills/global_config/github-actions-validator/SKILL.md +576 -0
- package/skills/global_config/github-actions-validator/examples/README.md +88 -0
- package/skills/global_config/github-actions-validator/examples/outdated-versions.yml +76 -0
- package/skills/global_config/github-actions-validator/examples/valid-ci.yml +79 -0
- package/skills/global_config/github-actions-validator/examples/with-errors.yml +47 -0
- package/skills/global_config/github-actions-validator/references/act_usage.md +233 -0
- package/skills/global_config/github-actions-validator/references/action_versions.md +122 -0
- package/skills/global_config/github-actions-validator/references/actionlint_usage.md +343 -0
- package/skills/global_config/github-actions-validator/references/common_errors.md +512 -0
- package/skills/global_config/github-actions-validator/references/modern_features.md +384 -0
- package/skills/global_config/github-actions-validator/references/runners.md +317 -0
- package/skills/global_config/github-actions-validator/scripts/install_tools.sh +113 -0
- package/skills/global_config/github-actions-validator/scripts/validate_workflow.sh +910 -0
- package/skills/global_config/github-actions-validator/tests/test_validate_workflow.sh +237 -0
- package/skills/global_config/makefile-generator/SKILL.md +614 -0
- package/skills/global_config/makefile-generator/assets/templates/.gitkeep +1 -0
- package/skills/global_config/makefile-generator/docs/makefile-structure.md +530 -0
- package/skills/global_config/makefile-generator/docs/optimization-guide.md +784 -0
- package/skills/global_config/makefile-generator/docs/patterns-guide.md +642 -0
- package/skills/global_config/makefile-generator/docs/security-guide.md +361 -0
- package/skills/global_config/makefile-generator/docs/targets-guide.md +642 -0
- package/skills/global_config/makefile-generator/docs/variables-guide.md +596 -0
- package/skills/global_config/makefile-generator/scripts/add_standard_targets.sh +539 -0
- package/skills/global_config/makefile-generator/scripts/generate_makefile_template.sh +690 -0
- package/skills/global_config/makefile-generator/test/test_helper_scripts.sh +190 -0
- package/skills/global_config/makefile-validator/SKILL.md +244 -0
- package/skills/global_config/makefile-validator/docs/bake-tool.md +1000 -0
- package/skills/global_config/makefile-validator/docs/best-practices.md +858 -0
- package/skills/global_config/makefile-validator/docs/common-mistakes.md +944 -0
- package/skills/global_config/makefile-validator/examples/bad-makefile.mk +77 -0
- package/skills/global_config/makefile-validator/examples/good-makefile.mk +103 -0
- package/skills/global_config/makefile-validator/scripts/test_validate.sh +382 -0
- package/skills/global_config/makefile-validator/scripts/validate_makefile.sh +712 -0
- package/skills/global_config/{MCP_Manage โ mcp-manage}/SKILL.md +3 -3
- package/skills/global_config/requesting-code-review/SKILL.md +98 -0
- package/skills/global_config/requesting-code-review/code-reviewer.md +198 -0
- package/skills/global_config/using-git-worktrees/SKILL.md +170 -0
- package/skills/global_config/verification-before-completion/SKILL.md +123 -0
- package/skills/global_config/writing-plans/SKILL.md +126 -46
- package/skills/global_config/writing-plans-legacy/SKILL.md +139 -0
package/installer.js
CHANGED
|
@@ -115,8 +115,8 @@ if (mcpsArgRaw && mcpsArg === null) {
|
|
|
115
115
|
// not express that in a script or CI, and got Antigravity as their primary
|
|
116
116
|
// target instead. Values match the menu: 0 universal, 1 Antigravity,
|
|
117
117
|
// 2 Claude Desktop/Code, 3 Cursor, 4 custom, 5 Codex, 6 Windsurf, 7 Roo/Cline,
|
|
118
|
-
// 8 Aider (9 = project harness has its own --project-harness flag).
|
|
119
|
-
const VALID_PLATFORMS = ['0', '1', '2', '3', '4', '5', '6', '7', '8'];
|
|
118
|
+
// 8 Aider, 10 AOS CLI (9 = project harness has its own --project-harness flag).
|
|
119
|
+
const VALID_PLATFORMS = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '10'];
|
|
120
120
|
const platformsArgRaw = process.argv.find(a => a === '--platforms' || a.startsWith('--platforms='));
|
|
121
121
|
let PLATFORMS_ARG = null;
|
|
122
122
|
if (platformsArgRaw) {
|
|
@@ -1257,6 +1257,7 @@ function syncSkillsToGlobalHarnesses(excludeSkills = []) {
|
|
|
1257
1257
|
{ dir: path.join(homeDir, '.codex', 'skills'), key: 'codex' },
|
|
1258
1258
|
{ dir: path.join(homeDir, '.cursor', 'skills'), key: 'cursor' },
|
|
1259
1259
|
{ dir: path.join(homeDir, '.roo', 'skills'), key: 'vscode' },
|
|
1260
|
+
{ dir: process.platform === 'win32' ? path.join(process.env.APPDATA || homeDir, 'opencode', 'skills') : path.join(homeDir, '.config', 'opencode', 'skills'), key: 'opencode' },
|
|
1260
1261
|
].filter((d) => d.key === null || detectedKeys.has(d.key));
|
|
1261
1262
|
|
|
1262
1263
|
for (const { dir: dest } of extraSkillDestinations) {
|
|
@@ -1709,7 +1710,12 @@ function checkModuleUpdate(pkgName, targetDir) {
|
|
|
1709
1710
|
let remoteVer = null;
|
|
1710
1711
|
let checkFailed = false;
|
|
1711
1712
|
try {
|
|
1712
|
-
|
|
1713
|
+
const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
1714
|
+
if (process.platform === 'win32') {
|
|
1715
|
+
remoteVer = execSync(`"${npmCmd}" view ${pkgName} version`, { stdio: ['ignore', 'pipe', 'ignore'], encoding: 'utf8', timeout: 4000 }).trim();
|
|
1716
|
+
} else {
|
|
1717
|
+
remoteVer = execFileSync(npmCmd, ['view', pkgName, 'version'], { stdio: ['ignore', 'pipe', 'ignore'], encoding: 'utf8', timeout: 4000 }).trim();
|
|
1718
|
+
}
|
|
1713
1719
|
} catch (e) {
|
|
1714
1720
|
// Offline, a proxy, or a misconfigured registry. Swallowing this
|
|
1715
1721
|
// made every module report "up to date" forever on such a machine,
|
|
@@ -1804,15 +1810,40 @@ function downloadOrUpdateModule(pkgName, targetDir, displayName) {
|
|
|
1804
1810
|
}
|
|
1805
1811
|
}
|
|
1806
1812
|
|
|
1813
|
+
// Phase 1: retire the live tree. On Windows a running daemon holds open
|
|
1814
|
+
// file handles into targetDir โ retry with brief backoff before failing.
|
|
1815
|
+
// ponytail: 3 retries ร 600ms; escalate to process kill if this ceiling matters
|
|
1816
|
+
let phase1Done = false;
|
|
1817
|
+
for (let attempt = 0; attempt < 3 && !phase1Done; attempt++) {
|
|
1818
|
+
try {
|
|
1819
|
+
fs.renameSync(targetDir, retiredDir);
|
|
1820
|
+
phase1Done = true;
|
|
1821
|
+
} catch (retireError) {
|
|
1822
|
+
const retriable = retireError.code === 'EPERM' || retireError.code === 'EBUSY';
|
|
1823
|
+
if (retriable && attempt < 2) {
|
|
1824
|
+
const delayMs = 600 * (attempt + 1);
|
|
1825
|
+
try {
|
|
1826
|
+
if (process.platform === 'win32') {
|
|
1827
|
+
execSync(`powershell -NoProfile -Command "Start-Sleep -Milliseconds ${delayMs}"`, { stdio: 'ignore' });
|
|
1828
|
+
} else {
|
|
1829
|
+
execSync(`sleep ${delayMs / 1000}`, { stdio: 'ignore' });
|
|
1830
|
+
}
|
|
1831
|
+
} catch (_) {}
|
|
1832
|
+
continue;
|
|
1833
|
+
}
|
|
1834
|
+
safeRmDirSync(stagingDir);
|
|
1835
|
+
throw retireError;
|
|
1836
|
+
}
|
|
1837
|
+
}
|
|
1838
|
+
|
|
1839
|
+
// Phase 2: promote the staging tree. stagingDir was just unpacked and
|
|
1840
|
+
// has no open handles, so a single attempt is sufficient.
|
|
1807
1841
|
try {
|
|
1808
|
-
fs.renameSync(targetDir, retiredDir);
|
|
1809
1842
|
fs.renameSync(stagingDir, targetDir);
|
|
1810
|
-
} catch (
|
|
1811
|
-
|
|
1812
|
-
try { fs.renameSync(retiredDir, targetDir); } catch (_) {}
|
|
1813
|
-
}
|
|
1843
|
+
} catch (promoteError) {
|
|
1844
|
+
try { fs.renameSync(retiredDir, targetDir); } catch (_) {}
|
|
1814
1845
|
safeRmDirSync(stagingDir);
|
|
1815
|
-
throw
|
|
1846
|
+
throw promoteError;
|
|
1816
1847
|
}
|
|
1817
1848
|
|
|
1818
1849
|
// On Windows especially, deleting a directory that was just renamed or contains
|
|
@@ -1885,6 +1916,21 @@ async function installMemB(interactive) {
|
|
|
1885
1916
|
}));
|
|
1886
1917
|
}
|
|
1887
1918
|
const membDir = path.join(moduleBasePath(), 'memB');
|
|
1919
|
+
// On Windows the memB WebUI process holds open file handles inside membDir.
|
|
1920
|
+
// The atomic rename inside downloadOrUpdateModule fails with EPERM as long as
|
|
1921
|
+
// those handles are live โ retry backoff cannot help. Kill the process on
|
|
1922
|
+
// port 8088 before attempting the download so the rename succeeds.
|
|
1923
|
+
if (process.platform === 'win32') {
|
|
1924
|
+
try {
|
|
1925
|
+
execSync(
|
|
1926
|
+
'powershell -NoProfile -Command "' +
|
|
1927
|
+
'Get-NetTCPConnection -LocalPort 8088 -ErrorAction SilentlyContinue |' +
|
|
1928
|
+
' Select-Object -ExpandProperty OwningProcess |' +
|
|
1929
|
+
' ForEach-Object { Stop-Process -Id $_ -Force -ErrorAction SilentlyContinue }"',
|
|
1930
|
+
{ stdio: 'ignore' }
|
|
1931
|
+
);
|
|
1932
|
+
} catch (_) {}
|
|
1933
|
+
}
|
|
1888
1934
|
// A failed download used to fall through into venv setup and daemon
|
|
1889
1935
|
// registration, each of which then failed on its own terms or, worse,
|
|
1890
1936
|
// "succeeded" against a stale tree -- and the run still ended in a success
|
|
@@ -2050,13 +2096,23 @@ async function installSynapse() {
|
|
|
2050
2096
|
}
|
|
2051
2097
|
|
|
2052
2098
|
const isWin = process.platform === 'win32';
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2099
|
+
let binaryPath;
|
|
2100
|
+
if (isWin) {
|
|
2101
|
+
if (fs.existsSync(path.join(synapseDir, 'bin', 'synapse.exe'))) {
|
|
2102
|
+
binaryPath = path.join(synapseDir, 'bin', 'synapse.exe');
|
|
2103
|
+
} else if (fs.existsSync(path.join(synapseDir, 'bin', 'synapse-windows-amd64.exe'))) {
|
|
2104
|
+
binaryPath = path.join(synapseDir, 'bin', 'synapse-windows-amd64.exe');
|
|
2105
|
+
} else {
|
|
2106
|
+
binaryPath = path.join(synapseDir, 'bin', 'synapse.js');
|
|
2107
|
+
}
|
|
2108
|
+
} else {
|
|
2109
|
+
binaryPath = path.join(synapseDir, 'bin', 'synapse');
|
|
2110
|
+
if (!fs.existsSync(binaryPath)) {
|
|
2111
|
+
if (process.platform === 'darwin' && fs.existsSync(path.join(synapseDir, 'bin', 'synapse-darwin-arm64'))) {
|
|
2112
|
+
binaryPath = path.join(synapseDir, 'bin', 'synapse-darwin-arm64');
|
|
2113
|
+
} else if (process.platform === 'linux' && fs.existsSync(path.join(synapseDir, 'bin', 'synapse-linux-amd64'))) {
|
|
2114
|
+
binaryPath = path.join(synapseDir, 'bin', 'synapse-linux-amd64');
|
|
2115
|
+
}
|
|
2060
2116
|
}
|
|
2061
2117
|
}
|
|
2062
2118
|
|
|
@@ -2406,85 +2462,159 @@ async function installDevToolInstaller() {
|
|
|
2406
2462
|
}
|
|
2407
2463
|
}
|
|
2408
2464
|
|
|
2409
|
-
// AO
|
|
2410
|
-
// carries Windows and Linux sources but nothing built for them, and its CLI
|
|
2411
|
-
// shim picks the first candidate path that EXISTS without checking whether it
|
|
2412
|
-
// can run โ so on any other platform it hands spawn a Mach-O file and fails
|
|
2413
|
-
// with an exec-format error instead of the "go build" hint it means to give.
|
|
2414
|
-
// Installing it there would be installing something known not to work.
|
|
2465
|
+
// AO is fully supported across macOS (arm64, amd64), Linux (amd64, arm64), and Windows (amd64).
|
|
2415
2466
|
function aoSupportedHere() {
|
|
2416
|
-
return
|
|
2467
|
+
return ['darwin', 'linux', 'win32'].includes(process.platform);
|
|
2417
2468
|
}
|
|
2418
2469
|
|
|
2419
2470
|
async function installOSAgentWorkspace() {
|
|
2420
2471
|
if (!aoSupportedHere()) {
|
|
2421
|
-
log.warn(`AO
|
|
2422
|
-
log.warn('Build it from source instead: github.com/hybridlabor-api/bdb-agent-orchestrator');
|
|
2472
|
+
log.warn(`AO is not supported on ${process.platform}/${process.arch}.`);
|
|
2423
2473
|
return;
|
|
2424
2474
|
}
|
|
2425
2475
|
|
|
2426
|
-
const
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2476
|
+
const isWin = process.platform === 'win32';
|
|
2477
|
+
const isMac = process.platform === 'darwin';
|
|
2478
|
+
const isLinux = process.platform === 'linux';
|
|
2479
|
+
|
|
2480
|
+
// Discover AO directory: check local development checkouts first, then moduleBasePath
|
|
2481
|
+
const candidateDirs = [
|
|
2482
|
+
path.join(homeDir, 'dev', 'agents', 'bdb-agent-orchestrator'),
|
|
2483
|
+
path.join(homeDir, 'dev', 'bdb-dev', 'bdb-agent-orchestrator'),
|
|
2484
|
+
path.join(moduleBasePath(), 'bdb-agent-orchestrator')
|
|
2485
|
+
];
|
|
2486
|
+
const osAgentDir = candidateDirs.find(d => fs.existsSync(d)) || candidateDirs[candidateDirs.length - 1];
|
|
2487
|
+
const isLocalGitRepo = fs.existsSync(path.join(osAgentDir, '.git'));
|
|
2488
|
+
|
|
2489
|
+
if (isLocalGitRepo) {
|
|
2490
|
+
log.step(`Using local development workspace for AO: ${osAgentDir}`);
|
|
2491
|
+
} else {
|
|
2492
|
+
if (!downloadOrUpdateModule('@hybridlabor-api/bdb-agent-orchestrator', osAgentDir, 'BDB Agent Orchestrator')) {
|
|
2493
|
+
log.warn('Skipping AO setup: the module could not be downloaded.');
|
|
2494
|
+
return;
|
|
2495
|
+
}
|
|
2430
2496
|
}
|
|
2431
2497
|
if (DRY_RUN) {
|
|
2432
|
-
log.step('[dry-run] would link
|
|
2498
|
+
log.step('[dry-run] would link ao binary and run `ao service install`');
|
|
2433
2499
|
return;
|
|
2434
2500
|
}
|
|
2435
2501
|
|
|
2436
|
-
const localBinDir =
|
|
2437
|
-
|
|
2438
|
-
|
|
2502
|
+
const localBinDir = isWin
|
|
2503
|
+
? path.join(process.env.LOCALAPPDATA || homeDir, 'Programs', 'ao')
|
|
2504
|
+
: path.join(homeDir, '.local', 'bin');
|
|
2505
|
+
const binTarget = path.join(localBinDir, isWin ? 'ao.exe' : 'ao');
|
|
2506
|
+
|
|
2507
|
+
// Platform-specific binary lookup
|
|
2508
|
+
const candidateBinaries = [];
|
|
2509
|
+
if (isWin) {
|
|
2510
|
+
candidateBinaries.push(
|
|
2511
|
+
path.join(osAgentDir, 'backend', 'bin', 'ao-windows-amd64.exe'),
|
|
2512
|
+
path.join(osAgentDir, 'backend', 'bin', 'ao.exe'),
|
|
2513
|
+
path.join(osAgentDir, 'backend', 'ao.exe')
|
|
2514
|
+
);
|
|
2515
|
+
} else if (isMac) {
|
|
2516
|
+
if (process.arch === 'arm64') {
|
|
2517
|
+
candidateBinaries.push(path.join(osAgentDir, 'backend', 'bin', 'ao-darwin-arm64'));
|
|
2518
|
+
} else {
|
|
2519
|
+
candidateBinaries.push(path.join(osAgentDir, 'backend', 'bin', 'ao-darwin-amd64'));
|
|
2520
|
+
}
|
|
2521
|
+
candidateBinaries.push(
|
|
2522
|
+
path.join(osAgentDir, 'backend', 'ao-daemon'),
|
|
2523
|
+
path.join(osAgentDir, 'backend', 'bin', 'ao'),
|
|
2524
|
+
path.join(osAgentDir, 'backend', 'ao')
|
|
2525
|
+
);
|
|
2526
|
+
} else if (isLinux) {
|
|
2527
|
+
if (process.arch === 'arm64') {
|
|
2528
|
+
candidateBinaries.push(path.join(osAgentDir, 'backend', 'bin', 'ao-linux-arm64'));
|
|
2529
|
+
} else {
|
|
2530
|
+
candidateBinaries.push(path.join(osAgentDir, 'backend', 'bin', 'ao-linux-amd64'));
|
|
2531
|
+
}
|
|
2532
|
+
candidateBinaries.push(
|
|
2533
|
+
path.join(osAgentDir, 'backend', 'ao-daemon'),
|
|
2534
|
+
path.join(osAgentDir, 'backend', 'bin', 'ao'),
|
|
2535
|
+
path.join(osAgentDir, 'backend', 'ao')
|
|
2536
|
+
);
|
|
2537
|
+
}
|
|
2538
|
+
let daemonBin = candidateBinaries.find(p => fs.existsSync(p));
|
|
2539
|
+
|
|
2540
|
+
// Fallback: compile from Go source if Go is installed and binary is not pre-built
|
|
2541
|
+
if (!daemonBin && hasExecutable('go') && fs.existsSync(path.join(osAgentDir, 'backend', 'cmd', 'ao'))) {
|
|
2542
|
+
const s = spinner();
|
|
2543
|
+
s.start('Compiling AO daemon binary from Go source...');
|
|
2544
|
+
try {
|
|
2545
|
+
const buildTarget = path.join(osAgentDir, 'backend', 'bin', isWin ? 'ao.exe' : 'ao');
|
|
2546
|
+
fs.mkdirSync(path.dirname(buildTarget), { recursive: true });
|
|
2547
|
+
execFileSync('go', ['build', '-ldflags=-s -w', '-o', buildTarget, './cmd/ao'], {
|
|
2548
|
+
cwd: path.join(osAgentDir, 'backend'),
|
|
2549
|
+
stdio: 'ignore'
|
|
2550
|
+
});
|
|
2551
|
+
daemonBin = buildTarget;
|
|
2552
|
+
s.stop('Compiled AO daemon binary successfully.');
|
|
2553
|
+
} catch (e) {
|
|
2554
|
+
s.stop(`Failed to compile AO from source: ${e.message}`);
|
|
2555
|
+
}
|
|
2556
|
+
}
|
|
2439
2557
|
|
|
2440
|
-
if
|
|
2441
|
-
|
|
2558
|
+
// Fallback: if already installed and functional, keep it
|
|
2559
|
+
if (!daemonBin && fs.existsSync(binTarget)) {
|
|
2560
|
+
try {
|
|
2561
|
+
execFileSync(binTarget, ['--version'], { stdio: 'ignore' });
|
|
2562
|
+
log.step(`Keeping existing working AO binary at ${binTarget}`);
|
|
2563
|
+
daemonBin = binTarget;
|
|
2564
|
+
} catch (_) {}
|
|
2565
|
+
}
|
|
2566
|
+
|
|
2567
|
+
if (!daemonBin) {
|
|
2568
|
+
log.warn(`AO binary missing in ${osAgentDir} โ package layout changed or Go build needed.`);
|
|
2442
2569
|
return;
|
|
2443
2570
|
}
|
|
2444
2571
|
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
}
|
|
2572
|
+
if (daemonBin !== binTarget) {
|
|
2573
|
+
installStep('place the ao binary', () => {
|
|
2574
|
+
fs.mkdirSync(localBinDir, { recursive: true });
|
|
2575
|
+
fs.copyFileSync(daemonBin, binTarget);
|
|
2576
|
+
if (!isWin) {
|
|
2577
|
+
fs.chmodSync(binTarget, 0o755);
|
|
2578
|
+
}
|
|
2579
|
+
log.step(`Installed ao to ${binTarget}`);
|
|
2580
|
+
}, 'AO cannot be started without its binary.');
|
|
2581
|
+
}
|
|
2455
2582
|
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
} catch {
|
|
2459
|
-
log.warn('The ao binary is not code-signed โ AMFI will kill it at launch.');
|
|
2583
|
+
// macOS only: code-sign ad-hoc to prevent AMFI SIGKILL
|
|
2584
|
+
if (isMac) {
|
|
2460
2585
|
try {
|
|
2461
|
-
execFileSync('codesign', ['-
|
|
2462
|
-
|
|
2463
|
-
|
|
2586
|
+
execFileSync('codesign', ['-v', binTarget], { stdio: 'ignore' });
|
|
2587
|
+
} catch {
|
|
2588
|
+
log.warn('The ao binary is not code-signed โ AMFI will kill it at launch.');
|
|
2589
|
+
try {
|
|
2590
|
+
execFileSync('codesign', ['-s', '-', '-f', binTarget], { stdio: 'ignore' });
|
|
2591
|
+
log.step('Signed it ad-hoc.');
|
|
2592
|
+
} catch (e) { log.warn(`Could not sign it: ${e.message}`); }
|
|
2593
|
+
}
|
|
2464
2594
|
}
|
|
2465
2595
|
|
|
2466
2596
|
// AO installs its own service, and does it for macOS, Windows and Linux.
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
// service definition changes upstream.
|
|
2474
|
-
const legacyPlist = path.join(homeDir, 'Library', 'LaunchAgents', 'com.bdb.agent-workspace.plist');
|
|
2475
|
-
if (fs.existsSync(legacyPlist)) {
|
|
2476
|
-
try { execFileSync('launchctl', ['unload', legacyPlist], { stdio: 'ignore' }); } catch (e) { logDebug(e, 'unload legacy ao agent'); }
|
|
2477
|
-
try { fs.unlinkSync(legacyPlist); log.step('Removed the old com.bdb.agent-workspace service.'); } catch (e) { logDebug(e, 'remove legacy plist'); }
|
|
2597
|
+
if (isMac) {
|
|
2598
|
+
const legacyPlist = path.join(homeDir, 'Library', 'LaunchAgents', 'com.bdb.agent-workspace.plist');
|
|
2599
|
+
if (fs.existsSync(legacyPlist)) {
|
|
2600
|
+
try { execFileSync('launchctl', ['unload', legacyPlist], { stdio: 'ignore' }); } catch (e) { logDebug(e, 'unload legacy ao agent'); }
|
|
2601
|
+
try { fs.unlinkSync(legacyPlist); log.step('Removed the old com.bdb.agent-workspace service.'); } catch (e) { logDebug(e, 'remove legacy plist'); }
|
|
2602
|
+
}
|
|
2478
2603
|
}
|
|
2479
2604
|
|
|
2480
2605
|
installStep('register the AO service', () => {
|
|
2481
2606
|
execFileSync(binTarget, ['service', 'install'], { stdio: 'ignore' });
|
|
2482
2607
|
}, 'Start it by hand with: ao service install');
|
|
2483
2608
|
|
|
2484
|
-
|
|
2609
|
+
// Windows startup entries fire asynchronously โ give the service more time
|
|
2610
|
+
const aoTimeout = process.platform === 'win32' ? 20000 : 8000;
|
|
2611
|
+
if (await verifyDaemonListening(3101, 'AO Orchestrator', aoTimeout)) {
|
|
2485
2612
|
log.success('AO Orchestrator running on http://localhost:3101');
|
|
2486
2613
|
} else {
|
|
2487
|
-
|
|
2614
|
+
const hint = process.platform === 'win32'
|
|
2615
|
+
? 'Run `ao service install` again or log out and back in, then check `ao service status`.'
|
|
2616
|
+
: 'Check `ao service status` and `ao service logs`.';
|
|
2617
|
+
log.warn(`AO did not answer on :3101 โ ${hint}`);
|
|
2488
2618
|
}
|
|
2489
2619
|
}
|
|
2490
2620
|
async function promptMemBIngestion(mcpCodeTarget) {
|
|
@@ -2534,7 +2664,7 @@ function verifyEcosystemInstallation() {
|
|
|
2534
2664
|
{ name: '1. bdb-synapse', pkg: '@hybridlabor-api/bdb-synapse', paths: [path.join(moduleBasePath(), 'bdb-synapse')] },
|
|
2535
2665
|
{ name: '2. memB', pkg: '@hybridlabor-api/memb', paths: [path.join(moduleBasePath(), 'memB'), path.join(geminiDir, 'config', 'mcps', 'memb-mcp')] },
|
|
2536
2666
|
{ name: '3. heimdall-token-saver', pkg: '@hybridlabor-api/heimdall-token-saver', paths: [path.join(moduleBasePath(), 'heimdall-token-saver'), path.join(srcDir, 'vendor', 'token-saver')] },
|
|
2537
|
-
{ name: '4. AO Agent Orchestrator', pkg: '@hybridlabor-api/bdb-agent-orchestrator', paths: [path.join(moduleBasePath(), 'bdb-agent-orchestrator')] },
|
|
2667
|
+
{ name: '4. AO Agent Orchestrator', pkg: '@hybridlabor-api/bdb-agent-orchestrator', paths: [path.join(homeDir, 'dev', 'agents', 'bdb-agent-orchestrator'), path.join(moduleBasePath(), 'bdb-agent-orchestrator')] },
|
|
2538
2668
|
{ name: '5. bdb-dev-creator-extension', pkg: '@hybridlabor-api/bdb-dev-creator-extension', paths: [path.join(moduleBasePath(), 'bdb-dev-creator-extension')] },
|
|
2539
2669
|
{ name: '6. bdb-hardware-pcb', pkg: '@hybridlabor-api/bdb-hardware-pcb', paths: [path.join(moduleBasePath(), 'bdb-hardware-pcb')] },
|
|
2540
2670
|
{ name: '7. bdb-os-remote', pkg: '@hybridlabor-api/bdb-os-remote', paths: [path.join(moduleBasePath(), 'bdb-os-remote')] },
|
|
@@ -2558,7 +2688,10 @@ function verifyEcosystemInstallation() {
|
|
|
2558
2688
|
let newerVersion = null;
|
|
2559
2689
|
let newerTag = null;
|
|
2560
2690
|
try {
|
|
2561
|
-
const
|
|
2691
|
+
const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
2692
|
+
const distTagsJson = process.platform === 'win32'
|
|
2693
|
+
? execSync(`"${npmCmd}" view ${mod.pkg} dist-tags --json`, { stdio: ['ignore', 'pipe', 'ignore'], encoding: 'utf8', timeout: 4000 }).trim()
|
|
2694
|
+
: execFileSync(npmCmd, ['view', mod.pkg, 'dist-tags', '--json'], { stdio: ['ignore', 'pipe', 'ignore'], encoding: 'utf8', timeout: 4000 }).trim();
|
|
2562
2695
|
const distTags = JSON.parse(distTagsJson);
|
|
2563
2696
|
for (const [tag, ver] of Object.entries(distTags)) {
|
|
2564
2697
|
if (isNewerVersion(localVer, ver)) {
|
|
@@ -2604,7 +2737,7 @@ function verifyEcosystemInstallation() {
|
|
|
2604
2737
|
|
|
2605
2738
|
console.log('');
|
|
2606
2739
|
console.log(` ${colors.bold}โโโ BDB Agent OS Dashboard โโโ${colors.reset}`);
|
|
2607
|
-
console.log(` Interactive Control Center:
|
|
2740
|
+
console.log(` Interactive Control Center: aos-dashboard`);
|
|
2608
2741
|
console.log(` ${colors.dim}(Live status & service control at http://127.0.0.1:7900)${colors.reset}`);
|
|
2609
2742
|
}
|
|
2610
2743
|
|
|
@@ -3544,23 +3677,23 @@ function injectHarnessRules() {
|
|
|
3544
3677
|
// that adds or changes a hook silently never received it -- which is exactly
|
|
3545
3678
|
// what happened to memb-inject.mjs in v4.4.0, on the machines that needed it
|
|
3546
3679
|
// most (a fresh install got it; every machine that already had AOS did not).
|
|
3547
|
-
function installGlobalHooks() {
|
|
3680
|
+
function installGlobalHooks({ targetHome = homeDir, targetGemini = geminiDir } = {}) {
|
|
3548
3681
|
const hooksSrc = path.join(srcDir, '.claude', 'hooks');
|
|
3549
3682
|
const workflowsSrc = path.join(srcDir, '.claude', 'workflows');
|
|
3550
3683
|
|
|
3551
3684
|
// 1. Claude Code
|
|
3552
3685
|
if (fs.existsSync(hooksSrc)) {
|
|
3553
|
-
copyDirRecursiveSync(hooksSrc, path.join(
|
|
3554
|
-
log.step(`Installed hooks to ${path.join(
|
|
3686
|
+
copyDirRecursiveSync(hooksSrc, path.join(targetHome, '.claude', 'hooks'));
|
|
3687
|
+
log.step(`Installed hooks to ${path.join(targetHome, '.claude', 'hooks')}`);
|
|
3555
3688
|
}
|
|
3556
3689
|
if (fs.existsSync(workflowsSrc)) {
|
|
3557
|
-
copyDirRecursiveSync(workflowsSrc, path.join(
|
|
3690
|
+
copyDirRecursiveSync(workflowsSrc, path.join(targetHome, '.claude', 'workflows'));
|
|
3558
3691
|
}
|
|
3559
|
-
mergeBdbSettingsHooks(path.join(
|
|
3692
|
+
mergeBdbSettingsHooks(path.join(targetHome, '.claude', 'settings.json'));
|
|
3560
3693
|
|
|
3561
3694
|
// 2. Google Antigravity
|
|
3562
|
-
const agyHooksDir = path.join(
|
|
3563
|
-
const agyWorkflowsDir = path.join(
|
|
3695
|
+
const agyHooksDir = path.join(targetGemini, 'config', 'hooks');
|
|
3696
|
+
const agyWorkflowsDir = path.join(targetGemini, 'config', 'workflows');
|
|
3564
3697
|
if (fs.existsSync(hooksSrc)) {
|
|
3565
3698
|
copyDirRecursiveSync(hooksSrc, agyHooksDir);
|
|
3566
3699
|
log.step(`Installed hooks to ${agyHooksDir}`);
|
|
@@ -3568,14 +3701,24 @@ function installGlobalHooks() {
|
|
|
3568
3701
|
if (fs.existsSync(workflowsSrc)) {
|
|
3569
3702
|
copyDirRecursiveSync(workflowsSrc, agyWorkflowsDir);
|
|
3570
3703
|
}
|
|
3571
|
-
mergeAntigravityHooks(path.join(
|
|
3572
|
-
|
|
3573
|
-
|
|
3704
|
+
mergeAntigravityHooks(path.join(targetGemini, 'config', 'hooks.json'));
|
|
3705
|
+
const agyCliDir = path.join(targetGemini, 'antigravity-cli');
|
|
3706
|
+
if (fs.existsSync(agyCliDir)) {
|
|
3707
|
+
const agyCliHooksDir = path.join(agyCliDir, 'hooks');
|
|
3708
|
+
const agyCliWorkflowsDir = path.join(agyCliDir, 'workflows');
|
|
3709
|
+
if (fs.existsSync(hooksSrc)) {
|
|
3710
|
+
copyDirRecursiveSync(hooksSrc, agyCliHooksDir);
|
|
3711
|
+
log.step(`Installed hooks to ${agyCliHooksDir}`);
|
|
3712
|
+
}
|
|
3713
|
+
if (fs.existsSync(workflowsSrc)) {
|
|
3714
|
+
copyDirRecursiveSync(workflowsSrc, agyCliWorkflowsDir);
|
|
3715
|
+
}
|
|
3716
|
+
mergeAntigravityHooks(path.join(agyCliDir, 'hooks.json'));
|
|
3574
3717
|
}
|
|
3575
3718
|
|
|
3576
3719
|
// 3. OpenAI Codex CLI
|
|
3577
|
-
const codexHooksDir = path.join(
|
|
3578
|
-
const codexWorkflowsDir = path.join(
|
|
3720
|
+
const codexHooksDir = path.join(targetHome, '.codex', 'hooks');
|
|
3721
|
+
const codexWorkflowsDir = path.join(targetHome, '.codex', 'workflows');
|
|
3579
3722
|
if (fs.existsSync(hooksSrc)) {
|
|
3580
3723
|
copyDirRecursiveSync(hooksSrc, codexHooksDir);
|
|
3581
3724
|
log.step(`Installed hooks to ${codexHooksDir}`);
|
|
@@ -3583,12 +3726,12 @@ function installGlobalHooks() {
|
|
|
3583
3726
|
if (fs.existsSync(workflowsSrc)) {
|
|
3584
3727
|
copyDirRecursiveSync(workflowsSrc, codexWorkflowsDir);
|
|
3585
3728
|
}
|
|
3586
|
-
mergeCodexTomlHooks(path.join(
|
|
3729
|
+
mergeCodexTomlHooks(path.join(targetHome, '.codex', 'config.toml'));
|
|
3587
3730
|
|
|
3588
3731
|
// 4. OpenCode CLI
|
|
3589
3732
|
const opencodeDir = process.platform === 'win32'
|
|
3590
|
-
? path.join(process.env.APPDATA ||
|
|
3591
|
-
: path.join(
|
|
3733
|
+
? path.join(process.env.APPDATA || targetHome, 'opencode')
|
|
3734
|
+
: path.join(targetHome, '.config', 'opencode');
|
|
3592
3735
|
const opencodePluginSrc = path.join(srcDir, '.opencode', 'plugins', 'bdb-aos.js');
|
|
3593
3736
|
if (fs.existsSync(opencodePluginSrc)) {
|
|
3594
3737
|
const opencodePluginsDir = path.join(opencodeDir, 'plugins');
|
|
@@ -3664,7 +3807,7 @@ function installGlobalBinaries() {
|
|
|
3664
3807
|
// merged result goes to a .bdb-new.json sidecar -- the same recovery pattern
|
|
3665
3808
|
// the MCP config merge in installMcpsForTarget uses.
|
|
3666
3809
|
function mergeBdbSettingsHooks(settingsPath, { projectLocal = false } = {}) {
|
|
3667
|
-
const bdbHookScripts = ['go-gate.mjs', 'graph-gate.mjs', 'memb-inject.mjs', 'trail-relay.mjs'];
|
|
3810
|
+
const bdbHookScripts = ['go-gate.mjs', 'graph-gate.mjs', 'memb-inject.mjs', 'trail-relay.mjs', 'conventional-commits.mjs', 'env-file-protection.mjs'];
|
|
3668
3811
|
// memb-inject reads the machine-global memB store under $HOME and is
|
|
3669
3812
|
// installed once per machine, so it stays $HOME-anchored even inside a
|
|
3670
3813
|
// project harness -- unlike the two gate hooks, which are per-checkout by
|
|
@@ -3736,7 +3879,7 @@ function mergeBdbSettingsHooks(settingsPath, { projectLocal = false } = {}) {
|
|
|
3736
3879
|
// Merge the BDB hooks into Google Antigravity's hooks.json (.agents/hooks.json or
|
|
3737
3880
|
// ~/.gemini/config/hooks.json), preserving user-defined foreign hooks.
|
|
3738
3881
|
function mergeAntigravityHooks(hooksPath, { projectLocal = false } = {}) {
|
|
3739
|
-
const bdbHookScripts = ['go-gate.mjs', 'graph-gate.mjs', 'memb-inject.mjs', 'startcycle-dispatch.mjs', 'trail-relay.mjs'];
|
|
3882
|
+
const bdbHookScripts = ['go-gate.mjs', 'graph-gate.mjs', 'memb-inject.mjs', 'startcycle-dispatch.mjs', 'trail-relay.mjs', 'conventional-commits.mjs', 'env-file-protection.mjs'];
|
|
3740
3883
|
const isBdbEntry = (entry) => {
|
|
3741
3884
|
const cmds = (entry && Array.isArray(entry.hooks) ? entry.hooks : [entry])
|
|
3742
3885
|
.map((h) => (h && typeof h.command === 'string' ? h.command : (typeof h === 'string' ? h : '')))
|
|
@@ -3753,7 +3896,14 @@ function mergeAntigravityHooks(hooksPath, { projectLocal = false } = {}) {
|
|
|
3753
3896
|
PreToolUse: [
|
|
3754
3897
|
{
|
|
3755
3898
|
matcher: "run_command|Bash",
|
|
3756
|
-
hooks: [
|
|
3899
|
+
hooks: [
|
|
3900
|
+
{ type: "command", command: `node "${path.join(hooksDir, 'go-gate.mjs')}"`, timeout: 10000 },
|
|
3901
|
+
{ type: "command", command: `node "${path.join(hooksDir, 'conventional-commits.mjs')}"`, timeout: 10000 }
|
|
3902
|
+
]
|
|
3903
|
+
},
|
|
3904
|
+
{
|
|
3905
|
+
matcher: "write_file|edit_file|replace|Write|Edit|MultiEdit",
|
|
3906
|
+
hooks: [{ type: "command", command: `node "${path.join(hooksDir, 'env-file-protection.mjs')}"`, timeout: 10000 }]
|
|
3757
3907
|
},
|
|
3758
3908
|
{
|
|
3759
3909
|
hooks: [{ type: "command", command: `node "${path.join(globalHooksDir, 'trail-relay.mjs')}" --agent agy --event PreToolUse`, timeout: 2000 }]
|
|
@@ -4775,18 +4925,24 @@ async function runQuickUpdate(installState) {
|
|
|
4775
4925
|
injectHarnessRules();
|
|
4776
4926
|
}, 'Harness files keep whatever version this machine already had.');
|
|
4777
4927
|
|
|
4778
|
-
// OpenWiki
|
|
4779
|
-
//
|
|
4780
|
-
//
|
|
4781
|
-
//
|
|
4782
|
-
// that case, so this is a no-op confirm for anyone already configured and a
|
|
4783
|
-
// real one-time offer for anyone who isn't (including installs from before
|
|
4784
|
-
// this feature existed).
|
|
4928
|
+
// OpenWiki: if already configured, refresh the daemon silently (no prompt).
|
|
4929
|
+
// Only ask when there is no key yet โ i.e. a first-time offer or a machine
|
|
4930
|
+
// that predates this feature. This avoids the "keep existing?" confirmation
|
|
4931
|
+
// on every Quick Update for users who have already set up OpenWiki.
|
|
4785
4932
|
if (!isAutoYes) {
|
|
4786
|
-
const
|
|
4787
|
-
|
|
4788
|
-
|
|
4933
|
+
const _owEnv = loadExistingEnv(paths.targetMcpDir);
|
|
4934
|
+
const _owProvider = _owEnv['OPENWIKI_PROVIDER'] || 'google';
|
|
4935
|
+
const _owKeyName = PROVIDER_KEY_ENV_NAMES[_owProvider] || 'GEMINI_API_KEY';
|
|
4936
|
+
const _owKey = _owEnv[_owKeyName] || _owEnv['GEMINI_API_KEY'] || _owEnv['GOOGLE_API_KEY'] || _owEnv['OPENWIKI_API_KEY'] || '';
|
|
4937
|
+
if (_owKey || _owProvider === 'ollama') {
|
|
4938
|
+
await installOpenWikiDaemon(_owKey, paths.targetSkillDir, { provider: _owProvider, model: _owEnv['OPENWIKI_MODEL'] || '', baseUrl: _owEnv['OPENWIKI_BASE_URL'] || '' });
|
|
4789
4939
|
await installOpenWikiVisualizer();
|
|
4940
|
+
} else {
|
|
4941
|
+
const creds = await promptCredentials(paths.targetMcpDir);
|
|
4942
|
+
if (creds !== BACK) {
|
|
4943
|
+
await installOpenWikiDaemon(creds.gemini, paths.targetSkillDir, { provider: creds.openwikiProvider, model: creds.openwikiModel, baseUrl: creds.openwikiBaseUrl });
|
|
4944
|
+
await installOpenWikiVisualizer();
|
|
4945
|
+
}
|
|
4790
4946
|
}
|
|
4791
4947
|
}
|
|
4792
4948
|
|
|
@@ -4795,8 +4951,7 @@ async function runQuickUpdate(installState) {
|
|
|
4795
4951
|
if (subId === 'synapse') await installSynapse();
|
|
4796
4952
|
else if (subId === 'memb') await installMemB(false);
|
|
4797
4953
|
else if (subId === 'remote') await installOSRemoteGateway();
|
|
4798
|
-
|
|
4799
|
-
// existing installs -- see promptOptionalModules() for why.
|
|
4954
|
+
else if (subId === 'ao' && aoSupportedHere()) await installOSAgentWorkspace();
|
|
4800
4955
|
else if (subId === 'creator') await installCreatorExtension();
|
|
4801
4956
|
else if (subId === 'hardware') await installHardwarePcb();
|
|
4802
4957
|
else if (subId === 'installer') await installDevToolInstaller();
|
|
@@ -4840,6 +4995,40 @@ function buildAoAnnouncementBanner() {
|
|
|
4840
4995
|
].join('\n');
|
|
4841
4996
|
}
|
|
4842
4997
|
|
|
4998
|
+
// AOS CLI ships as a separate npm package under packages/ for one reason: pi
|
|
4999
|
+
// updates on its own cadence, and folding it into this release cycle would turn
|
|
5000
|
+
// every pi bump into a full AOS reinstall. So it installs as an ordinary global
|
|
5001
|
+
// package and pulls pi in as its own dependency -- and it writes nothing to
|
|
5002
|
+
// ~/.agents, because it reads that directory rather than owning it.
|
|
5003
|
+
function installAosCli() {
|
|
5004
|
+
const pkgDir = path.join(srcDir, 'packages', 'aos-cli');
|
|
5005
|
+
const manual = 'cd packages/aos-cli && npm install -g .';
|
|
5006
|
+
|
|
5007
|
+
if (!fs.existsSync(path.join(pkgDir, 'package.json'))) {
|
|
5008
|
+
log.warn(`AOS CLI package missing at ${pkgDir} -- skipped. Install it later: ${manual}`);
|
|
5009
|
+
return;
|
|
5010
|
+
}
|
|
5011
|
+
if (hasExecutable('aos-cli')) {
|
|
5012
|
+
log.step('aos-cli is already on PATH.');
|
|
5013
|
+
return;
|
|
5014
|
+
}
|
|
5015
|
+
if (DRY_RUN) {
|
|
5016
|
+
log.step('[dry-run] would run: npm install -g <packages/aos-cli>');
|
|
5017
|
+
return;
|
|
5018
|
+
}
|
|
5019
|
+
|
|
5020
|
+
const res = installStep('install AOS CLI', () => {
|
|
5021
|
+
log.step('Installing AOS CLI globally (pi is installed as its dependency)...');
|
|
5022
|
+
execSync(`npm install -g ${JSON.stringify(pkgDir)}`, { stdio: 'ignore' });
|
|
5023
|
+
}, `The rest of AOS is installed. Install AOS CLI later: ${manual}`);
|
|
5024
|
+
|
|
5025
|
+
if (res.ok && hasExecutable('aos-cli')) {
|
|
5026
|
+
log.success('AOS CLI installed -- run `aos-cli`.');
|
|
5027
|
+
} else if (res.ok) {
|
|
5028
|
+
log.warn('AOS CLI is installed but `aos-cli` is not on PATH. launchd and some Windows shells start with a PATH that omits npm\'s global bin.');
|
|
5029
|
+
}
|
|
5030
|
+
}
|
|
5031
|
+
|
|
4843
5032
|
async function main() {
|
|
4844
5033
|
if (process.argv[2] === 'store') {
|
|
4845
5034
|
const storeScript = path.join(srcDir, 'bin', 'aos-store.mjs');
|
|
@@ -4981,6 +5170,7 @@ async function main() {
|
|
|
4981
5170
|
{ value: '7', label: 'Roo Code / Cline / VS Code', hint: '~/.roo' },
|
|
4982
5171
|
{ value: '8', label: 'Aider CLI', hint: '~/.aider' },
|
|
4983
5172
|
{ value: '9', label: '๐ Local Project Harness', hint: 'copy dispatcher contract to current project' },
|
|
5173
|
+
{ value: '10', label: '๐ฅ๏ธ AOS CLI', hint: 'pi harness -- reads ~/.agents, no own skill copy' },
|
|
4984
5174
|
{ value: '4', label: 'โ๏ธ Custom Installation', hint: 'specify paths manually' }
|
|
4985
5175
|
];
|
|
4986
5176
|
|
|
@@ -5010,7 +5200,7 @@ async function main() {
|
|
|
5010
5200
|
selectedMcps = await promptMcpSelection(tier);
|
|
5011
5201
|
} else {
|
|
5012
5202
|
const ctx = { tier: '1', selectedPlatforms: ['0'], mode: 'merge', customPaths: null, creds: null, selectedMcps: null };
|
|
5013
|
-
const platformNames = { '0': '๐ Universal Harness', '1': 'Google Antigravity', '2': 'Claude Desktop/Code', '3': 'Cursor/Generic IDE', '4': 'Custom Paths', '5': 'ChatGPT Codex CLI', '6': 'Windsurf', '7': 'Roo Code / Cline / VS Code', '8': 'Aider CLI', '9': 'Local Project Harness' };
|
|
5203
|
+
const platformNames = { '0': '๐ Universal Harness', '1': 'Google Antigravity', '2': 'Claude Desktop/Code', '3': 'Cursor/Generic IDE', '4': 'Custom Paths', '5': 'ChatGPT Codex CLI', '6': 'Windsurf', '7': 'Roo Code / Cline / VS Code', '8': 'Aider CLI', '9': 'Local Project Harness', '10': 'AOS CLI' };
|
|
5014
5204
|
|
|
5015
5205
|
const stepTier = async () => {
|
|
5016
5206
|
const t = await selectWithBack({
|
|
@@ -5176,7 +5366,22 @@ async function main() {
|
|
|
5176
5366
|
fs.mkdirSync(backupDir, { recursive: true, mode: 0o700 });
|
|
5177
5367
|
}, 'The installation continues, but existing files are not backed up.');
|
|
5178
5368
|
|
|
5179
|
-
|
|
5369
|
+
// '10' is an action, not a directory target. AOS CLI reads
|
|
5370
|
+
// ~/.agents/skills, which syncSkillsToGlobalHarnesses() already writes --
|
|
5371
|
+
// left in this list it would fall through resolveTargetPaths()'s universal
|
|
5372
|
+
// defaults and install a second full copy of every skill somewhere nobody
|
|
5373
|
+
// reads them from.
|
|
5374
|
+
const aosCliRequested = specificPlatforms.includes('10');
|
|
5375
|
+
const dirPlatforms = specificPlatforms.filter(p => p !== '10');
|
|
5376
|
+
|
|
5377
|
+
if (aosCliRequested && dirPlatforms.length === 0) {
|
|
5378
|
+
// AOS CLI alone would have no skills to load, and an empty target list
|
|
5379
|
+
// leaves primaryTarget undefined for everything downstream of it.
|
|
5380
|
+
log.warn('AOS CLI was the only target -- adding the universal skill target so it has something to load.');
|
|
5381
|
+
dirPlatforms.push('1');
|
|
5382
|
+
}
|
|
5383
|
+
|
|
5384
|
+
const targets = dirPlatforms.map(p => ({
|
|
5180
5385
|
value: p,
|
|
5181
5386
|
...resolveTargetPaths(p, customPaths)
|
|
5182
5387
|
}));
|
|
@@ -5263,10 +5468,13 @@ async function main() {
|
|
|
5263
5468
|
// Flush file-level install manifest after all writes are done.
|
|
5264
5469
|
flushSessionManifest();
|
|
5265
5470
|
|
|
5471
|
+
// After the skill sync, because AOS CLI is useless without ~/.agents.
|
|
5472
|
+
if (aosCliRequested) installAosCli();
|
|
5473
|
+
|
|
5266
5474
|
console.log('');
|
|
5267
5475
|
verifyEcosystemInstallation();
|
|
5268
5476
|
|
|
5269
|
-
outro(`๐ Installation complete! Targets: ${targets.map(t => t.value).join(', ')} ยท Tier: ${tier === '1' ? 'Pro MEDIA' : 'Basic'}${DRY_RUN ? ' ยท DRY-RUN (nothing was modified)' : ''}`);
|
|
5477
|
+
outro(`๐ Installation complete! Targets: ${targets.map(t => t.value).join(', ')}${aosCliRequested ? ' + AOS CLI' : ''} ยท Tier: ${tier === '1' ? 'Pro MEDIA' : 'Basic'}${DRY_RUN ? ' ยท DRY-RUN (nothing was modified)' : ''}`);
|
|
5270
5478
|
}
|
|
5271
5479
|
|
|
5272
5480
|
if (require.main === module) {
|