Lines 1-62javascript
1import { execFile, execFileSync, spawn } from 'child_process';
2import { writeFileSync, mkdirSync, existsSync } from 'fs';
3import { fileURLToPath } from 'url';
4import { join, dirname } from 'path';
5import { platform, homedir } from 'os';
6import ctx from '../context.js';
7import { getConfigDir, getServiceName, getPm2AppName, getLaunchdPlistPath, DEFAULT_INSTANCE_ID } from '../service.js';
9 buildUpgradeInstallCommand,
10 buildUpgradeMetadataArgs,
11 buildContainerImageUpgradeMessage,
12 CONTAINER_AGENT_CAPABILITY,
13 CONTAINER_IMAGE_UPGRADE_REASON,
14 isContainerAgentRuntime,
15 createWindowsUpgradeRun,
16 launchWindowsUpgradeScript,
17 prepareWindowsUpgradeRunner,
18 releaseWindowsUpgradeLock,
19 resolveWindowsNpmCliPath,
20 resolveWindowsPm2CliPath,
21} from '../upgrade-command.js';
22import { sendToServer } from './buffer.js';
23import { stopAgentHeartbeat } from './heartbeat.js';
26 * Resolve the local service instance id for this running agent. Each agent
27 * process is pinned to one instance (set in index.js from
28 * YEAFT_AGENT_INSTANCE / config), so the upgrade flow must target THAT
29 * instance's service unit — not the bare `yeaft-agent` default. Without this,
30 * a named instance (e.g. `server-e7a9eb`) installs the new package but its
31 * systemd unit `yeaft-agent@server-e7a9eb` is never restarted, leaving the
32 * agent permanently offline after a UI-triggered upgrade.
34export function resolveInstanceId() {
35 return ctx.CONFIG?.instanceId || process.env.YEAFT_AGENT_INSTANCE || DEFAULT_INSTANCE_ID;
38// Derive absolute paths for npm/pm2 from current node executable.
39// In launchd/systemd environments, PATH may not include nvm/node dirs,
40// but process.execPath always points to the running node binary.
41const nodeBinDir = dirname(process.execPath);
42const isWin = platform() === 'win32';
43// Windows: use bare 'npm'/'pm2' + shell:true — cmd.exe finds them via PATH.
44// This was the working pattern before ce58bbc. Absolute paths break when
MediumInstall Persistence
Source writes installer persistence such as shell profile or service configuration.
connection/upgrade.jsView on unpkg · L1 45// the path contains spaces (e.g., "C:\Program Files\nodejs\npm.cmd").
46// macOS/Linux: use absolute path — launchd/systemd have minimal PATH.
47const npmPath = isWin ? 'npm' : join(nodeBinDir, 'npm');
48const pm2Path = isWin ? 'pm2' : join(nodeBinDir, 'pm2');
49const shellOpt = isWin ? { shell: true, windowsHide: true } : {};
51// Ensure PATH includes nodeBinDir so that `#!/usr/bin/env node` shebangs
52// can locate node in launchd/systemd environments with minimal PATH.
53const currentPath = process.env.PATH || '/usr/bin:/bin:/usr/sbin:/sbin';
54const safePath = currentPath.includes(nodeBinDir) ? currentPath : `${nodeBinDir}:${currentPath}`;
55const safeEnv = { ...process.env, PATH: safePath };
57/** Return true only when `latestVersion` is semantically newer. */
58export function isUpgradeAvailable(currentVersion, latestVersion) {
59 const current = parseSemver(currentVersion);
60 const latest = parseSemver(latestVersion);
61 if (!current || !latest) return currentVersion !== latestVersion;
62 return cmpTuple(latest, current) > 0;