@threadbase-sh/streamer 1.30.0 → 1.31.0
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.cjs +85 -91
- package/dist/cli.cjs.map +1 -1
- package/dist/index.cjs +70 -88
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +18 -7
- package/dist/index.d.ts +18 -7
- package/dist/index.js +70 -88
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -215,7 +215,7 @@ function verifySignature(rawBody, signature, secret) {
|
|
|
215
215
|
}
|
|
216
216
|
}
|
|
217
217
|
function isWithinSkew(timestampHeader, skewSeconds) {
|
|
218
|
-
if (!timestampHeader) return
|
|
218
|
+
if (!timestampHeader) return true;
|
|
219
219
|
const t = Number(timestampHeader);
|
|
220
220
|
if (!Number.isFinite(t)) return false;
|
|
221
221
|
const now = Math.floor(Date.now() / 1e3);
|
|
@@ -797,6 +797,7 @@ function debounce(fn, waitMs) {
|
|
|
797
797
|
|
|
798
798
|
// src/codex-pty-runner.ts
|
|
799
799
|
var OUTPUT_BUFFER_MAX = 65536;
|
|
800
|
+
var INPUT_HISTORY_MAX = 50;
|
|
800
801
|
var PTY_COLS = 120;
|
|
801
802
|
var PTY_ROWS = 40;
|
|
802
803
|
var SCREEN_SCROLLBACK = 1e3;
|
|
@@ -877,6 +878,7 @@ var CodexPtyRunner = class {
|
|
|
877
878
|
onPermissionChange;
|
|
878
879
|
onLiveQuestion;
|
|
879
880
|
onLiveQuestionGone;
|
|
881
|
+
onUserMessage;
|
|
880
882
|
log;
|
|
881
883
|
// Tracks sessions whose PTY has spawned but Codex hasn't yet reached its
|
|
882
884
|
// "Ready" status bar — i.e. onReady hasn't fired.
|
|
@@ -907,6 +909,7 @@ var CodexPtyRunner = class {
|
|
|
907
909
|
this.onPermissionChange = options.onPermissionChange;
|
|
908
910
|
this.onLiveQuestion = options.onLiveQuestion;
|
|
909
911
|
this.onLiveQuestionGone = options.onLiveQuestionGone;
|
|
912
|
+
this.onUserMessage = options.onUserMessage;
|
|
910
913
|
this.log = options.logger ?? getLogger("codex-pty");
|
|
911
914
|
}
|
|
912
915
|
// Resume an existing Codex session. sessionId is the Codex-persisted
|
|
@@ -950,7 +953,8 @@ var CodexPtyRunner = class {
|
|
|
950
953
|
lastOutput: "",
|
|
951
954
|
process: proc,
|
|
952
955
|
outputBuffer: Buffer.alloc(0),
|
|
953
|
-
screen: createScreen()
|
|
956
|
+
screen: createScreen(),
|
|
957
|
+
inputHistory: []
|
|
954
958
|
};
|
|
955
959
|
this.sessions.set(sessionId, session);
|
|
956
960
|
this.pendingReady.add(sessionId);
|
|
@@ -996,7 +1000,8 @@ var CodexPtyRunner = class {
|
|
|
996
1000
|
lastOutput: "",
|
|
997
1001
|
process: proc,
|
|
998
1002
|
outputBuffer: Buffer.alloc(0),
|
|
999
|
-
screen: createScreen()
|
|
1003
|
+
screen: createScreen(),
|
|
1004
|
+
inputHistory: []
|
|
1000
1005
|
};
|
|
1001
1006
|
this.sessions.set(sessionId, session);
|
|
1002
1007
|
this.pendingReady.add(sessionId);
|
|
@@ -1114,6 +1119,7 @@ var CodexPtyRunner = class {
|
|
|
1114
1119
|
// confirmed Codex accepts plain keystrokes), then submit \r after a short
|
|
1115
1120
|
// delay so Codex's TUI gets an event-loop tick to process the input first.
|
|
1116
1121
|
writeSubmit(sessionId, session, input, path, promptCount) {
|
|
1122
|
+
this.recordUserMessage(session, input);
|
|
1117
1123
|
this.log.info(
|
|
1118
1124
|
`[codex.input.write] ${sessionId.slice(0, 8)} promptCount=${promptCount} bytes=${input.length} digest=${digestBytes(input)}`,
|
|
1119
1125
|
{
|
|
@@ -1243,6 +1249,19 @@ var CodexPtyRunner = class {
|
|
|
1243
1249
|
}
|
|
1244
1250
|
return lines.slice(-maxLines);
|
|
1245
1251
|
}
|
|
1252
|
+
getInputHistory(sessionId) {
|
|
1253
|
+
return this.sessions.get(sessionId)?.inputHistory ?? [];
|
|
1254
|
+
}
|
|
1255
|
+
// Record a submitted user message as ground truth and fire onUserMessage.
|
|
1256
|
+
// Called from writeSubmit (direct and flush paths) — never from sendKeys.
|
|
1257
|
+
recordUserMessage(session, text) {
|
|
1258
|
+
const ts = Date.now();
|
|
1259
|
+
session.inputHistory.push({ text, ts });
|
|
1260
|
+
if (session.inputHistory.length > INPUT_HISTORY_MAX) {
|
|
1261
|
+
session.inputHistory.shift();
|
|
1262
|
+
}
|
|
1263
|
+
this.onUserMessage?.(session.id, text, ts);
|
|
1264
|
+
}
|
|
1246
1265
|
getSession(sessionId) {
|
|
1247
1266
|
const session = this.sessions.get(sessionId);
|
|
1248
1267
|
return session ? toPublicSession(session) : null;
|
|
@@ -1620,6 +1639,7 @@ function detectShellPrompt(lines) {
|
|
|
1620
1639
|
|
|
1621
1640
|
// src/pty-manager.ts
|
|
1622
1641
|
var OUTPUT_BUFFER_MAX2 = 65536;
|
|
1642
|
+
var INPUT_HISTORY_MAX2 = 50;
|
|
1623
1643
|
var PTY_COLS2 = 120;
|
|
1624
1644
|
var PTY_ROWS2 = 40;
|
|
1625
1645
|
var SCREEN_SCROLLBACK2 = 1e3;
|
|
@@ -1678,6 +1698,7 @@ var PTYManager = class {
|
|
|
1678
1698
|
onPermissionChange;
|
|
1679
1699
|
onLiveQuestion;
|
|
1680
1700
|
onLiveQuestionGone;
|
|
1701
|
+
onUserMessage;
|
|
1681
1702
|
// Per-session permission-gate state. True between an OSC 777 (gate open) and
|
|
1682
1703
|
// the next prompt-ready without a fresh 777 (gate closed). Prevents
|
|
1683
1704
|
// re-broadcasting open/close on every chunk.
|
|
@@ -1723,6 +1744,7 @@ var PTYManager = class {
|
|
|
1723
1744
|
this.onPermissionChange = options.onPermissionChange;
|
|
1724
1745
|
this.onLiveQuestion = options.onLiveQuestion;
|
|
1725
1746
|
this.onLiveQuestionGone = options.onLiveQuestionGone;
|
|
1747
|
+
this.onUserMessage = options.onUserMessage;
|
|
1726
1748
|
this.log = options.logger ?? getLogger("pty");
|
|
1727
1749
|
}
|
|
1728
1750
|
// Resume an existing Claude conversation. sessionId is the JSONL UUID.
|
|
@@ -1785,7 +1807,8 @@ var PTYManager = class {
|
|
|
1785
1807
|
lastOutput: "",
|
|
1786
1808
|
process: proc,
|
|
1787
1809
|
outputBuffer: Buffer.alloc(0),
|
|
1788
|
-
screen: createScreen2()
|
|
1810
|
+
screen: createScreen2(),
|
|
1811
|
+
inputHistory: []
|
|
1789
1812
|
};
|
|
1790
1813
|
this.sessions.set(sessionId, session);
|
|
1791
1814
|
this.pendingReady.add(sessionId);
|
|
@@ -1836,7 +1859,8 @@ var PTYManager = class {
|
|
|
1836
1859
|
lastOutput: "",
|
|
1837
1860
|
process: proc,
|
|
1838
1861
|
outputBuffer: Buffer.alloc(0),
|
|
1839
|
-
screen: createScreen2()
|
|
1862
|
+
screen: createScreen2(),
|
|
1863
|
+
inputHistory: []
|
|
1840
1864
|
};
|
|
1841
1865
|
this.sessions.set(sessionId, session);
|
|
1842
1866
|
this.pendingReady.add(sessionId);
|
|
@@ -1916,6 +1940,7 @@ var PTYManager = class {
|
|
|
1916
1940
|
// step gives the TUI as many extra ticks as it needs, capped at
|
|
1917
1941
|
// SUBMIT_MAX_WAIT_MS so a silent/wedged PTY still gets its \r eventually.
|
|
1918
1942
|
writeSubmit(sessionId, session, input, path, promptCount) {
|
|
1943
|
+
this.recordUserMessage(session, input);
|
|
1919
1944
|
const pasteBytes = buildPasteBytes(input);
|
|
1920
1945
|
this.log.info(
|
|
1921
1946
|
`[pty.input.write] ${sessionId.slice(0, 8)} promptCount=${promptCount} bytes=${pasteBytes.length} digest=${digestBytes2(pasteBytes)}`,
|
|
@@ -2046,6 +2071,20 @@ var PTYManager = class {
|
|
|
2046
2071
|
}
|
|
2047
2072
|
return lines.slice(-maxLines);
|
|
2048
2073
|
}
|
|
2074
|
+
getInputHistory(sessionId) {
|
|
2075
|
+
return this.sessions.get(sessionId)?.inputHistory ?? [];
|
|
2076
|
+
}
|
|
2077
|
+
// Record a submitted user message as ground truth and fire onUserMessage.
|
|
2078
|
+
// Called from writeSubmit (both direct and flush paths) — never from
|
|
2079
|
+
// sendKeys, so raw keystrokes aren't logged as messages.
|
|
2080
|
+
recordUserMessage(session, text) {
|
|
2081
|
+
const ts = Date.now();
|
|
2082
|
+
session.inputHistory.push({ text, ts });
|
|
2083
|
+
if (session.inputHistory.length > INPUT_HISTORY_MAX2) {
|
|
2084
|
+
session.inputHistory.shift();
|
|
2085
|
+
}
|
|
2086
|
+
this.onUserMessage?.(session.id, text, ts);
|
|
2087
|
+
}
|
|
2049
2088
|
getSession(sessionId) {
|
|
2050
2089
|
const session = this.sessions.get(sessionId);
|
|
2051
2090
|
return session ? toPublicSession2(session) : null;
|
|
@@ -2342,6 +2381,9 @@ var LiveSessionManager = class {
|
|
|
2342
2381
|
getOutputLines(sessionId, maxLines) {
|
|
2343
2382
|
return this.runnerFor(sessionId).getOutputLines(sessionId, maxLines);
|
|
2344
2383
|
}
|
|
2384
|
+
getInputHistory(sessionId) {
|
|
2385
|
+
return this.runnerFor(sessionId).getInputHistory(sessionId);
|
|
2386
|
+
}
|
|
2345
2387
|
getSession(sessionId) {
|
|
2346
2388
|
for (const runner of this.runners.values()) {
|
|
2347
2389
|
const session = runner.getSession(sessionId);
|
|
@@ -2801,7 +2843,7 @@ function isLocalRequest(remoteAddr) {
|
|
|
2801
2843
|
const addr = remoteAddr ?? "";
|
|
2802
2844
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
2803
2845
|
}
|
|
2804
|
-
var PUBLIC_PATHS = /* @__PURE__ */ new Set(["/healthz"
|
|
2846
|
+
var PUBLIC_PATHS = /* @__PURE__ */ new Set(["/healthz"]);
|
|
2805
2847
|
var LOCAL_ONLY_PATHS = /* @__PURE__ */ new Set(["/api/logs", "/api/logs/meta"]);
|
|
2806
2848
|
var PUBLIC_POST_PATHS = /* @__PURE__ */ new Set(["/api/pair/exchange", "/api/__update"]);
|
|
2807
2849
|
var PUBLIC_POST_PREFIXES = ["/internal/sessions/"];
|
|
@@ -3398,16 +3440,14 @@ var createWsRoutes = (deps, upgradeWebSocket) => {
|
|
|
3398
3440
|
const app = new import_hono11.Hono();
|
|
3399
3441
|
app.get(
|
|
3400
3442
|
"/ws",
|
|
3401
|
-
upgradeWebSocket((
|
|
3402
|
-
const key = c.req.query("key");
|
|
3403
|
-
const preAuthed = typeof key === "string" && validateApiKey(key, deps.apiKey);
|
|
3443
|
+
upgradeWebSocket(() => {
|
|
3404
3444
|
let openWs = null;
|
|
3405
3445
|
return {
|
|
3406
3446
|
onOpen(_evt, ws) {
|
|
3407
3447
|
const raw = ws.raw;
|
|
3408
3448
|
if (!raw) return;
|
|
3409
3449
|
openWs = raw;
|
|
3410
|
-
deps.handleWsOpen(raw
|
|
3450
|
+
deps.handleWsOpen(raw);
|
|
3411
3451
|
},
|
|
3412
3452
|
onMessage(evt, _ws) {
|
|
3413
3453
|
if (openWs) deps.handleWsMessage(openWs, evt.data);
|
|
@@ -5313,13 +5353,6 @@ function deriveProjectChatTitle(input) {
|
|
|
5313
5353
|
return `Untitled \xB7 ${input.id.slice(0, 8)}`;
|
|
5314
5354
|
}
|
|
5315
5355
|
|
|
5316
|
-
// src/services/questions/permissionAnswerKeys.ts
|
|
5317
|
-
var ANSWER_KEYS_ALLOWLIST = /^(?:\r|[yn]\r|\x03|\d+\r)$/;
|
|
5318
|
-
function sanitizeAnswerKeys(keys) {
|
|
5319
|
-
if (keys === void 0) return void 0;
|
|
5320
|
-
return ANSWER_KEYS_ALLOWLIST.test(keys) ? keys : void 0;
|
|
5321
|
-
}
|
|
5322
|
-
|
|
5323
5356
|
// src/services/questions/detectAskUserQuestion.ts
|
|
5324
5357
|
function normalizeContent2(raw) {
|
|
5325
5358
|
if (Array.isArray(raw)) return raw;
|
|
@@ -5924,8 +5957,6 @@ var WSHub = class {
|
|
|
5924
5957
|
var BROWSE_SYSTEM_PROMPT = (browseRoot) => `You are working within the project boundary: ${browseRoot}. Do not read, write, or execute commands that access files or directories outside this boundary.`;
|
|
5925
5958
|
var DEFAULT_SYSTEM_PROMPT = "When presenting options or choices to the user, limit the options to at most 3.";
|
|
5926
5959
|
var DEFAULT_PTY_GRACE_PERIOD_MS = 27e4;
|
|
5927
|
-
var DEFAULT_WS_AUTH_TIMEOUT_MS = 5e3;
|
|
5928
|
-
var WS_CLOSE_UNAUTHORIZED = 4401;
|
|
5929
5960
|
var REFRESH_TTL_MS = 2e3;
|
|
5930
5961
|
var START_READY_TIMEOUT_MS = 1e4;
|
|
5931
5962
|
function parseIncludeAgentsEnv(raw) {
|
|
@@ -6016,14 +6047,6 @@ var StreamerServer = class {
|
|
|
6016
6047
|
clientIdToWs = /* @__PURE__ */ new Map();
|
|
6017
6048
|
// Reverse map for cleanup on close
|
|
6018
6049
|
wsToClientId = /* @__PURE__ */ new Map();
|
|
6019
|
-
// M1 — WS auth. Sockets that have authenticated (via ?key= at upgrade OR a
|
|
6020
|
-
// { type: "auth", token } first message). Only authed sockets are added to
|
|
6021
|
-
// the hub and receive broadcasts.
|
|
6022
|
-
// Plan: https://github.com/RonenMars/threadbase-streamer/blob/a251353bfa417bd48ce3f15086bc336a2c622629/docs/plans/2026-06-24-security-hardening.md#L40
|
|
6023
|
-
wsAuthed = /* @__PURE__ */ new Set();
|
|
6024
|
-
// Keyless sockets awaiting their first-message auth handshake → close timer.
|
|
6025
|
-
wsAuthPending = /* @__PURE__ */ new Map();
|
|
6026
|
-
wsAuthTimeoutMs;
|
|
6027
6050
|
cache = null;
|
|
6028
6051
|
projectsRepo = null;
|
|
6029
6052
|
conversationsRepo = null;
|
|
@@ -6063,7 +6086,6 @@ var StreamerServer = class {
|
|
|
6063
6086
|
this.scanProfiles = config.scanProfiles;
|
|
6064
6087
|
this.codexRoots = config.codexRoots ?? [(0, import_path14.join)((0, import_os7.homedir)(), ".codex", "sessions")];
|
|
6065
6088
|
this.ptyGracePeriodMs = config.ptyGracePeriodMs ?? DEFAULT_PTY_GRACE_PERIOD_MS;
|
|
6066
|
-
this.wsAuthTimeoutMs = config.wsAuthTimeoutMs ?? DEFAULT_WS_AUTH_TIMEOUT_MS;
|
|
6067
6089
|
this.defaultSystemPrompt = config.defaultSystemPrompt ?? DEFAULT_SYSTEM_PROMPT;
|
|
6068
6090
|
this.defaultPermissionMode = config.defaultPermissionMode ?? loadDefaultPermissionMode() ?? "acceptEdits";
|
|
6069
6091
|
this.cacheDir = config.cacheDir ?? loadCacheDir() ?? (0, import_path14.join)((0, import_os7.homedir)(), ".threadbase", "cache");
|
|
@@ -6192,6 +6214,9 @@ var StreamerServer = class {
|
|
|
6192
6214
|
onOutput: (sessionId, data) => {
|
|
6193
6215
|
this.wsHub.broadcast({ type: "terminal_output", sessionId, data });
|
|
6194
6216
|
},
|
|
6217
|
+
onUserMessage: (sessionId, text, ts) => {
|
|
6218
|
+
this.wsHub.broadcast({ type: "user_message", sessionId, text, ts });
|
|
6219
|
+
},
|
|
6195
6220
|
onPermissionChange: (sessionId, gate) => {
|
|
6196
6221
|
this.handlePermissionChange(sessionId, gate);
|
|
6197
6222
|
},
|
|
@@ -6321,39 +6346,17 @@ var StreamerServer = class {
|
|
|
6321
6346
|
handlePairExchange: (req, res) => this.handlePairExchange(req, res),
|
|
6322
6347
|
handleBrowse: (url, res) => this.handleBrowse(url, res),
|
|
6323
6348
|
handleMkdir: (req, res) => this.handleMkdir(req, res),
|
|
6324
|
-
handleWsOpen: (ws
|
|
6325
|
-
|
|
6326
|
-
|
|
6327
|
-
|
|
6349
|
+
handleWsOpen: (ws) => {
|
|
6350
|
+
this.wsHub.addClient(ws);
|
|
6351
|
+
const sessions = this.sessionStore.list(this.ptyAttachedIds());
|
|
6352
|
+
ws.send(JSON.stringify({ type: "session_list", sessions }));
|
|
6353
|
+
if (this.cacheReady) {
|
|
6354
|
+
ws.send(JSON.stringify({ type: "cache_ready" }));
|
|
6328
6355
|
}
|
|
6329
|
-
const timer = setTimeout(() => {
|
|
6330
|
-
this.wsAuthPending.delete(ws);
|
|
6331
|
-
try {
|
|
6332
|
-
ws.close(WS_CLOSE_UNAUTHORIZED, "auth timeout");
|
|
6333
|
-
} catch {
|
|
6334
|
-
}
|
|
6335
|
-
}, this.wsAuthTimeoutMs);
|
|
6336
|
-
this.wsAuthPending.set(ws, timer);
|
|
6337
6356
|
},
|
|
6338
6357
|
handleWsMessage: async (ws, raw) => {
|
|
6339
6358
|
try {
|
|
6340
6359
|
const msg = JSON.parse(String(raw));
|
|
6341
|
-
if (!this.wsAuthed.has(ws)) {
|
|
6342
|
-
if (msg.type === "auth" && typeof msg.token === "string") {
|
|
6343
|
-
const t = this.wsAuthPending.get(ws);
|
|
6344
|
-
if (t) clearTimeout(t);
|
|
6345
|
-
this.wsAuthPending.delete(ws);
|
|
6346
|
-
if (validateApiKey(msg.token, this.apiKey)) {
|
|
6347
|
-
this.completeWsAuth(ws);
|
|
6348
|
-
} else {
|
|
6349
|
-
try {
|
|
6350
|
-
ws.close(WS_CLOSE_UNAUTHORIZED, "unauthorized");
|
|
6351
|
-
} catch {
|
|
6352
|
-
}
|
|
6353
|
-
}
|
|
6354
|
-
}
|
|
6355
|
-
return;
|
|
6356
|
-
}
|
|
6357
6360
|
if (msg.type === "register" && typeof msg.clientId === "string") {
|
|
6358
6361
|
const oldClientId = this.wsToClientId.get(ws);
|
|
6359
6362
|
if (oldClientId) this.clientIdToWs.delete(oldClientId);
|
|
@@ -6364,7 +6367,15 @@ var StreamerServer = class {
|
|
|
6364
6367
|
this.addSessionSubscriber(msg.sessionId, ws);
|
|
6365
6368
|
if (this.ptyManager.hasSession(msg.sessionId)) {
|
|
6366
6369
|
const lines = await this.ptyManager.getOutputLines(msg.sessionId, 200);
|
|
6367
|
-
|
|
6370
|
+
const userMessages = this.ptyManager.getInputHistory(msg.sessionId);
|
|
6371
|
+
ws.send(
|
|
6372
|
+
JSON.stringify({
|
|
6373
|
+
type: "terminal_replay",
|
|
6374
|
+
sessionId: msg.sessionId,
|
|
6375
|
+
lines,
|
|
6376
|
+
userMessages
|
|
6377
|
+
})
|
|
6378
|
+
);
|
|
6368
6379
|
}
|
|
6369
6380
|
const pendingGate = this.pendingPermission.get(msg.sessionId);
|
|
6370
6381
|
if (pendingGate) {
|
|
@@ -6400,20 +6411,12 @@ var StreamerServer = class {
|
|
|
6400
6411
|
}
|
|
6401
6412
|
}
|
|
6402
6413
|
if (msg.type === "hold_session" && typeof msg.sessionId === "string") {
|
|
6403
|
-
|
|
6404
|
-
this.startGraceTimer(msg.sessionId, 0);
|
|
6405
|
-
}
|
|
6414
|
+
this.startGraceTimer(msg.sessionId, 0);
|
|
6406
6415
|
}
|
|
6407
6416
|
} catch {
|
|
6408
6417
|
}
|
|
6409
6418
|
},
|
|
6410
6419
|
handleWsClose: (ws) => {
|
|
6411
|
-
const pendingTimer = this.wsAuthPending.get(ws);
|
|
6412
|
-
if (pendingTimer) {
|
|
6413
|
-
clearTimeout(pendingTimer);
|
|
6414
|
-
this.wsAuthPending.delete(ws);
|
|
6415
|
-
}
|
|
6416
|
-
this.wsAuthed.delete(ws);
|
|
6417
6420
|
const clientId = this.wsToClientId.get(ws);
|
|
6418
6421
|
if (clientId) {
|
|
6419
6422
|
this.clientIdToWs.delete(clientId);
|
|
@@ -6483,20 +6486,6 @@ var StreamerServer = class {
|
|
|
6483
6486
|
this.wsHub.broadcast(payload);
|
|
6484
6487
|
}
|
|
6485
6488
|
}
|
|
6486
|
-
// M1: finalize a WebSocket auth (via ?key= at upgrade or a first-message
|
|
6487
|
-
// handshake) — register it with the hub and send the initial snapshot. Only
|
|
6488
|
-
// authed sockets reach this, so no unauthenticated client ever receives a
|
|
6489
|
-
// broadcast.
|
|
6490
|
-
// Plan: https://github.com/RonenMars/threadbase-streamer/blob/a251353bfa417bd48ce3f15086bc336a2c622629/docs/plans/2026-06-24-security-hardening.md#L40
|
|
6491
|
-
completeWsAuth(ws) {
|
|
6492
|
-
this.wsAuthed.add(ws);
|
|
6493
|
-
this.wsHub.addClient(ws);
|
|
6494
|
-
const sessions = this.sessionStore.list(this.ptyAttachedIds());
|
|
6495
|
-
ws.send(JSON.stringify({ type: "session_list", sessions }));
|
|
6496
|
-
if (this.cacheReady) {
|
|
6497
|
-
ws.send(JSON.stringify({ type: "cache_ready" }));
|
|
6498
|
-
}
|
|
6499
|
-
}
|
|
6500
6489
|
addSessionSubscriber(sessionId, ws) {
|
|
6501
6490
|
let subs = this.sessionSubscribers.get(sessionId);
|
|
6502
6491
|
if (!subs) {
|
|
@@ -6783,9 +6772,6 @@ var StreamerServer = class {
|
|
|
6783
6772
|
this.ptyManager.dispose();
|
|
6784
6773
|
this.fileWatcher.dispose();
|
|
6785
6774
|
this.wsHub.dispose();
|
|
6786
|
-
for (const timer of this.wsAuthPending.values()) clearTimeout(timer);
|
|
6787
|
-
this.wsAuthPending.clear();
|
|
6788
|
-
this.wsAuthed.clear();
|
|
6789
6775
|
this.pairTokens.dispose();
|
|
6790
6776
|
if (this.dbPool) {
|
|
6791
6777
|
await this.dbPool.end();
|
|
@@ -7912,10 +7898,6 @@ var StreamerServer = class {
|
|
|
7912
7898
|
return;
|
|
7913
7899
|
}
|
|
7914
7900
|
this.pendingPermission.set(sessionId, gate);
|
|
7915
|
-
const safeOptions = gate.options.map((o) => {
|
|
7916
|
-
const answerKeys = sanitizeAnswerKeys(o.answerKeys);
|
|
7917
|
-
return answerKeys === void 0 ? { index: o.index, label: o.label } : { ...o, answerKeys };
|
|
7918
|
-
});
|
|
7919
7901
|
const subscriberCount = this.sessionSubscribers.get(sessionId)?.size ?? 0;
|
|
7920
7902
|
this.log.info(
|
|
7921
7903
|
`[ws.broadcast_permission] ${sessionId.slice(0, 8)} subscribers=${subscriberCount}`,
|
|
@@ -7926,7 +7908,7 @@ var StreamerServer = class {
|
|
|
7926
7908
|
sessionId,
|
|
7927
7909
|
...gate.prompt ? { prompt: gate.prompt } : {},
|
|
7928
7910
|
...gate.detail ? { detail: gate.detail } : {},
|
|
7929
|
-
options:
|
|
7911
|
+
options: gate.options,
|
|
7930
7912
|
...gate.cursor !== void 0 ? { cursor: gate.cursor } : {}
|
|
7931
7913
|
});
|
|
7932
7914
|
}
|