herdr-remote 0.2.18 → 0.2.20
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/bin/herdr-remote.js +3 -225
- package/dist/agent-status.js +130 -0
- package/dist/binary-plist.js +157 -0
- package/dist/cli.js +255 -0
- package/dist/config.js +270 -0
- package/dist/connector/agent-watch.js +110 -0
- package/dist/connector/font-server.js +165 -0
- package/dist/connector/host-connector.js +430 -0
- package/dist/connector/lock.js +66 -0
- package/dist/connector/main.js +18 -0
- package/dist/connector/sessions.js +366 -0
- package/dist/connector/update-report.js +67 -0
- package/dist/connector/wire.js +42 -0
- package/{src → dist}/exit-codes.js +1 -4
- package/dist/font-subset.js +110 -0
- package/dist/herdr-api.js +246 -0
- package/dist/herdr-command.js +223 -0
- package/dist/herdr-plugin.js +116 -0
- package/dist/herdr-server.js +189 -0
- package/dist/i18n/en.js +223 -0
- package/dist/i18n/index.js +48 -0
- package/dist/i18n/zh.js +222 -0
- package/dist/keepalive/detached.js +78 -0
- package/dist/keepalive/environment.js +44 -0
- package/dist/keepalive/index.js +110 -0
- package/dist/keepalive/launchd.js +117 -0
- package/dist/keepalive/systemd.js +108 -0
- package/dist/keepalive/types.js +1 -0
- package/dist/lib/process.js +12 -0
- package/dist/lifecycle.js +59 -0
- package/dist/net-interfaces.js +73 -0
- package/dist/pasted-files.js +115 -0
- package/dist/paths.js +62 -0
- package/dist/pty-session.js +96 -0
- package/dist/relay-client.js +106 -0
- package/dist/relay-urls.js +99 -0
- package/dist/runtime.js +106 -0
- package/dist/service.js +260 -0
- package/dist/settings-model.js +298 -0
- package/dist/socket-discovery.js +48 -0
- package/dist/supervisor.js +319 -0
- package/dist/terminal-font/deps.js +73 -0
- package/dist/terminal-font/files.js +354 -0
- package/dist/terminal-font/formats.js +335 -0
- package/dist/terminal-font/index.js +187 -0
- package/dist/terminal-font/readers.js +316 -0
- package/dist/terminal-font/terminals.js +128 -0
- package/dist/terminal-palette.js +339 -0
- package/dist/tui/App.js +195 -0
- package/dist/tui/api.js +79 -0
- package/dist/tui/components/TextField.js +50 -0
- package/dist/tui/components/common.js +80 -0
- package/dist/tui/index.js +36 -0
- package/dist/tui/mouse/index.js +164 -0
- package/dist/tui/mouse/protocol.js +96 -0
- package/dist/tui/mouse/source.js +74 -0
- package/dist/tui/screens/About.js +166 -0
- package/dist/tui/screens/Herdr.js +74 -0
- package/dist/tui/screens/Keepalive.js +84 -0
- package/dist/tui/screens/Overview.js +36 -0
- package/dist/tui/screens/Pair.js +74 -0
- package/dist/tui/screens/Relay.js +242 -0
- package/dist/tui/screens/Services.js +63 -0
- package/dist/tui/screens/Wizard.js +235 -0
- package/dist/tui/terminal.js +39 -0
- package/dist/tui/theme.js +33 -0
- package/dist/updater.js +382 -0
- package/herdr-plugin.toml +1 -1
- package/package.json +8 -8
- package/dist/tui.mjs +0 -5775
- package/src/agent-status.js +0 -139
- package/src/binary-plist.js +0 -146
- package/src/config.js +0 -454
- package/src/font-subset.js +0 -110
- package/src/herdr-api.js +0 -244
- package/src/herdr-command.js +0 -231
- package/src/herdr-plugin.js +0 -130
- package/src/herdr-server.js +0 -201
- package/src/host-connector.js +0 -1069
- package/src/i18n/en.js +0 -240
- package/src/i18n/index.js +0 -56
- package/src/i18n/zh.js +0 -239
- package/src/keepalive.js +0 -460
- package/src/lifecycle.js +0 -62
- package/src/net-interfaces.js +0 -76
- package/src/pasted-files.js +0 -176
- package/src/pty-session.js +0 -92
- package/src/service.js +0 -530
- package/src/settings-model.js +0 -323
- package/src/socket-discovery.js +0 -60
- package/src/state.js +0 -47
- package/src/supervisor.js +0 -250
- package/src/terminal-font.js +0 -1204
- package/src/terminal-palette.js +0 -325
- package/src/updater.js +0 -394
package/src/herdr-server.js
DELETED
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
// Whether Herdr's server is running on this workstation, and starting it when
|
|
4
|
-
// the user asked for that.
|
|
5
|
-
//
|
|
6
|
-
// herdr-remote never starts Herdr on its own initiative. It starts one when a
|
|
7
|
-
// browser paired to this workstation asks for it, or at service start when the
|
|
8
|
-
// user switched that on — and both go through here.
|
|
9
|
-
//
|
|
10
|
-
// Two traps shape this file:
|
|
11
|
-
//
|
|
12
|
-
// - A socket file is not a server. Herdr leaves `herdr.sock` behind when it dies
|
|
13
|
-
// without cleaning up (a crash, a power cut), and a `herdr` client pointed at
|
|
14
|
-
// a dead socket quietly starts a server of its own. So "running" means a
|
|
15
|
-
// connection was accepted, not that the path exists.
|
|
16
|
-
// - A server started from inside herdr-remote's systemd service lives in that
|
|
17
|
-
// service's cgroup, and `systemctl restart herdr-remote` — an update, a keep-
|
|
18
|
-
// alive restart, Herdr's own plugin startup hook — would kill it along with
|
|
19
|
-
// every agent in it. Under a service it is therefore started in a transient
|
|
20
|
-
// scope of its own, the same place it would live had the user started it
|
|
21
|
-
// from a terminal.
|
|
22
|
-
|
|
23
|
-
const fs = require('node:fs');
|
|
24
|
-
const net = require('node:net');
|
|
25
|
-
const path = require('node:path');
|
|
26
|
-
const { spawn } = require('node:child_process');
|
|
27
|
-
const { inspectSocket } = require('./socket-discovery');
|
|
28
|
-
const { ensureDir } = require('./state');
|
|
29
|
-
|
|
30
|
-
/** A Unix socket either accepts at once or is dead; this only guards a hang. */
|
|
31
|
-
const PROBE_TIMEOUT_MS = 1_000;
|
|
32
|
-
/** Herdr restores the saved session before its API socket opens. */
|
|
33
|
-
const START_TIMEOUT_MS = 20_000;
|
|
34
|
-
const START_POLL_MS = 200;
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Is Herdr's server answering on `socketPath`?
|
|
38
|
-
*
|
|
39
|
-
* Resolves `{ state }`: `running`, `stopped` (no socket, or a socket nothing is
|
|
40
|
-
* listening on), or `unavailable` with a `reason` — a path that is not a socket
|
|
41
|
-
* or belongs to another user. That last one is never "stopped": the socket may
|
|
42
|
-
* well be live, just not ours to use, and starting a second server beside it
|
|
43
|
-
* would be starting somebody else's Herdr.
|
|
44
|
-
*/
|
|
45
|
-
function probeHerdrServer(socketPath, { connect = net.connect, timeout = PROBE_TIMEOUT_MS } = {}) {
|
|
46
|
-
const info = inspectSocket(socketPath);
|
|
47
|
-
if (!info.ok) {
|
|
48
|
-
return Promise.resolve(info.missing ? { state: 'stopped' } : { state: 'unavailable', reason: info.reason });
|
|
49
|
-
}
|
|
50
|
-
return new Promise((resolve) => {
|
|
51
|
-
let socket;
|
|
52
|
-
const finish = (result) => {
|
|
53
|
-
clearTimeout(timer);
|
|
54
|
-
if (socket) {
|
|
55
|
-
socket.removeAllListeners();
|
|
56
|
-
socket.on('error', () => {});
|
|
57
|
-
socket.destroy();
|
|
58
|
-
}
|
|
59
|
-
resolve(result);
|
|
60
|
-
};
|
|
61
|
-
// A socket that neither accepts nor refuses has a listener behind it that
|
|
62
|
-
// is slow, not absent; starting another server would only fight it.
|
|
63
|
-
const timer = setTimeout(() => finish({ state: 'running' }), timeout);
|
|
64
|
-
if (typeof timer.unref === 'function') timer.unref();
|
|
65
|
-
socket = connect(socketPath);
|
|
66
|
-
socket.once('connect', () => finish({ state: 'running' }));
|
|
67
|
-
socket.once('error', (error) => finish(
|
|
68
|
-
error.code === 'ECONNREFUSED' || error.code === 'ENOENT'
|
|
69
|
-
? { state: 'stopped', stale: true }
|
|
70
|
-
: { state: 'unavailable', reason: error.message },
|
|
71
|
-
));
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* True when this process is a systemd service (herdr-remote's keep-alive), so
|
|
77
|
-
* anything it starts would be killed with it.
|
|
78
|
-
*/
|
|
79
|
-
function runningInSystemdService({ platform = process.platform, readCgroup = () => fs.readFileSync('/proc/self/cgroup', 'utf8') } = {}) {
|
|
80
|
-
if (platform !== 'linux') return false;
|
|
81
|
-
try {
|
|
82
|
-
const unified = readCgroup().split('\n').find((line) => line.startsWith('0::'));
|
|
83
|
-
return Boolean(unified) && /\.service$/.test(unified.trim());
|
|
84
|
-
} catch {
|
|
85
|
-
return false;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/** The server's environment: the one a Herdr pane would give its client. */
|
|
90
|
-
function serverEnv(socketPath, env = process.env) {
|
|
91
|
-
const next = { ...env };
|
|
92
|
-
for (const key of Object.keys(next)) {
|
|
93
|
-
if (key.startsWith('HERDR_')) delete next[key];
|
|
94
|
-
}
|
|
95
|
-
if (socketPath) next.HERDR_SOCKET_PATH = socketPath;
|
|
96
|
-
return next;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* The argv that starts Herdr's server: Herdr's own global arguments (a
|
|
101
|
-
* `--session`, say) followed by `server`, wrapped in `systemd-run --scope` when
|
|
102
|
-
* the caller is a systemd service.
|
|
103
|
-
*/
|
|
104
|
-
function serverCommand({ command, args = [], inService = runningInSystemdService() }) {
|
|
105
|
-
const herdr = [command, ...args, 'server'];
|
|
106
|
-
if (!inService) return { file: herdr[0], args: herdr.slice(1) };
|
|
107
|
-
return {
|
|
108
|
-
file: 'systemd-run',
|
|
109
|
-
args: ['--user', '--scope', '--quiet', '--collect', '--description=Herdr server started by herdr-remote', '--', ...herdr],
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Start Herdr's server in the background. Detached from this process, with its
|
|
115
|
-
* output appended to `logPath` rather than piped here: a pipe would break the
|
|
116
|
-
* moment herdr-remote exits and take the server with it.
|
|
117
|
-
*/
|
|
118
|
-
function launchHerdrServer({ command, args = [], socketPath, cwd, logPath, spawnProcess = spawn, inService }) {
|
|
119
|
-
const { file, args: argv } = serverCommand({ command, args, inService });
|
|
120
|
-
ensureDir(path.dirname(logPath));
|
|
121
|
-
const out = fs.openSync(logPath, 'a');
|
|
122
|
-
let child;
|
|
123
|
-
try {
|
|
124
|
-
child = spawnProcess(file, argv, {
|
|
125
|
-
cwd,
|
|
126
|
-
env: serverEnv(socketPath),
|
|
127
|
-
detached: true,
|
|
128
|
-
stdio: ['ignore', out, out],
|
|
129
|
-
});
|
|
130
|
-
} finally {
|
|
131
|
-
fs.closeSync(out);
|
|
132
|
-
}
|
|
133
|
-
child.on('error', () => {});
|
|
134
|
-
child.unref();
|
|
135
|
-
return child;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
function readLogTail(logPath, bytes = 2_000) {
|
|
139
|
-
try {
|
|
140
|
-
const text = fs.readFileSync(logPath, 'utf8');
|
|
141
|
-
return text.slice(-bytes).trim();
|
|
142
|
-
} catch {
|
|
143
|
-
return '';
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Make sure Herdr's server is running, starting it if it is not.
|
|
149
|
-
*
|
|
150
|
-
* Resolves `{ started }`, or rejects with a message that says what happened:
|
|
151
|
-
* the socket belongs to someone else, the server exited, or it never opened
|
|
152
|
-
* its socket. The last lines Herdr printed ride along, because "did not start"
|
|
153
|
-
* with no reason is a message nobody can act on.
|
|
154
|
-
*/
|
|
155
|
-
async function ensureHerdrServer({
|
|
156
|
-
command,
|
|
157
|
-
args = [],
|
|
158
|
-
socketPath,
|
|
159
|
-
cwd,
|
|
160
|
-
logPath,
|
|
161
|
-
probe = probeHerdrServer,
|
|
162
|
-
launch = launchHerdrServer,
|
|
163
|
-
timeout = START_TIMEOUT_MS,
|
|
164
|
-
interval = START_POLL_MS,
|
|
165
|
-
}) {
|
|
166
|
-
const before = await probe(socketPath);
|
|
167
|
-
if (before.state === 'running') return { started: false };
|
|
168
|
-
if (before.state === 'unavailable') {
|
|
169
|
-
throw new Error(`Herdr socket at ${socketPath} cannot be used: ${before.reason}`);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const child = launch({ command, args, socketPath, cwd, logPath });
|
|
173
|
-
let exit = null;
|
|
174
|
-
child.once('exit', (code, signal) => { exit = { code, signal }; });
|
|
175
|
-
|
|
176
|
-
const deadline = Date.now() + timeout;
|
|
177
|
-
for (;;) {
|
|
178
|
-
await new Promise((resolve) => setTimeout(resolve, interval));
|
|
179
|
-
const now = await probe(socketPath);
|
|
180
|
-
if (now.state === 'running') return { started: true };
|
|
181
|
-
const tail = readLogTail(logPath);
|
|
182
|
-
const detail = tail ? `\n${tail}` : '';
|
|
183
|
-
if (exit) {
|
|
184
|
-
throw new Error(`Herdr server exited (${exit.signal || `code ${exit.code}`}) before opening ${socketPath}.${detail}`);
|
|
185
|
-
}
|
|
186
|
-
if (Date.now() >= deadline) {
|
|
187
|
-
throw new Error(`Herdr server did not open ${socketPath} within ${Math.round(timeout / 1000)}s.${detail}`);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
module.exports = {
|
|
193
|
-
PROBE_TIMEOUT_MS,
|
|
194
|
-
START_TIMEOUT_MS,
|
|
195
|
-
probeHerdrServer,
|
|
196
|
-
runningInSystemdService,
|
|
197
|
-
serverEnv,
|
|
198
|
-
serverCommand,
|
|
199
|
-
launchHerdrServer,
|
|
200
|
-
ensureHerdrServer,
|
|
201
|
-
};
|