@sessionbus/dsh 0.1.0-pre.10 → 0.1.0-pre.12
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 +6 -0
- package/package.json +1 -1
- package/plugin.cjs +43 -10
package/README.md
CHANGED
|
@@ -62,6 +62,12 @@ when given a launch token. Install the selected launcher alongside `dsh` at the
|
|
|
62
62
|
host level and put their shared `node_modules/.bin` on the daemon service's
|
|
63
63
|
`PATH`; the `dashi` launcher resolves its child `dsh` by name.
|
|
64
64
|
|
|
65
|
+
Without an explicit socket, peers use `$XDG_RUNTIME_DIR/sessionbus/presence.sock`
|
|
66
|
+
or `/tmp/sessionbus-<uid>/presence.sock`, matching the daemon's discovery rule.
|
|
67
|
+
Set `SESSIONBUS_DSH_TRACE=1` to write one-line mode, readiness, root-lifecycle,
|
|
68
|
+
publication-gate, and socket-connection diagnostics to stderr; tracing is off
|
|
69
|
+
by default.
|
|
70
|
+
|
|
65
71
|
Uninstall without invoking DSH by running the installed bin from the profile:
|
|
66
72
|
|
|
67
73
|
```sh
|
package/package.json
CHANGED
package/plugin.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const net = require("node:net");
|
|
4
4
|
const path = require("node:path");
|
|
5
5
|
const kit = require("@sessionbus/kit");
|
|
6
6
|
const version = require("./package.json").version;
|
|
@@ -66,10 +66,13 @@ function readConfiguration(ctx, config = {}, ambient = process.env) {
|
|
|
66
66
|
if (config.mode !== undefined && config.mode !== mode) throw new Error(`mode ${config.mode} conflicts with launch environment`);
|
|
67
67
|
let groups = mode === "lane" ? [] : Object.hasOwn(config, "groups") ? config.groups : JSON.parse(value("SESSIONBUS_GROUPS") || "[]");
|
|
68
68
|
if (!Array.isArray(groups) || groups.some((group) => !text(group)) || new Set(groups).size !== groups.length) throw new Error("groups are invalid");
|
|
69
|
-
const
|
|
69
|
+
const explicitSocket = Object.hasOwn(config, "socket") ? config.socket : value("SESSIONBUS_SOCKET");
|
|
70
|
+
const socket = explicitSocket ? path.resolve(explicitSocket) : value("XDG_RUNTIME_DIR")
|
|
71
|
+
? path.resolve(value("XDG_RUNTIME_DIR"), "sessionbus/presence.sock")
|
|
72
|
+
: path.join("/tmp", `sessionbus-${process.getuid()}`, "presence.sock");
|
|
70
73
|
const localKey = Object.hasOwn(config, "local_key") ? config.local_key : value("SESSIONBUS_LOCAL_KEY");
|
|
71
74
|
if (!text(socket) || localKey !== undefined && !text(localKey)) throw new Error("connection settings are invalid");
|
|
72
|
-
return { settings: { mode, product: config.product, groups: [...groups], socket, localKey }, token };
|
|
75
|
+
return { settings: { mode, product: config.product, groups: [...groups], socket, localKey }, token, trace: value("SESSIONBUS_DSH_TRACE") === "1" };
|
|
73
76
|
}
|
|
74
77
|
|
|
75
78
|
function captureContext(ctx) {
|
|
@@ -285,26 +288,54 @@ function createRuntime(ctx, config, dependencies, prepared) {
|
|
|
285
288
|
let launchToken = configured.token;
|
|
286
289
|
const native = new NativeSession(ctx, dependencies.createUserMessage);
|
|
287
290
|
const peers = new Map();
|
|
291
|
+
const publicationErrors = new WeakSet();
|
|
288
292
|
let worker;
|
|
289
293
|
let workerExit = Promise.resolve();
|
|
290
294
|
let ready = false;
|
|
291
295
|
let warned = false;
|
|
292
296
|
const warn = (error) => { if (active() && !warned) { warned = true; dependencies.stderr(`sessionbus: ${clean(error)}\n`); } };
|
|
297
|
+
const trace = (message) => { if (configured.trace && active()) dependencies.stderr(`sessionbus trace: ${message}\n`); };
|
|
293
298
|
const root = (agent) => ctx.agents.roots().includes(agent);
|
|
299
|
+
trace(`mode=${values.mode} ready=false socket=${values.socket}`);
|
|
300
|
+
const publicationError = (agent, error, record) => {
|
|
301
|
+
if (record && peers.get(agent) === record) {
|
|
302
|
+
record.peer?.shutdown();
|
|
303
|
+
peers.delete(agent);
|
|
304
|
+
// Leave it unpublished; a later title change may naturally call present() again.
|
|
305
|
+
}
|
|
306
|
+
if (active() && !publicationErrors.has(agent)) {
|
|
307
|
+
publicationErrors.add(agent);
|
|
308
|
+
dependencies.stderr(`sessionbus: ${clean(error)}\n`);
|
|
309
|
+
}
|
|
310
|
+
};
|
|
294
311
|
const present = (agent) => {
|
|
295
|
-
|
|
312
|
+
const isRoot = root(agent);
|
|
313
|
+
const reason = values.mode !== "peer" ? "not-peer" : !ready ? "not-ready" : !isRoot ? "not-root" : peers.has(agent) ? "published" : "publish";
|
|
314
|
+
trace(`present id=${agent?.session?.id || agent?.id || "unknown"} root=${isRoot} reason=${reason}`);
|
|
315
|
+
if (reason !== "publish") return;
|
|
296
316
|
try {
|
|
297
317
|
const current = identity(ctx, agent, values.product, values.groups);
|
|
298
|
-
if (!current) return;
|
|
299
|
-
const
|
|
300
|
-
|
|
301
|
-
|
|
318
|
+
if (!current) { trace(`present id=${agent?.id || "unknown"} root=${isRoot} reason=no-session-id`); return; }
|
|
319
|
+
const record = { peer: undefined, identity: current, rehello: Promise.resolve() };
|
|
320
|
+
const peer = dependencies.connectPeer(current, (cancel, request) => native.deliver(cancel, request, agent), connectionEnvironment(values), {
|
|
321
|
+
connect: (socket) => {
|
|
322
|
+
trace(`connect id=${current.session_id} socket=${socket}`);
|
|
323
|
+
const stream = net.createConnection(socket);
|
|
324
|
+
stream.once("connect", () => trace(`connect id=${current.session_id} state=connected`));
|
|
325
|
+
stream.once("error", (error) => publicationError(agent, error, record));
|
|
326
|
+
return stream;
|
|
327
|
+
},
|
|
328
|
+
});
|
|
329
|
+
record.peer = peer;
|
|
330
|
+
peers.set(agent, record);
|
|
331
|
+
void peer.closed?.then(() => { if (peer.error) publicationError(agent, peer.error, record); });
|
|
332
|
+
} catch (error) { publicationError(agent, error); }
|
|
302
333
|
};
|
|
303
334
|
const forget = (agent) => { peers.get(agent)?.peer.shutdown(); peers.delete(agent); };
|
|
304
335
|
let removeCreated = () => {}, removeDisposed = () => {}, removeTitle = () => {};
|
|
305
336
|
if (values.mode === "peer") {
|
|
306
|
-
removeCreated = ctx.on("agent/created", ({ agent }) => present(agent));
|
|
307
|
-
removeDisposed = ctx.on("agent/disposed", ({ agent }) => forget(agent));
|
|
337
|
+
removeCreated = ctx.on("agent/created", ({ agent }) => { trace(`agent/created id=${agent?.session?.id || agent?.id || "unknown"} scope=global`); present(agent); }, { global: true });
|
|
338
|
+
removeDisposed = ctx.on("agent/disposed", ({ agent }) => { trace(`agent/disposed id=${agent?.session?.id || agent?.id || "unknown"} scope=global`); forget(agent); }, { global: true });
|
|
308
339
|
removeTitle = ctx.on("session/event", (session, event) => {
|
|
309
340
|
if (event.type !== "session/title") return;
|
|
310
341
|
const agent = ctx.agents.get(session.id);
|
|
@@ -348,6 +379,7 @@ function createRuntime(ctx, config, dependencies, prepared) {
|
|
|
348
379
|
});
|
|
349
380
|
const start = () => {
|
|
350
381
|
ready = true;
|
|
382
|
+
trace(`mode=${values.mode} ready=true`);
|
|
351
383
|
if (values.mode === "lane") {
|
|
352
384
|
const environment = connectionEnvironment(values, launchToken);
|
|
353
385
|
launchToken = undefined;
|
|
@@ -370,6 +402,7 @@ function createRuntime(ctx, config, dependencies, prepared) {
|
|
|
370
402
|
};
|
|
371
403
|
const removeReady = ctx.appReady.onReady(start);
|
|
372
404
|
const close = () => {
|
|
405
|
+
trace(`mode=${values.mode} ready=false reason=close`);
|
|
373
406
|
removeReady(); removeCreated(); removeDisposed(); removeTitle(); removeCommand(); removeGrant(); removeTool();
|
|
374
407
|
for (const agent of peers.keys()) forget(agent);
|
|
375
408
|
worker?.shutdown(); native.removeEvents();
|