mslxdff 0.1.24 → 0.1.26
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/mslxdff.js +51 -14
- package/package.json +1 -1
- package/src/server.js +5 -1
package/bin/mslxdff.js
CHANGED
|
@@ -253,24 +253,60 @@ if (groupCmd && groupCmd !== "create") {
|
|
|
253
253
|
continue;
|
|
254
254
|
}
|
|
255
255
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
const
|
|
264
|
-
|
|
256
|
+
const entries = Object.entries(members).filter(([id]) => id !== "leader");
|
|
257
|
+
console.log(`${g.name} (${entries.length} member${entries.length === 1 ? "" : "s"})`);
|
|
258
|
+
// probe every member endpoint concurrently for reachability + latency;
|
|
259
|
+
// display order = state order so the sequence numbers stay stable for -group remove
|
|
260
|
+
const probes = await Promise.all(
|
|
261
|
+
entries.map(([id, m]) => probeHealth({ id, url: m?.url || id }))
|
|
262
|
+
);
|
|
263
|
+
const leaderEntry = members.leader ? Object.entries(members).find(([id]) => id === "leader") : null;
|
|
264
|
+
const leaderProbe = leaderEntry ? await probeHealth({ id: "leader", url: leaderEntry[1].url }) : null;
|
|
265
|
+
const display = leaderProbe ? [...probes, leaderProbe] : probes;
|
|
266
|
+
let seq = 0;
|
|
267
|
+
for (const r of display) {
|
|
265
268
|
const state = r.fail ? `fail ${r.fail}` : `ok ${r.ms}ms`;
|
|
266
|
-
|
|
267
|
-
|
|
269
|
+
if (r.id === "leader") {
|
|
270
|
+
console.log(` leader ${r.url} ${state}`);
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
seq += 1;
|
|
274
|
+
const label = r.id && r.id !== r.url ? ` [${r.id}]` : "";
|
|
275
|
+
console.log(` ${seq}. ${r.url}${label} ${state}`);
|
|
268
276
|
}
|
|
269
277
|
}
|
|
270
278
|
console.log(`\njoined groups (${joinedList.length}):`);
|
|
271
279
|
for (const g of joinedList) console.log(` ${g.name} ${g.leaderUrl || "(this node is the leader)"}`);
|
|
280
|
+
} else if (action === "remove" && a) {
|
|
281
|
+
// leader-only: kick a member by its list sequence number (1-based, leader excluded)
|
|
282
|
+
const seq = Number(a);
|
|
283
|
+
if (!Number.isInteger(seq) || seq < 1) {
|
|
284
|
+
console.error(`usage: mslxdff -group remove <seq>`);
|
|
285
|
+
process.exit(1);
|
|
286
|
+
}
|
|
287
|
+
const joined = loadGroupsJoined().find((g) => !g.leaderUrl);
|
|
288
|
+
if (!joined) {
|
|
289
|
+
console.error("group remove requires being the leader — this node leads no group");
|
|
290
|
+
process.exit(1);
|
|
291
|
+
}
|
|
292
|
+
const members = groups.list()[joined.name]?.members || {};
|
|
293
|
+
const entries = Object.entries(members).filter(([id]) => id !== "leader");
|
|
294
|
+
const target = entries[seq - 1];
|
|
295
|
+
if (!target) {
|
|
296
|
+
console.error(`member #${seq} not found — group "${joined.name}" has ${entries.length} member(s)`);
|
|
297
|
+
process.exit(1);
|
|
298
|
+
}
|
|
299
|
+
const [id, m] = target;
|
|
300
|
+
try {
|
|
301
|
+
const removed = groups.removeMember(joined.name, { url: m.url });
|
|
302
|
+
if (removed) console.log(`removed ${m.url} from "${joined.name}"`);
|
|
303
|
+
else console.log(`member ${m.url} already gone from "${joined.name}"`);
|
|
304
|
+
} catch (err) {
|
|
305
|
+
console.error(`remove failed: ${errMsg(err)}`);
|
|
306
|
+
process.exit(1);
|
|
307
|
+
}
|
|
272
308
|
} else {
|
|
273
|
-
console.error("usage: mslxdff -
|
|
309
|
+
console.error("usage: mslxdff -group sync | -group leave <name> | -group list | -group remove <seq> | -creategroup <name>");
|
|
274
310
|
}
|
|
275
311
|
process.exit(0);
|
|
276
312
|
}
|
|
@@ -714,14 +750,15 @@ Usage:
|
|
|
714
750
|
mslxdff -addtogroup <leader-host> <name> join a group via its leader host (default port 8989)
|
|
715
751
|
mslxdff -group sync pull the freshest member list for all joined groups
|
|
716
752
|
mslxdff -group leave <name> leave a group (removes its members from this node)
|
|
717
|
-
mslxdff -group list list groups on this node
|
|
753
|
+
mslxdff -group list list groups on this node (numbered members)
|
|
754
|
+
mslxdff -group remove <seq> leader only: kick a member by its list sequence number
|
|
718
755
|
mslxdff -leavegroup leave every joined group as a member (leaders: use -delgroup)
|
|
719
756
|
mslxdff -delgroup <name> disband a group this node leads (deletes it and its members)
|
|
720
757
|
mslxdff -resetban [ip] clear join-failure bans (all, or one ip)
|
|
721
758
|
mslxdff -help show this help
|
|
722
759
|
|
|
723
760
|
Environment:
|
|
724
|
-
|
|
761
|
+
MSLXDFF_PORT listen port (default 8989; use mslxdff -port N to persist)
|
|
725
762
|
MSLXDFF_STATE_FILE token/port state file
|
|
726
763
|
MSLXDFF_DAEMON_DIR daemon pid/log/models dir
|
|
727
764
|
UPSTREAM_BASE_URL upstream base (default https://opencode.ai)
|
package/package.json
CHANGED
package/src/server.js
CHANGED
|
@@ -33,9 +33,13 @@ export function startServer({ router, signals = true }, port = resolvePort()) {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
export function resolvePort() {
|
|
36
|
+
// 8989 is the hard default. Port only changes via an explicit, mslxdff-owned
|
|
37
|
+
// override: the persisted `-port N` setting, or the MSLXDFF_PORT env var.
|
|
38
|
+
// Bare `PORT` is deliberately NOT read — an ssh session / wrapper script
|
|
39
|
+
// commonly injects it and would silently override the default.
|
|
36
40
|
const persisted = getPort();
|
|
37
41
|
if (persisted) return persisted;
|
|
38
|
-
const env = Number(process.env.
|
|
42
|
+
const env = Number(process.env.MSLXDFF_PORT);
|
|
39
43
|
// 0 = OS-assigned ephemeral port (valid; used by tests/containers)
|
|
40
44
|
if (Number.isInteger(env) && env >= 0) return env;
|
|
41
45
|
return DEFAULT_PORT;
|