@songsid/agend 2.0.8-beta.16 → 2.0.8-beta.18
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 +126 -48
- package/dist/cli.js.map +1 -1
- package/dist/daemon.js +17 -0
- package/dist/daemon.js.map +1 -1
- package/dist/fleet-manager.d.ts +7 -0
- package/dist/fleet-manager.js +77 -4
- package/dist/fleet-manager.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -131,12 +131,40 @@ fleet
|
|
|
131
131
|
.argument("[instance]", "Specific instance to stop")
|
|
132
132
|
.action(async (instance) => {
|
|
133
133
|
if (instance) {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
134
|
+
// Stop a single instance via the RUNNING fleet's HTTP API. Do NOT spawn a
|
|
135
|
+
// detached FleetManager and call stopInstance(): its in-memory daemons map
|
|
136
|
+
// is empty, so lifecycle.stop falls back to reading the instance's
|
|
137
|
+
// daemon.pid — which is the shared fleet process pid (daemons run
|
|
138
|
+
// in-process) — and SIGTERMs the whole fleet.
|
|
139
|
+
const { loadFleetConfig } = await import("./config.js");
|
|
140
|
+
const fleet = loadFleetConfig(FLEET_CONFIG_PATH);
|
|
141
|
+
const port = fleet.health_port ?? 19280;
|
|
142
|
+
let token = "";
|
|
143
|
+
try {
|
|
144
|
+
token = readFileSync(join(DATA_DIR, "web.token"), "utf-8").trim();
|
|
145
|
+
}
|
|
146
|
+
catch { /* fleet may not be running */ }
|
|
147
|
+
try {
|
|
148
|
+
const resp = await fetch(`http://127.0.0.1:${port}/stop/${encodeURIComponent(instance)}`, {
|
|
149
|
+
method: "POST",
|
|
150
|
+
headers: token ? { "X-Agend-Token": token } : {},
|
|
151
|
+
});
|
|
152
|
+
const body = await resp.json().catch(() => ({}));
|
|
153
|
+
if (resp.ok) {
|
|
154
|
+
console.log(`Instance "${instance}" stopped`);
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
console.error(`Stop failed: ${body.error ?? resp.statusText}`);
|
|
158
|
+
process.exit(1);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
console.error(`Cannot connect to fleet (port ${port}). Is the fleet running?`);
|
|
163
|
+
process.exit(1);
|
|
164
|
+
}
|
|
165
|
+
return;
|
|
138
166
|
}
|
|
139
|
-
|
|
167
|
+
{
|
|
140
168
|
const pidPath = join(DATA_DIR, "fleet.pid");
|
|
141
169
|
if (!existsSync(pidPath)) {
|
|
142
170
|
console.error("Fleet is not running (no PID file found)");
|
|
@@ -185,8 +213,16 @@ fleet
|
|
|
185
213
|
const { loadFleetConfig } = await import("./config.js");
|
|
186
214
|
const fleet = loadFleetConfig(FLEET_CONFIG_PATH);
|
|
187
215
|
const port = fleet.health_port ?? 19280;
|
|
216
|
+
let token = "";
|
|
188
217
|
try {
|
|
189
|
-
|
|
218
|
+
token = readFileSync(join(DATA_DIR, "web.token"), "utf-8").trim();
|
|
219
|
+
}
|
|
220
|
+
catch { /* fleet may not be running */ }
|
|
221
|
+
try {
|
|
222
|
+
const resp = await fetch(`http://127.0.0.1:${port}/restart/${encodeURIComponent(instance)}`, {
|
|
223
|
+
method: "POST",
|
|
224
|
+
headers: token ? { "X-Agend-Token": token } : {},
|
|
225
|
+
});
|
|
190
226
|
const body = await resp.json();
|
|
191
227
|
if (resp.ok) {
|
|
192
228
|
console.log(`Instance "${instance}" restarted (immediate)`);
|
|
@@ -1156,69 +1192,111 @@ program
|
|
|
1156
1192
|
}
|
|
1157
1193
|
}
|
|
1158
1194
|
// ── Restart fleet ──
|
|
1195
|
+
// Try each runtime environment in order and stop at the first that succeeds.
|
|
1196
|
+
// We no longer gate on fleet.pid existence: a fleet running under systemd or
|
|
1197
|
+
// launchd writes its pid in the service's own HOME, which may differ from the
|
|
1198
|
+
// path this command resolves (sudo, AGEND_HOME, etc.) — so an absent pid file
|
|
1199
|
+
// does NOT mean the fleet is stopped. Ask the service manager first.
|
|
1159
1200
|
const pidPath = join(DATA_DIR, "fleet.pid");
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
return;
|
|
1163
|
-
}
|
|
1164
|
-
// Kill old fleet process first to prevent duplicate
|
|
1165
|
-
const oldPid = parseInt(readFileSync(pidPath, "utf-8").trim(), 10);
|
|
1166
|
-
if (oldPid) {
|
|
1201
|
+
console.log(" Restarting fleet...");
|
|
1202
|
+
const isActive = (cmd) => {
|
|
1167
1203
|
try {
|
|
1168
|
-
|
|
1204
|
+
return spawnSync("sh", ["-c", cmd], { encoding: "utf-8", timeout: 5000 }).stdout?.trim() === "active";
|
|
1169
1205
|
}
|
|
1170
|
-
catch {
|
|
1171
|
-
|
|
1172
|
-
for (let i = 0; i < 20; i++) {
|
|
1173
|
-
try {
|
|
1174
|
-
process.kill(oldPid, 0);
|
|
1175
|
-
}
|
|
1176
|
-
catch {
|
|
1177
|
-
break;
|
|
1178
|
-
}
|
|
1179
|
-
spawnSync("sleep", ["0.5"]);
|
|
1206
|
+
catch {
|
|
1207
|
+
return false;
|
|
1180
1208
|
}
|
|
1181
|
-
|
|
1209
|
+
};
|
|
1210
|
+
const run = (cmd) => {
|
|
1182
1211
|
try {
|
|
1183
|
-
|
|
1212
|
+
execSync(cmd, { stdio: "inherit", timeout: 15000 });
|
|
1213
|
+
return true;
|
|
1214
|
+
}
|
|
1215
|
+
catch {
|
|
1216
|
+
return false;
|
|
1184
1217
|
}
|
|
1185
|
-
|
|
1218
|
+
};
|
|
1219
|
+
// 1. System-level systemd service "agend"
|
|
1220
|
+
if (plat !== "macos" && isActive("systemctl is-active agend 2>/dev/null")) {
|
|
1221
|
+
run("systemctl daemon-reload");
|
|
1222
|
+
if (run("systemctl restart agend")) {
|
|
1223
|
+
console.log(" ✓ Service restarted (system)\n");
|
|
1224
|
+
return;
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
// 2. User-level systemd service "com.agend.fleet"
|
|
1228
|
+
if (plat !== "macos" && isActive("systemctl --user is-active com.agend.fleet 2>/dev/null")) {
|
|
1229
|
+
run("systemctl --user daemon-reload");
|
|
1186
1230
|
try {
|
|
1187
|
-
|
|
1231
|
+
execSync("systemctl --user reset-failed com.agend.fleet", { stdio: "pipe", timeout: 5000 });
|
|
1188
1232
|
}
|
|
1189
1233
|
catch { /* best effort */ }
|
|
1234
|
+
if (run("systemctl --user restart com.agend.fleet")) {
|
|
1235
|
+
console.log(" ✓ Service restarted (user)\n");
|
|
1236
|
+
return;
|
|
1237
|
+
}
|
|
1190
1238
|
}
|
|
1191
|
-
|
|
1239
|
+
// 3. launchd (macOS)
|
|
1192
1240
|
if (plat === "macos") {
|
|
1193
1241
|
const uid = process.getuid?.() ?? 501;
|
|
1194
1242
|
const label = "com.agend.fleet";
|
|
1195
1243
|
try {
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1244
|
+
// print succeeds only if the service is loaded in launchd
|
|
1245
|
+
execSync(`launchctl print gui/${uid}/${label}`, { stdio: "pipe", timeout: 5000 });
|
|
1246
|
+
if (run(`launchctl kickstart -k gui/${uid}/${label}`)) {
|
|
1247
|
+
console.log(" ✓ Service restarted\n");
|
|
1248
|
+
return;
|
|
1249
|
+
}
|
|
1199
1250
|
}
|
|
1200
|
-
catch { /*
|
|
1251
|
+
catch { /* not loaded — fall through */ }
|
|
1201
1252
|
}
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1253
|
+
// 4. Detached process tracked by fleet.pid (no service manager)
|
|
1254
|
+
if (existsSync(pidPath)) {
|
|
1255
|
+
const oldPid = parseInt(readFileSync(pidPath, "utf-8").trim(), 10);
|
|
1256
|
+
let alive = false;
|
|
1257
|
+
if (oldPid) {
|
|
1206
1258
|
try {
|
|
1207
|
-
|
|
1259
|
+
process.kill(oldPid, 0);
|
|
1260
|
+
alive = true;
|
|
1208
1261
|
}
|
|
1209
|
-
catch { }
|
|
1210
|
-
|
|
1211
|
-
|
|
1262
|
+
catch { /* dead or not ours */ }
|
|
1263
|
+
}
|
|
1264
|
+
if (alive) {
|
|
1265
|
+
try {
|
|
1266
|
+
process.kill(oldPid, "SIGTERM");
|
|
1267
|
+
}
|
|
1268
|
+
catch { /* already gone */ }
|
|
1269
|
+
// Wait up to 10s for the old process to exit
|
|
1270
|
+
for (let i = 0; i < 20; i++) {
|
|
1271
|
+
try {
|
|
1272
|
+
process.kill(oldPid, 0);
|
|
1273
|
+
}
|
|
1274
|
+
catch {
|
|
1275
|
+
break;
|
|
1276
|
+
}
|
|
1277
|
+
spawnSync("sleep", ["0.5"]);
|
|
1278
|
+
}
|
|
1279
|
+
try {
|
|
1280
|
+
process.kill(oldPid, "SIGKILL");
|
|
1281
|
+
}
|
|
1282
|
+
catch { /* already gone */ }
|
|
1283
|
+
try {
|
|
1284
|
+
unlinkSync(pidPath);
|
|
1285
|
+
}
|
|
1286
|
+
catch { /* best effort */ }
|
|
1287
|
+
const child = spawnAsync(agendPath, ["fleet", "start"], { detached: true, stdio: "ignore" });
|
|
1288
|
+
child.unref();
|
|
1289
|
+
console.log(" ✓ Fleet restarting in background\n");
|
|
1212
1290
|
return;
|
|
1213
1291
|
}
|
|
1214
|
-
|
|
1292
|
+
// Stale pid file (process gone) — clean it up before declaring stopped.
|
|
1293
|
+
try {
|
|
1294
|
+
unlinkSync(pidPath);
|
|
1295
|
+
}
|
|
1296
|
+
catch { /* best effort */ }
|
|
1215
1297
|
}
|
|
1216
|
-
//
|
|
1217
|
-
|
|
1218
|
-
detached: true, stdio: "ignore",
|
|
1219
|
-
});
|
|
1220
|
-
child.unref();
|
|
1221
|
-
console.log(" ✓ Fleet restarting in background\n");
|
|
1298
|
+
// 5. Nothing running anywhere
|
|
1299
|
+
console.log("\n Fleet not running. Start with: agend start\n");
|
|
1222
1300
|
});
|
|
1223
1301
|
program
|
|
1224
1302
|
.command("reload")
|