@threadbase-sh/streamer 1.31.1 → 1.31.3

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 CHANGED
@@ -29489,6 +29489,7 @@ var require_receiver = __commonJS({
29489
29489
  this._opcode = 0;
29490
29490
  this._totalPayloadLength = 0;
29491
29491
  this._messageLength = 0;
29492
+ this._numFragments = 0;
29492
29493
  this._fragments = [];
29493
29494
  this._errored = false;
29494
29495
  this._loop = false;
@@ -29839,23 +29840,23 @@ var require_receiver = __commonJS({
29839
29840
  this.controlMessage(data, cb2);
29840
29841
  return;
29841
29842
  }
29843
+ if (this._maxFragments > 0 && ++this._numFragments > this._maxFragments) {
29844
+ const error51 = this.createError(
29845
+ RangeError,
29846
+ "Too many message fragments",
29847
+ false,
29848
+ 1008,
29849
+ "WS_ERR_TOO_MANY_BUFFERED_PARTS"
29850
+ );
29851
+ cb2(error51);
29852
+ return;
29853
+ }
29842
29854
  if (this._compressed) {
29843
29855
  this._state = INFLATING;
29844
29856
  this.decompress(data, cb2);
29845
29857
  return;
29846
29858
  }
29847
29859
  if (data.length) {
29848
- if (this._maxFragments > 0 && this._fragments.length >= this._maxFragments) {
29849
- const error51 = this.createError(
29850
- RangeError,
29851
- "Too many message fragments",
29852
- false,
29853
- 1008,
29854
- "WS_ERR_TOO_MANY_BUFFERED_PARTS"
29855
- );
29856
- cb2(error51);
29857
- return;
29858
- }
29859
29860
  this._messageLength = this._totalPayloadLength;
29860
29861
  this._fragments.push(data);
29861
29862
  }
@@ -29885,17 +29886,6 @@ var require_receiver = __commonJS({
29885
29886
  cb2(error51);
29886
29887
  return;
29887
29888
  }
29888
- if (this._maxFragments > 0 && this._fragments.length >= this._maxFragments) {
29889
- const error51 = this.createError(
29890
- RangeError,
29891
- "Too many message fragments",
29892
- false,
29893
- 1008,
29894
- "WS_ERR_TOO_MANY_BUFFERED_PARTS"
29895
- );
29896
- cb2(error51);
29897
- return;
29898
- }
29899
29889
  this._fragments.push(buf);
29900
29890
  }
29901
29891
  this.dataMessage(cb2);
@@ -29918,6 +29908,7 @@ var require_receiver = __commonJS({
29918
29908
  this._totalPayloadLength = 0;
29919
29909
  this._messageLength = 0;
29920
29910
  this._fragmented = 0;
29911
+ this._numFragments = 0;
29921
29912
  this._fragments = [];
29922
29913
  if (this._opcode === 2) {
29923
29914
  let data;
@@ -31418,8 +31409,8 @@ var require_websocket = __commonJS({
31418
31409
  autoPong: true,
31419
31410
  closeTimeout: CLOSE_TIMEOUT,
31420
31411
  protocolVersion: protocolVersions[1],
31421
- maxBufferedChunks: 1024 * 1024,
31422
- maxFragments: 128 * 1024,
31412
+ maxBufferedChunks: 256 * 1024,
31413
+ maxFragments: 16 * 1024,
31423
31414
  maxPayload: 100 * 1024 * 1024,
31424
31415
  skipUTF8Validation: false,
31425
31416
  perMessageDeflate: true,
@@ -32006,9 +31997,9 @@ var require_websocket_server = __commonJS({
32006
31997
  * called
32007
31998
  * @param {Function} [options.handleProtocols] A hook to handle protocols
32008
31999
  * @param {String} [options.host] The hostname where to bind the server
32009
- * @param {Number} [options.maxBufferedChunks=1048576] The maximum number of
32000
+ * @param {Number} [options.maxBufferedChunks=262144] The maximum number of
32010
32001
  * buffered data chunks
32011
- * @param {Number} [options.maxFragments=131072] The maximum number of message
32002
+ * @param {Number} [options.maxFragments=16384] The maximum number of message
32012
32003
  * fragments
32013
32004
  * @param {Number} [options.maxPayload=104857600] The maximum allowed message
32014
32005
  * size
@@ -32031,8 +32022,8 @@ var require_websocket_server = __commonJS({
32031
32022
  options = {
32032
32023
  allowSynchronousEvents: true,
32033
32024
  autoPong: true,
32034
- maxBufferedChunks: 1024 * 1024,
32035
- maxFragments: 128 * 1024,
32025
+ maxBufferedChunks: 256 * 1024,
32026
+ maxFragments: 16 * 1024,
32036
32027
  maxPayload: 100 * 1024 * 1024,
32037
32028
  skipUTF8Validation: false,
32038
32029
  perMessageDeflate: false,
@@ -145337,14 +145328,8 @@ var StreamerServer = class {
145337
145328
  this.conversationsRepo = new ConversationsRepository(this.cache);
145338
145329
  this.sessionsRepo = new SessionsRepository(this.sessionStore);
145339
145330
  this.cacheMetadataRepo = new CacheMetadataRepository(db);
145340
- if (this.scanProfiles && this.scanProfiles.length > 0) {
145341
- for (const profile of this.scanProfiles) {
145342
- if (profile.enabled) {
145343
- this.fileWatcher.watchDirectory((0, import_path23.join)(profile.configDir, "projects"));
145344
- }
145345
- }
145346
- } else {
145347
- this.fileWatcher.watchDirectory((0, import_path23.join)((0, import_os11.homedir)(), ".claude", "projects"));
145331
+ for (const dir of this.projectsDirs()) {
145332
+ this.fileWatcher.watchDirectory(dir);
145348
145333
  }
145349
145334
  } catch (err) {
145350
145335
  const message = err instanceof Error ? err.message : String(err);
@@ -145925,20 +145910,35 @@ var StreamerServer = class {
145925
145910
  await this.scannerReady;
145926
145911
  return scanner;
145927
145912
  }
145913
+ /**
145914
+ * The projects dirs disk discovery should walk — the single source of truth
145915
+ * for "where do this server's JSONLs live", mirroring the warm-up watcher
145916
+ * (see listen()). Derived from the enabled scanProfiles' configDirs, or the
145917
+ * real ~/.claude/projects when no profiles are configured. An all-disabled
145918
+ * profile set intentionally yields [] (nothing to discover), matching the
145919
+ * watcher — it does NOT fall back to home in that case.
145920
+ */
145921
+ projectsDirs() {
145922
+ if (this.scanProfiles && this.scanProfiles.length > 0) {
145923
+ return this.scanProfiles.filter((p2) => p2.enabled).map((p2) => (0, import_path23.join)(p2.configDir, "projects"));
145924
+ }
145925
+ return [(0, import_path23.join)((0, import_os11.homedir)(), ".claude", "projects")];
145926
+ }
145928
145927
  findJsonlPath(uuid3) {
145929
- const projectsDir = (0, import_path23.join)((0, import_os11.homedir)(), ".claude", "projects");
145930
- if (!(0, import_fs26.existsSync)(projectsDir)) return null;
145931
145928
  const filename = `${uuid3}.jsonl`;
145932
- for (const dir of (0, import_fs26.readdirSync)(projectsDir)) {
145933
- const fp = (0, import_path23.join)(projectsDir, dir, filename);
145934
- if ((0, import_fs26.existsSync)(fp)) return fp;
145935
- const projectDir = (0, import_path23.join)(projectsDir, dir);
145936
- try {
145937
- for (const sub of (0, import_fs26.readdirSync)(projectDir)) {
145938
- const subagentPath = (0, import_path23.join)(projectDir, sub, "subagents", filename);
145939
- if ((0, import_fs26.existsSync)(subagentPath)) return subagentPath;
145929
+ for (const projectsDir of this.projectsDirs()) {
145930
+ if (!(0, import_fs26.existsSync)(projectsDir)) continue;
145931
+ for (const dir of (0, import_fs26.readdirSync)(projectsDir)) {
145932
+ const fp = (0, import_path23.join)(projectsDir, dir, filename);
145933
+ if ((0, import_fs26.existsSync)(fp)) return fp;
145934
+ const projectDir = (0, import_path23.join)(projectsDir, dir);
145935
+ try {
145936
+ for (const sub of (0, import_fs26.readdirSync)(projectDir)) {
145937
+ const subagentPath = (0, import_path23.join)(projectDir, sub, "subagents", filename);
145938
+ if ((0, import_fs26.existsSync)(subagentPath)) return subagentPath;
145939
+ }
145940
+ } catch {
145940
145941
  }
145941
- } catch {
145942
145942
  }
145943
145943
  }
145944
145944
  return null;
@@ -147757,7 +147757,81 @@ async function stopService(opts = {}) {
147757
147757
  const { stdout: stdout2, stderr } = await execFileP("schtasks.exe", ["/End", "/TN", label]).catch(
147758
147758
  (err) => ({ stdout: "", stderr: String(err) })
147759
147759
  );
147760
- return { method: "schtasks-end", stdout: stdout2, stderr };
147760
+ const listenerResult = await stopWindowsListener(opts.port ?? 8766);
147761
+ return {
147762
+ method: "schtasks-end",
147763
+ stdout: `${stdout2}
147764
+ ${listenerResult.stdout}`,
147765
+ stderr: `${stderr}
147766
+ ${listenerResult.stderr}`
147767
+ };
147768
+ }
147769
+ async function stopWindowsListener(port) {
147770
+ let netstat;
147771
+ try {
147772
+ netstat = await execFileP("netstat.exe", ["-ano", "-p", "tcp"]);
147773
+ } catch (err) {
147774
+ return { stdout: "", stderr: `Could not inspect port ${port}: ${String(err)}` };
147775
+ }
147776
+ const pids = /* @__PURE__ */ new Set();
147777
+ for (const line of netstat.stdout.split(/\r?\n/)) {
147778
+ const columns = line.trim().split(/\s+/);
147779
+ if (columns.length < 5 || columns[0]?.toUpperCase() !== "TCP") continue;
147780
+ const [localAddress, state, pid] = [columns[1], columns[3], columns[4]];
147781
+ if (state?.toUpperCase() !== "LISTENING" || !pid || pid === "0") continue;
147782
+ if (localAddress?.endsWith(`:${port}`)) pids.add(pid);
147783
+ }
147784
+ const output = [];
147785
+ const errors = [];
147786
+ for (const pid of pids) {
147787
+ try {
147788
+ const result = await execFileP("taskkill.exe", ["/PID", pid, "/T", "/F"]);
147789
+ output.push(result.stdout);
147790
+ if (result.stderr) errors.push(result.stderr);
147791
+ } catch (err) {
147792
+ errors.push(`Could not stop PID ${pid} on port ${port}: ${String(err)}`);
147793
+ }
147794
+ }
147795
+ return { stdout: output.join("\n"), stderr: errors.join("\n") };
147796
+ }
147797
+
147798
+ // src/updater/restart-health.ts
147799
+ function isExpectedVersion(actual, expected) {
147800
+ return actual === expected || actual.startsWith(`${expected}+`);
147801
+ }
147802
+ async function waitForRestartHealth(opts) {
147803
+ const timeoutMs = opts.timeoutMs ?? 15e3;
147804
+ const pollIntervalMs = opts.pollIntervalMs ?? 250;
147805
+ const deadline = Date.now() + timeoutMs;
147806
+ let lastFailure = "server did not respond";
147807
+ while (Date.now() <= deadline) {
147808
+ const controller = new AbortController();
147809
+ const requestTimer = setTimeout(() => controller.abort(), Math.min(2e3, timeoutMs));
147810
+ try {
147811
+ const response = await fetch(`http://127.0.0.1:${opts.port}/healthz`, {
147812
+ signal: controller.signal
147813
+ });
147814
+ if (response.ok) {
147815
+ const body = await response.json();
147816
+ if (body.ok === true && typeof body.version === "string") {
147817
+ if (isExpectedVersion(body.version, opts.expectedVersion)) return;
147818
+ lastFailure = `running version is ${body.version}, expected ${opts.expectedVersion}`;
147819
+ } else {
147820
+ lastFailure = "health response is missing ok/version";
147821
+ }
147822
+ } else {
147823
+ lastFailure = `health endpoint returned ${response.status}`;
147824
+ }
147825
+ } catch (err) {
147826
+ lastFailure = err instanceof Error ? err.message : String(err);
147827
+ } finally {
147828
+ clearTimeout(requestTimer);
147829
+ }
147830
+ const remaining = deadline - Date.now();
147831
+ if (remaining <= 0) break;
147832
+ await new Promise((resolve6) => setTimeout(resolve6, Math.min(pollIntervalMs, remaining)));
147833
+ }
147834
+ throw new Error(`restart verification failed: ${lastFailure}`);
147761
147835
  }
147762
147836
 
147763
147837
  // src/updater/stamp-version.ts
@@ -150899,7 +150973,7 @@ async function runInstall(opts) {
150899
150973
  await unpackTarball({ tarballPath, destDir });
150900
150974
  stampVersionTxt(destDir, targetVersion);
150901
150975
  if (process.platform === "win32") {
150902
- await stopService().catch(() => {
150976
+ await stopService({ port: opts.runningServer?.port }).catch(() => {
150903
150977
  });
150904
150978
  }
150905
150979
  swapCurrent(targetVersion);
@@ -150908,6 +150982,12 @@ async function runInstall(opts) {
150908
150982
  try {
150909
150983
  const r = await restartService();
150910
150984
  restartMethod = r.method;
150985
+ if (opts.runningServer && r.method !== "none") {
150986
+ await waitForRestartHealth({
150987
+ port: opts.runningServer.port,
150988
+ expectedVersion: targetVersion
150989
+ });
150990
+ }
150911
150991
  } catch (err) {
150912
150992
  restartMethod = `failed: ${err instanceof Error ? err.message : String(err)}`;
150913
150993
  }
@@ -150918,8 +150998,9 @@ async function runInstall(opts) {
150918
150998
  pruned,
150919
150999
  restart: { method: restartMethod }
150920
151000
  };
151001
+ const outcome = restartMethod.startsWith("failed:") ? "failed" : "installed";
150921
151002
  appendUpdateLog(
150922
- `[installed] ${installed.previous} \u2192 ${installed.installed} restart=${installed.restart.method}${pruned.length > 0 ? ` pruned=${pruned.length}` : ""}`
151003
+ `[${outcome}] ${installed.previous} \u2192 ${installed.installed} restart=${installed.restart.method}${pruned.length > 0 ? ` pruned=${pruned.length}` : ""}`
150923
151004
  );
150924
151005
  return installed;
150925
151006
  }
@@ -151378,11 +151459,20 @@ program2.command("update").description("Check for streamer updates from GitHub R
151378
151459
  );
151379
151460
  break;
151380
151461
  case "installed":
151381
- log7.info(
151382
- `Installed ${result.installed} (was ${result.previous}). Restart: ${result.restart.method}.`,
151383
- void 0,
151384
- "console"
151385
- );
151462
+ if (result.restart.method.startsWith("failed:")) {
151463
+ log7.error(
151464
+ `Installed ${result.installed} on disk, but the running service was not updated. Restart: ${result.restart.method}.`,
151465
+ void 0,
151466
+ "console"
151467
+ );
151468
+ process.exitCode = 1;
151469
+ } else {
151470
+ log7.info(
151471
+ `Installed ${result.installed} (was ${result.previous}). Restart: ${result.restart.method}.`,
151472
+ void 0,
151473
+ "console"
151474
+ );
151475
+ }
151386
151476
  if (result.pruned.length > 0) {
151387
151477
  log7.info(`Pruned old releases: ${result.pruned.join(", ")}`, void 0, "console");
151388
151478
  }