@songsid/agend 2.1.2-beta.39 → 2.1.2-beta.40
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/dist/cli.js +51 -20
- package/dist/cli.js.map +1 -1
- package/dist/fleet-lock.d.ts +28 -0
- package/dist/fleet-lock.js +130 -0
- package/dist/fleet-lock.js.map +1 -0
- package/dist/fleet-manager.js +4 -0
- package/dist/fleet-manager.js.map +1 -1
- package/dist/instance-lifecycle.d.ts +1 -2
- package/dist/instance-lifecycle.js +2 -5
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/service-installer.d.ts +16 -0
- package/dist/service-installer.js +56 -1
- package/dist/service-installer.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -17,6 +17,7 @@ import { PIE_PERCENT_RE } from "./tui-glyphs.js";
|
|
|
17
17
|
import { COMPLETION_SHELLS, completionScript } from "./completion.js";
|
|
18
18
|
import { getUpdateSelector, lookupTargetVersion, reportUpdateRestart, shouldSkipUpdate, } from "./update-check.js";
|
|
19
19
|
import { clearUpdateMarker, markUpdateInProgress } from "./update-marker.js";
|
|
20
|
+
import { acquireFleetLock, releaseProcessFleetLock, setProcessFleetLock } from "./fleet-lock.js";
|
|
20
21
|
/** Prefix tmux args with -L when socket isolation is active. */
|
|
21
22
|
function tmuxArgs(args) {
|
|
22
23
|
const socket = getTmuxSocketName();
|
|
@@ -27,6 +28,18 @@ const __dirname = dirname(__filename);
|
|
|
27
28
|
const DATA_DIR = getAgendHome();
|
|
28
29
|
const FLEET_CONFIG_PATH = join(DATA_DIR, "fleet.yaml");
|
|
29
30
|
const program = new Command();
|
|
31
|
+
function claimFleetSingleton() {
|
|
32
|
+
try {
|
|
33
|
+
setProcessFleetLock(acquireFleetLock(DATA_DIR));
|
|
34
|
+
process.once("exit", () => { releaseProcessFleetLock(); });
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
console.error(err.message);
|
|
39
|
+
process.exitCode = 1;
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
30
43
|
// Read version from package.json at build time
|
|
31
44
|
const pkgVersion = (() => {
|
|
32
45
|
try {
|
|
@@ -98,6 +111,10 @@ fleet
|
|
|
98
111
|
}
|
|
99
112
|
catch { /* fleet not running, fall through */ }
|
|
100
113
|
}
|
|
114
|
+
// Claim the singleton before constructing FleetManager: its constructor and
|
|
115
|
+
// startAll path touch shared tmux, sockets, state files and adapters.
|
|
116
|
+
if (!claimFleetSingleton())
|
|
117
|
+
return;
|
|
101
118
|
const { FleetManager } = await import("./fleet-manager.js");
|
|
102
119
|
const fm = new FleetManager(DATA_DIR);
|
|
103
120
|
// Register crash/signal handlers BEFORE startAll(). Startup routinely takes
|
|
@@ -356,6 +373,8 @@ fleet
|
|
|
356
373
|
}
|
|
357
374
|
console.log("Old fleet stopped. Starting with new code...");
|
|
358
375
|
// Start new fleet in this process (new Node.js process = new code loaded)
|
|
376
|
+
if (!claimFleetSingleton())
|
|
377
|
+
return;
|
|
359
378
|
const { FleetManager } = await import("./fleet-manager.js");
|
|
360
379
|
const fm = new FleetManager(DATA_DIR);
|
|
361
380
|
await fm.startAll(FLEET_CONFIG_PATH);
|
|
@@ -1379,8 +1398,10 @@ program
|
|
|
1379
1398
|
.command("start")
|
|
1380
1399
|
.description("Start the AgEnD service (must be installed first)")
|
|
1381
1400
|
.action(async () => {
|
|
1382
|
-
const { getServicePath, startService } = await import("./service-installer.js");
|
|
1383
|
-
|
|
1401
|
+
const { getServicePath, getSystemServicePath, startService, startSystemService } = await import("./service-installer.js");
|
|
1402
|
+
const userServicePath = getServicePath();
|
|
1403
|
+
const systemServicePath = getSystemServicePath();
|
|
1404
|
+
if (!userServicePath && !systemServicePath) {
|
|
1384
1405
|
console.log("No service installed. Starting fleet directly...");
|
|
1385
1406
|
const { spawn } = await import("node:child_process");
|
|
1386
1407
|
const child = spawn("sh", ["-c", "agend fleet start"], { detached: true, stdio: "ignore" });
|
|
@@ -1388,16 +1409,16 @@ program
|
|
|
1388
1409
|
console.log("Fleet starting in background.");
|
|
1389
1410
|
return;
|
|
1390
1411
|
}
|
|
1391
|
-
|
|
1412
|
+
const started = systemServicePath ? startSystemService() : startService();
|
|
1413
|
+
if (started) {
|
|
1392
1414
|
console.log("Service started.");
|
|
1393
1415
|
}
|
|
1394
1416
|
else {
|
|
1395
|
-
//
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
console.log("Fleet starting in background.");
|
|
1417
|
+
// A service file means the service manager owns this fleet. Falling back
|
|
1418
|
+
// to a detached process here creates a second fleet when the bus recovers.
|
|
1419
|
+
console.error("Failed to start the installed AgEnD service; refusing to start a detached duplicate.");
|
|
1420
|
+
console.error("Check your service manager, then retry: systemctl --user status com.agend.fleet");
|
|
1421
|
+
process.exitCode = 1;
|
|
1401
1422
|
}
|
|
1402
1423
|
});
|
|
1403
1424
|
program
|
|
@@ -1409,18 +1430,10 @@ program
|
|
|
1409
1430
|
// service's own HOME, which may differ from what this command resolves (sudo,
|
|
1410
1431
|
// AGEND_HOME) — an absent pid file does NOT mean it's stopped. Ask the service
|
|
1411
1432
|
// manager first. This is the canonical restart the `update` flow spawns.
|
|
1412
|
-
const { detectPlatform } = await import("./service-installer.js");
|
|
1433
|
+
const { detectPlatform, getServicePath, getSystemServicePath, getSystemdServiceState } = await import("./service-installer.js");
|
|
1413
1434
|
const { spawn, spawnSync } = await import("node:child_process");
|
|
1414
1435
|
const plat = detectPlatform();
|
|
1415
1436
|
const pidPath = join(DATA_DIR, "fleet.pid");
|
|
1416
|
-
const isActive = (cmd) => {
|
|
1417
|
-
try {
|
|
1418
|
-
return spawnSync("sh", ["-c", cmd], { encoding: "utf-8", timeout: 5000 }).stdout?.trim() === "active";
|
|
1419
|
-
}
|
|
1420
|
-
catch {
|
|
1421
|
-
return false;
|
|
1422
|
-
}
|
|
1423
|
-
};
|
|
1424
1437
|
const run = (cmd) => {
|
|
1425
1438
|
try {
|
|
1426
1439
|
execSync(cmd, { stdio: "inherit", timeout: 15000 });
|
|
@@ -1431,7 +1444,15 @@ program
|
|
|
1431
1444
|
}
|
|
1432
1445
|
};
|
|
1433
1446
|
// 1. System-level systemd service "agend"
|
|
1434
|
-
|
|
1447
|
+
const systemServiceInstalled = plat !== "macos" && getSystemServicePath() !== null;
|
|
1448
|
+
const systemState = plat !== "macos" ? getSystemdServiceState("agend", false) : "stopped";
|
|
1449
|
+
if (systemServiceInstalled && systemState === "unavailable") {
|
|
1450
|
+
console.error("Cannot reach the system service manager; refusing a detached restart that could duplicate the fleet.");
|
|
1451
|
+
console.error("Check: systemctl status agend");
|
|
1452
|
+
process.exitCode = 1;
|
|
1453
|
+
return;
|
|
1454
|
+
}
|
|
1455
|
+
if (systemServiceInstalled && (systemState === "running" || systemState === "stopped")) {
|
|
1435
1456
|
run("systemctl daemon-reload");
|
|
1436
1457
|
if (run("systemctl restart agend")) {
|
|
1437
1458
|
console.log("Service restarted (system).");
|
|
@@ -1443,7 +1464,17 @@ program
|
|
|
1443
1464
|
return;
|
|
1444
1465
|
}
|
|
1445
1466
|
// 2. User-level systemd service "com.agend.fleet"
|
|
1446
|
-
|
|
1467
|
+
const userServiceInstalled = plat !== "macos" && getServicePath() !== null;
|
|
1468
|
+
const userState = plat !== "macos"
|
|
1469
|
+
? getSystemdServiceState("com.agend.fleet", true)
|
|
1470
|
+
: "stopped";
|
|
1471
|
+
if (userServiceInstalled && userState === "unavailable") {
|
|
1472
|
+
console.error("Cannot reach the user service manager; refusing a detached restart that could duplicate the fleet.");
|
|
1473
|
+
console.error("Check: systemctl --user status com.agend.fleet");
|
|
1474
|
+
process.exitCode = 1;
|
|
1475
|
+
return;
|
|
1476
|
+
}
|
|
1477
|
+
if (userServiceInstalled && (userState === "running" || userState === "stopped")) {
|
|
1447
1478
|
run("systemctl --user daemon-reload");
|
|
1448
1479
|
try {
|
|
1449
1480
|
execSync("systemctl --user reset-failed com.agend.fleet", { stdio: "pipe", timeout: 5000 });
|