@hybridlabor-api/aos 4.4.2-beta.5 → 4.4.2-beta.7

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 CHANGED
@@ -1,5 +1,20 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ // Node compatibility guard -- must run before any require() that could pull
4
+ // in a dependency using the `node:` built-in scheme (@clack/prompts ->
5
+ // @clack/core does `require('node:process')` internally), which only
6
+ // resolves on Node >=14.18/>=16. On an older Node this crashed deep inside
7
+ // that dependency with a bare "Cannot find module 'node:process'" -- no
8
+ // mention of Node version anywhere -- reported from a real Windows machine
9
+ // where the installer couldn't even start. Uses only process.version, a
10
+ // built-in global with no require() of its own, so this check itself runs
11
+ // on any Node version ever shipped.
12
+ const NODE_MAJOR = parseInt(process.version.slice(1).split('.')[0], 10);
13
+ if (Number.isFinite(NODE_MAJOR) && NODE_MAJOR < 20) {
14
+ console.error(`\nAOS requires Node.js 20 or newer -- this machine has ${process.version}.\nInstall a current Node.js from https://nodejs.org and re-run.\n`);
15
+ process.exit(1);
16
+ }
17
+
3
18
  const fs = require('fs');
4
19
  const path = require('path');
5
20
  const os = require('os');
@@ -2237,7 +2252,17 @@ function verifyEcosystemInstallation() {
2237
2252
  function resolveTargetPaths(platformValue, customPaths) {
2238
2253
  let targetSkillDir = globalConfigDir;
2239
2254
  let targetLegacyDir = globalLegacyDir;
2240
- let targetWorkspaceDir = workspaceDir;
2255
+ // NOT the module-level `workspaceDir` (process.cwd()-based) -- that default
2256
+ // is only correct for the Cursor branch below and the explicit Local
2257
+ // Project Harness selection (platformValue '4' with customPaths), both of
2258
+ // which are genuinely project-scoped by design. For every other platform,
2259
+ // including this function's own top-level default used by the universal
2260
+ // tier ('1'), a global Quick Update inherited a directory relative to
2261
+ // whatever the current working directory happened to be -- silently
2262
+ // harmless when cwd sat under the user's own home dir, but a hard EPERM
2263
+ // crash the one time a Windows user ran npx from C:\Windows\System32
2264
+ // (PowerShell's default start directory, unwritable for a normal user).
2265
+ let targetWorkspaceDir = path.join(homeDir, '.agents', 'workspace_skills');
2241
2266
  let targetMcpDir = path.join(geminiDir, 'config');
2242
2267
  let mcpConfigPath = path.join(targetMcpDir, 'mcp_config.json');
2243
2268
  // Secondary MCP stores that must receive the same servers as mcpConfigPath
@@ -3303,8 +3328,13 @@ function generateAndOpenLaunchpad() {
3303
3328
  if (process.env.SSH_CLIENT || process.env.SSH_TTY) return;
3304
3329
 
3305
3330
  // Local Developer Workflow Guard:
3306
- // Only generate and open the launchpad if running in a local developer repo environment or explicitly requested
3307
- const isDevWorkflow = fs.existsSync(path.join(homeDir, 'bdb-dev')) ||
3331
+ // Only generate and open the launchpad if running in a local developer repo environment or explicitly requested.
3332
+ // ~/bdb-dev was the pre-reorg workspace root; the State-0 reorg moved it to
3333
+ // ~/dev/bdb-dev, but this check was never updated -- it has been silently
3334
+ // false on every real dev machine since that reorg. Checking both keeps
3335
+ // this working regardless of which layout a given machine still has.
3336
+ const isDevWorkflow = fs.existsSync(path.join(homeDir, 'dev', 'bdb-dev')) ||
3337
+ fs.existsSync(path.join(homeDir, 'bdb-dev')) ||
3308
3338
  process.env.BDB_DEV === '1' ||
3309
3339
  process.argv.includes('--launchpad') ||
3310
3340
  process.argv.includes('--dev');
@@ -3464,8 +3494,8 @@ function generateAndOpenLaunchpad() {
3464
3494
  <div class="card-content">
3465
3495
  <div class="card-icon">⚡</div>
3466
3496
  <div class="card-info">
3467
- <h2>Agent Workspace</h2>
3468
- <p>Multi-Agent Cockpit & Orchestrator</p>
3497
+ <h2>AO — Agent Orchestrator</h2>
3498
+ <p>Multi-Agent Cockpit & Git-Worktree Orchestration</p>
3469
3499
  </div>
3470
3500
  </div>
3471
3501
  <div class="card-meta">
@@ -3473,6 +3503,19 @@ function generateAndOpenLaunchpad() {
3473
3503
  <span class="status-dot" id="dot-ao" title="Checking..."></span>
3474
3504
  </div>
3475
3505
  </a>
3506
+ <a class="card" href="http://127.0.0.1:9080" target="_blank">
3507
+ <div class="card-content">
3508
+ <div class="card-icon">🌐</div>
3509
+ <div class="card-info">
3510
+ <h2>RemoteOS Gateway</h2>
3511
+ <p>Multi-Cloud Execution & 4-Eyes Approval Gateway</p>
3512
+ </div>
3513
+ </div>
3514
+ <div class="card-meta">
3515
+ <span class="port-pill">:9080</span>
3516
+ <span class="status-dot" id="dot-remote" title="Checking..."></span>
3517
+ </div>
3518
+ </a>
3476
3519
  </div>
3477
3520
  <div class="footer">
3478
3521
  <span>Autostart Daemons • 127.0.0.1</span>
@@ -3486,14 +3529,14 @@ function generateAndOpenLaunchpad() {
3486
3529
  .then(() => dot.classList.add('online'))
3487
3530
  .catch(() => dot.classList.remove('online'));
3488
3531
  }
3489
- checkHealth('http://127.0.0.1:8088', 'dot-memb');
3490
- checkHealth('http://127.0.0.1:7781', 'dot-synapse');
3491
- checkHealth('http://127.0.0.1:3101', 'dot-ao');
3492
- setInterval(() => {
3532
+ function checkAllHealth() {
3493
3533
  checkHealth('http://127.0.0.1:8088', 'dot-memb');
3494
3534
  checkHealth('http://127.0.0.1:7781', 'dot-synapse');
3495
3535
  checkHealth('http://127.0.0.1:3101', 'dot-ao');
3496
- }, 5000);
3536
+ checkHealth('http://127.0.0.1:9080', 'dot-remote');
3537
+ }
3538
+ checkAllHealth();
3539
+ setInterval(checkAllHealth, 5000);
3497
3540
  </script>
3498
3541
  </body>
3499
3542
  </html>`;
@@ -3520,6 +3563,47 @@ function generateAndOpenLaunchpad() {
3520
3563
  child.on('error', warnOpenFailed);
3521
3564
  child.unref();
3522
3565
  } catch (e) { warnOpenFailed(e); }
3566
+
3567
+ // Opening it once per install/update isn't the same as being available at
3568
+ // every login -- memB/Synapse/AO all get a real autostart entry for their
3569
+ // own background services, but the dashboard itself (a static file, not
3570
+ // a process) never got the equivalent: something to open it automatically
3571
+ // on login too, not just right after an installer run.
3572
+ if (process.platform === 'darwin') {
3573
+ const plistPath = path.join(homeDir, 'Library', 'LaunchAgents', 'com.bdb.launchpad.plist');
3574
+ const plistContent = `<?xml version="1.0" encoding="UTF-8"?>
3575
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3576
+ <plist version="1.0">
3577
+ <dict>
3578
+ <key>Label</key>
3579
+ <string>com.bdb.launchpad</string>
3580
+ <key>ProgramArguments</key>
3581
+ <array>
3582
+ <string>open</string>
3583
+ <string>${filePath}</string>
3584
+ </array>
3585
+ <key>RunAtLoad</key>
3586
+ <true/>
3587
+ </dict>
3588
+ </plist>`;
3589
+ // Deliberately no KeepAlive: this launches a browser tab, not a
3590
+ // long-running service -- `open` exits the moment it's handed the
3591
+ // file to the browser, and KeepAlive would make launchd treat that
3592
+ // normal exit as a crash to restart, reopening the tab in a loop.
3593
+ try {
3594
+ fs.writeFileSync(plistPath, plistContent);
3595
+ execSync(`launchctl unload "${plistPath}" 2>/dev/null || true`, { stdio: 'ignore' });
3596
+ execSync(`launchctl load -w "${plistPath}" 2>/dev/null || true`, { stdio: 'ignore' });
3597
+ } catch (e) { logDebug(e, 'launchpad autostart plist'); }
3598
+ } else if (process.platform === 'win32') {
3599
+ const startupDir = path.join(process.env.APPDATA || path.join(homeDir, 'AppData', 'Roaming'), 'Microsoft', 'Windows', 'Start Menu', 'Programs', 'Startup');
3600
+ const vbsPath = path.join(startupDir, 'com.bdb.launchpad.vbs');
3601
+ const vbsContent = `Set WshShell = CreateObject("WScript.Shell")\r\nWshShell.Run """${filePath}""", 1, False\r\n`;
3602
+ try {
3603
+ fs.mkdirSync(startupDir, { recursive: true });
3604
+ fs.writeFileSync(vbsPath, vbsContent, 'utf-8');
3605
+ } catch (e) { logDebug(e, 'launchpad autostart vbs'); }
3606
+ }
3523
3607
  }
3524
3608
 
3525
3609
  async function universalHarnessSync(primaryMcpConfigPath) {
@@ -3704,12 +3788,17 @@ async function runQuickUpdate(installState) {
3704
3788
 
3705
3789
  console.log('');
3706
3790
  verifyEcosystemInstallation();
3791
+ // Fresh installs open this via universalHarnessSync(); Quick Update never
3792
+ // did, so a dev-workflow machine only ever saw it once, on day one --
3793
+ // every subsequent run is a Quick Update, which is what almost every
3794
+ // real run after the first actually is.
3795
+ generateAndOpenLaunchpad();
3707
3796
  }
3708
3797
 
3709
3798
 
3710
3799
  async function main() {
3711
3800
  const skipIntro = isAutoYes || process.argv.includes('--no-intro') || process.argv.includes('--no-animation');
3712
- await renderKineticIntro({ rotations: 1, fps: 12.5, skip: skipIntro });
3801
+ await renderKineticIntro({ rotations: 1, fps: 12.5, skip: skipIntro, pkgVersion: pkg.version });
3713
3802
  console.log(buildWordmarkBanner());
3714
3803
 
3715
3804
  const installState = detectInstallState();
package/lib/startup-ui.js CHANGED
@@ -19,7 +19,7 @@ const BRAND = {
19
19
  * Plays the 3D rotating BDB medallion kinetic intro in terminal.
20
20
  * Automatically clears frame buffer upon completion for smooth handoff to Clack.
21
21
  */
22
- async function renderKineticIntro({ rotations = 1, fps = 12.5, skip = false } = {}) {
22
+ async function renderKineticIntro({ rotations = 1, fps = 12.5, skip = false, pkgVersion = '4.0.0' } = {}) {
23
23
  if (skip || !process.stdout.isTTY) return;
24
24
 
25
25
  const frames = framesData.ansi;
@@ -27,7 +27,7 @@ async function renderKineticIntro({ rotations = 1, fps = 12.5, skip = false } =
27
27
  const totalFrames = Math.round(rotations * frames.length);
28
28
 
29
29
  // Clear terminal screen and hide cursor for a clean viewport
30
- process.stdout.write('\x1b]0;BDB Agent OS · AOS Installer v4.0.0\x07');
30
+ process.stdout.write(`\x1b]0;BDB Agent OS · AOS Installer v${pkgVersion}\x07`);
31
31
  process.stdout.write('\x1b[2J\x1b[H\x1b[?25l');
32
32
 
33
33
  return new Promise((resolve) => {
@@ -41,7 +41,7 @@ async function renderKineticIntro({ rotations = 1, fps = 12.5, skip = false } =
41
41
  '\x1b[H',
42
42
  ...lines.map(line => '\x1b[2K' + line),
43
43
  '\x1b[2K',
44
- `\x1b[2K ${BRAND.lila}${BRAND.bold}━━━ BDB AGENT OS ━━━${BRAND.reset} ${BRAND.white}${BRAND.bold}AOS Kernel v4.0.0${BRAND.reset} ${BRAND.dim}· Initializing runtime...${BRAND.reset}`
44
+ `\x1b[2K ${BRAND.lila}${BRAND.bold}━━━ BDB AGENT OS ━━━${BRAND.reset} ${BRAND.white}${BRAND.bold}AOS Kernel v${pkgVersion}${BRAND.reset} ${BRAND.dim}· Initializing runtime...${BRAND.reset}`
45
45
  ].join('\n');
46
46
 
47
47
  process.stdout.write(buffer);
package/package.json CHANGED
@@ -1,8 +1,11 @@
1
1
  {
2
2
  "name": "@hybridlabor-api/aos",
3
- "version": "4.4.2-beta.5",
3
+ "version": "4.4.2-beta.7",
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
+ "engines": {
7
+ "node": ">=20"
8
+ },
6
9
  "bin": {
7
10
  "aos": "installer.js",
8
11
  "bdb-dev-optimized-agent-skills": "installer.js",