@termhub/agent 0.2.1 → 0.2.2
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/README.md +7 -0
- package/dist/cli.js +41 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -35,6 +35,13 @@ starts the agent at login/boot and restarts it on failure. `termhub-agent servic
|
|
|
35
35
|
`termhub-agent service uninstall` manage it afterwards. On Linux, run
|
|
36
36
|
`loginctl enable-linger $USER` once so the service keeps running after you log out.
|
|
37
37
|
|
|
38
|
+
The service is deliberately kept apart from the tmux server that holds your terminals: on Linux
|
|
39
|
+
the unit sets `KillMode=process`, so restarting or updating the agent signals only the agent
|
|
40
|
+
itself and leaves tmux — and whatever is running inside it — alone, and the agent reattaches to
|
|
41
|
+
the existing sessions when it comes back (macOS needs nothing: launchd does not follow tmux once
|
|
42
|
+
it daemonises). A unit installed by an older agent is rewritten to the current template the first
|
|
43
|
+
time the new agent starts.
|
|
44
|
+
|
|
38
45
|
## Other commands
|
|
39
46
|
|
|
40
47
|
- `termhub-agent status` — shows the paired server, machine name and whether the agent can reach
|
package/dist/cli.js
CHANGED
|
@@ -1267,15 +1267,15 @@ function renderPlist({ label, node, script, logPath }) {
|
|
|
1267
1267
|
</plist>
|
|
1268
1268
|
`;
|
|
1269
1269
|
}
|
|
1270
|
-
function plistPath() {
|
|
1271
|
-
return path6.join(
|
|
1270
|
+
function plistPath(home = os4.homedir()) {
|
|
1271
|
+
return path6.join(home, "Library", "LaunchAgents", `${LABEL}.plist`);
|
|
1272
1272
|
}
|
|
1273
1273
|
function gui() {
|
|
1274
1274
|
return `gui/${process.getuid ? process.getuid() : 0}`;
|
|
1275
1275
|
}
|
|
1276
1276
|
async function install2(opts, deps = {}) {
|
|
1277
1277
|
const runFn = deps.run ?? run;
|
|
1278
|
-
const file = plistPath();
|
|
1278
|
+
const file = plistPath(deps.home);
|
|
1279
1279
|
const plist = renderPlist({ label: LABEL, node: opts.node, script: opts.script, logPath: opts.logPath });
|
|
1280
1280
|
fs4.mkdirSync(path6.dirname(file), { recursive: true });
|
|
1281
1281
|
fs4.writeFileSync(file, plist, "utf8");
|
|
@@ -1287,7 +1287,7 @@ async function install2(opts, deps = {}) {
|
|
|
1287
1287
|
}
|
|
1288
1288
|
async function uninstall2(deps = {}) {
|
|
1289
1289
|
const runFn = deps.run ?? run;
|
|
1290
|
-
const file = plistPath();
|
|
1290
|
+
const file = plistPath(deps.home);
|
|
1291
1291
|
await runFn("launchctl", ["bootout", gui(), file]);
|
|
1292
1292
|
try {
|
|
1293
1293
|
fs4.unlinkSync(file);
|
|
@@ -1315,7 +1315,7 @@ import fs5 from "fs";
|
|
|
1315
1315
|
import os5 from "os";
|
|
1316
1316
|
import path7 from "path";
|
|
1317
1317
|
var UNIT_NAME = "termhub-agent";
|
|
1318
|
-
function renderUnit({ node, script, logPath }) {
|
|
1318
|
+
function renderUnit({ node, script, logPath, pathEnv }) {
|
|
1319
1319
|
const lines = [
|
|
1320
1320
|
"[Unit]",
|
|
1321
1321
|
"Description=termhub agent",
|
|
@@ -1323,10 +1323,11 @@ function renderUnit({ node, script, logPath }) {
|
|
|
1323
1323
|
"",
|
|
1324
1324
|
"[Service]",
|
|
1325
1325
|
`ExecStart=${node} ${script} run`,
|
|
1326
|
+
"KillMode=process",
|
|
1326
1327
|
"Restart=on-failure",
|
|
1327
1328
|
"RestartSec=2",
|
|
1328
1329
|
"RestartPreventExitStatus=78",
|
|
1329
|
-
`Environment=PATH=${agentEnv().PATH ?? ""}`
|
|
1330
|
+
`Environment=PATH=${pathEnv ?? agentEnv().PATH ?? ""}`
|
|
1330
1331
|
];
|
|
1331
1332
|
if (logPath) {
|
|
1332
1333
|
lines.push(`StandardOutput=append:${logPath}`, `StandardError=append:${logPath}`);
|
|
@@ -1334,12 +1335,12 @@ function renderUnit({ node, script, logPath }) {
|
|
|
1334
1335
|
lines.push("", "[Install]", "WantedBy=default.target", "");
|
|
1335
1336
|
return lines.join("\n");
|
|
1336
1337
|
}
|
|
1337
|
-
function unitPath() {
|
|
1338
|
-
return path7.join(
|
|
1338
|
+
function unitPath(home = os5.homedir()) {
|
|
1339
|
+
return path7.join(home, ".config", "systemd", "user", `${UNIT_NAME}.service`);
|
|
1339
1340
|
}
|
|
1340
1341
|
async function install3(opts, deps = {}) {
|
|
1341
1342
|
const runFn = deps.run ?? run;
|
|
1342
|
-
const file = unitPath();
|
|
1343
|
+
const file = unitPath(deps.home);
|
|
1343
1344
|
const unit = renderUnit({ node: opts.node, script: opts.script, logPath: opts.logPath });
|
|
1344
1345
|
fs5.mkdirSync(path7.dirname(file), { recursive: true });
|
|
1345
1346
|
fs5.writeFileSync(file, unit, "utf8");
|
|
@@ -1349,11 +1350,31 @@ async function install3(opts, deps = {}) {
|
|
|
1349
1350
|
if (enable.code !== 0) throw new Error(`systemctl enable --now failed (code ${enable.code}): ${enable.stderr.trim()}`);
|
|
1350
1351
|
console.log("Para o agente continuar ap\xF3s o logout: loginctl enable-linger $USER");
|
|
1351
1352
|
}
|
|
1353
|
+
function unitPathEnv(unit) {
|
|
1354
|
+
return /^Environment=PATH=(.*)$/m.exec(unit)?.[1];
|
|
1355
|
+
}
|
|
1356
|
+
async function refreshUnit(opts, deps = {}) {
|
|
1357
|
+
const file = unitPath(deps.home);
|
|
1358
|
+
let current;
|
|
1359
|
+
try {
|
|
1360
|
+
current = fs5.readFileSync(file, "utf8");
|
|
1361
|
+
} catch (err) {
|
|
1362
|
+
if (err.code === "ENOENT") return false;
|
|
1363
|
+
throw err;
|
|
1364
|
+
}
|
|
1365
|
+
const unit = renderUnit({ node: opts.node, script: opts.script, logPath: opts.logPath, pathEnv: unitPathEnv(current) });
|
|
1366
|
+
if (unit === current) return false;
|
|
1367
|
+
fs5.writeFileSync(file, unit, "utf8");
|
|
1368
|
+
const runFn = deps.run ?? run;
|
|
1369
|
+
const reload = await runFn("systemctl", ["--user", "daemon-reload"]);
|
|
1370
|
+
if (reload.code !== 0) throw new Error(`systemctl daemon-reload failed (code ${reload.code}): ${reload.stderr.trim()}`);
|
|
1371
|
+
return true;
|
|
1372
|
+
}
|
|
1352
1373
|
async function uninstall3(deps = {}) {
|
|
1353
1374
|
const runFn = deps.run ?? run;
|
|
1354
1375
|
await runFn("systemctl", ["--user", "disable", "--now", UNIT_NAME]);
|
|
1355
1376
|
try {
|
|
1356
|
-
fs5.unlinkSync(unitPath());
|
|
1377
|
+
fs5.unlinkSync(unitPath(deps.home));
|
|
1357
1378
|
} catch (err) {
|
|
1358
1379
|
if (err.code !== "ENOENT") throw err;
|
|
1359
1380
|
}
|
|
@@ -1383,6 +1404,10 @@ async function install4() {
|
|
|
1383
1404
|
if (platform === "darwin") await install2(opts);
|
|
1384
1405
|
else await install3(opts);
|
|
1385
1406
|
}
|
|
1407
|
+
async function refresh() {
|
|
1408
|
+
if (process.platform !== "linux") return false;
|
|
1409
|
+
return refreshUnit(serviceFileOptions());
|
|
1410
|
+
}
|
|
1386
1411
|
async function uninstall4() {
|
|
1387
1412
|
const platform = process.platform;
|
|
1388
1413
|
assertSupported(platform);
|
|
@@ -1397,7 +1422,7 @@ async function status3() {
|
|
|
1397
1422
|
}
|
|
1398
1423
|
|
|
1399
1424
|
// src/version.ts
|
|
1400
|
-
var AGENT_VERSION = "0.2.
|
|
1425
|
+
var AGENT_VERSION = "0.2.2";
|
|
1401
1426
|
|
|
1402
1427
|
// src/rpc/update.ts
|
|
1403
1428
|
var PACKAGE = "@termhub/agent";
|
|
@@ -1766,6 +1791,11 @@ async function runCommand(log2) {
|
|
|
1766
1791
|
if (!config) {
|
|
1767
1792
|
return exitWithoutRestart("Nenhuma configura\xE7\xE3o. Rode: termhub-agent connect --url <url>");
|
|
1768
1793
|
}
|
|
1794
|
+
try {
|
|
1795
|
+
if (await refresh()) log2("service definition refreshed");
|
|
1796
|
+
} catch (err) {
|
|
1797
|
+
log2("service definition could not be refreshed", { error: err instanceof Error ? err.message : String(err) });
|
|
1798
|
+
}
|
|
1769
1799
|
await runForegroundUntilSignal(config, log2);
|
|
1770
1800
|
}
|
|
1771
1801
|
|
package/package.json
CHANGED