@staff0rd/assist 0.321.0 → 0.322.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.
Files changed (2) hide show
  1. package/dist/index.js +114 -31
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import { Command } from "commander";
6
6
  // package.json
7
7
  var package_default = {
8
8
  name: "@staff0rd/assist",
9
- version: "0.321.0",
9
+ version: "0.322.0",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -1556,19 +1556,19 @@ function moveCaseInsensitive(absSource, absDest) {
1556
1556
  fs9.renameSync(absSource, tmp);
1557
1557
  fs9.renameSync(tmp, absDest);
1558
1558
  }
1559
- function applyMoves(project, moves, cwd, emit2) {
1559
+ function applyMoves(project, moves, cwd, emit4) {
1560
1560
  for (const { sourcePath, destPath } of moves) {
1561
1561
  const start3 = performance.now();
1562
1562
  const absSource = path15.resolve(sourcePath);
1563
1563
  const absDest = path15.resolve(destPath);
1564
1564
  for (const r of renameExports(project, absSource, absDest)) {
1565
- emit2(` Renamed export ${r} in ${sourcePath}`);
1565
+ emit4(` Renamed export ${r} in ${sourcePath}`);
1566
1566
  }
1567
1567
  const sourceFile = project.getSourceFile(absSource);
1568
1568
  if (sourceFile) sourceFile.move(absDest);
1569
1569
  const ms = (performance.now() - start3).toFixed(0);
1570
1570
  const rel = `${path15.relative(cwd, absSource)} \u2192 ${path15.relative(cwd, absDest)}`;
1571
- emit2(` Renamed ${rel} (${ms}ms)`);
1571
+ emit4(` Renamed ${rel} (${ms}ms)`);
1572
1572
  }
1573
1573
  project.saveSync();
1574
1574
  for (const { sourcePath, destPath } of moves) {
@@ -6728,6 +6728,44 @@ function installRestartMenu(options2 = {}) {
6728
6728
  return cleanup;
6729
6729
  }
6730
6730
 
6731
+ // src/commands/sessions/web/streamDaemonLogs.ts
6732
+ import { createInterface as createInterface3 } from "readline";
6733
+ var RECONNECT_MS = 3e3;
6734
+ function streamDaemonLogs() {
6735
+ void connect2();
6736
+ }
6737
+ async function connect2() {
6738
+ try {
6739
+ await ensureDaemonRunning("web log stream");
6740
+ const socket = await connectToDaemon();
6741
+ wire(socket);
6742
+ socket.write(`${JSON.stringify({ type: "subscribe-logs" })}
6743
+ `);
6744
+ } catch {
6745
+ scheduleReconnect();
6746
+ }
6747
+ }
6748
+ function wire(socket) {
6749
+ const lines = createInterface3({ input: socket });
6750
+ lines.on("error", () => {
6751
+ });
6752
+ lines.on("line", emit);
6753
+ socket.on("error", () => {
6754
+ });
6755
+ socket.on("close", scheduleReconnect);
6756
+ }
6757
+ function emit(line) {
6758
+ try {
6759
+ const data = JSON.parse(line);
6760
+ if (data.type === "log" && typeof data.line === "string")
6761
+ console.log(data.line);
6762
+ } catch {
6763
+ }
6764
+ }
6765
+ function scheduleReconnect() {
6766
+ setTimeout(() => void connect2(), RECONNECT_MS).unref();
6767
+ }
6768
+
6731
6769
  // src/commands/sessions/web/index.ts
6732
6770
  async function web(options2) {
6733
6771
  const port = Number.parseInt(options2.port, 10);
@@ -6754,6 +6792,7 @@ async function web(options2) {
6754
6792
  }
6755
6793
  });
6756
6794
  installRestartMenu();
6795
+ streamDaemonLogs();
6757
6796
  void ensureDaemonRunning("web server start").catch((error) => {
6758
6797
  console.error(
6759
6798
  chalk55.yellow(
@@ -11669,7 +11708,7 @@ function advisory(count6) {
11669
11708
  const noun = count6 === 1 ? "handover" : "handovers";
11670
11709
  return `${count6} unrecalled ${noun} for this repo. Run /recall to load.`;
11671
11710
  }
11672
- function emit(message) {
11711
+ function emit2(message) {
11673
11712
  const json = JSON.stringify({
11674
11713
  hookSpecificOutput: { hookEventName: "SessionStart" },
11675
11714
  systemMessage: message
@@ -11686,7 +11725,7 @@ async function load2(options2 = {}) {
11686
11725
  await migrateDiskHandovers(orm, origin, cwd);
11687
11726
  const count6 = await countPendingHandovers(orm, origin);
11688
11727
  if (count6 === 0) return null;
11689
- return emit(advisory(count6));
11728
+ return emit2(advisory(count6));
11690
11729
  }
11691
11730
 
11692
11731
  // src/commands/handover/listPendingHandovers.ts
@@ -12401,25 +12440,25 @@ function isVisibleText(t) {
12401
12440
  return /[a-zA-Z]{3,}/.test(t);
12402
12441
  }
12403
12442
  var isHashtag = (t) => /^#[A-Za-z0-9_]+$/.test(t);
12404
- function collectRscText(v, resolve17, sink, seen) {
12443
+ function collectRscText(v, resolve17, sink2, seen) {
12405
12444
  if (v == null) return;
12406
12445
  if (typeof v === "string") {
12407
12446
  if (isRscRef(v)) {
12408
12447
  if (!seen.has(v)) {
12409
12448
  seen.add(v);
12410
- collectRscText(resolve17(v), resolve17, sink, seen);
12449
+ collectRscText(resolve17(v), resolve17, sink2, seen);
12411
12450
  }
12412
- } else if (isHashtag(v)) sink.hashtags.push(v);
12413
- else if (isVisibleText(v)) sink.text.push(v);
12451
+ } else if (isHashtag(v)) sink2.hashtags.push(v);
12452
+ else if (isVisibleText(v)) sink2.text.push(v);
12414
12453
  return;
12415
12454
  }
12416
12455
  if (Array.isArray(v)) {
12417
- for (const x of v) collectRscText(x, resolve17, sink, seen);
12456
+ for (const x of v) collectRscText(x, resolve17, sink2, seen);
12418
12457
  return;
12419
12458
  }
12420
12459
  if (typeof v === "object") {
12421
12460
  for (const val of Object.values(v)) {
12422
- collectRscText(val, resolve17, sink, seen);
12461
+ collectRscText(val, resolve17, sink2, seen);
12423
12462
  }
12424
12463
  }
12425
12464
  }
@@ -12458,9 +12497,9 @@ function buildMentionMap(rows, resolve17) {
12458
12497
  if (!url || o.children == null) return;
12459
12498
  const slug = slugFromProfileUrl(url);
12460
12499
  if (!slug || map.has(slug)) return;
12461
- const sink = { text: [], hashtags: [] };
12462
- collectRscText(o.children, resolve17, sink, /* @__PURE__ */ new Set());
12463
- const name = sink.text.join(" ").replace(/\s+/g, " ").trim();
12500
+ const sink2 = { text: [], hashtags: [] };
12501
+ collectRscText(o.children, resolve17, sink2, /* @__PURE__ */ new Set());
12502
+ const name = sink2.text.join(" ").replace(/\s+/g, " ").trim();
12464
12503
  map.set(slug, name ? { slug, name, url } : { slug, url });
12465
12504
  });
12466
12505
  return map;
@@ -12561,8 +12600,8 @@ function walkPostRow(v, resolve17, raw) {
12561
12600
  if (a) raw.related.push(a[0]);
12562
12601
  }
12563
12602
  if (isCommentary(o)) {
12564
- const sink = { text: raw.text, hashtags: raw.hashtags };
12565
- collectRscText(o.children, resolve17, sink, /* @__PURE__ */ new Set());
12603
+ const sink2 = { text: raw.text, hashtags: raw.hashtags };
12604
+ collectRscText(o.children, resolve17, sink2, /* @__PURE__ */ new Set());
12566
12605
  }
12567
12606
  for (const val of Object.values(o)) walkPostRow(val, resolve17, raw);
12568
12607
  }
@@ -19985,7 +20024,7 @@ function listDaemonPids() {
19985
20024
  }
19986
20025
 
19987
20026
  // src/commands/sessions/daemon/queryDaemon.ts
19988
- import { createInterface as createInterface4 } from "readline";
20027
+ import { createInterface as createInterface5 } from "readline";
19989
20028
  var STATUS_TIMEOUT_MS = 5e3;
19990
20029
  function queryDaemon(socket) {
19991
20030
  socket.write(`${JSON.stringify({ type: "ping" })}
@@ -19994,7 +20033,7 @@ function queryDaemon(socket) {
19994
20033
  const result = { sessions: [] };
19995
20034
  const pending = /* @__PURE__ */ new Set(["sessions", "pong"]);
19996
20035
  const timer = setTimeout(() => resolve17(result), STATUS_TIMEOUT_MS);
19997
- const lines = createInterface4({ input: socket });
20036
+ const lines = createInterface5({ input: socket });
19998
20037
  lines.on("error", () => {
19999
20038
  });
20000
20039
  lines.on("line", (line) => {
@@ -20074,14 +20113,32 @@ function reportStrays(pids) {
20074
20113
  }
20075
20114
 
20076
20115
  // src/commands/sessions/daemon/drainDaemon.ts
20077
- import { createInterface as createInterface5 } from "readline";
20116
+ import { createInterface as createInterface6 } from "readline";
20078
20117
 
20079
20118
  // src/commands/sessions/daemon/loadPersistedSessions.ts
20080
20119
  import { z as z5 } from "zod";
20081
20120
 
20082
20121
  // src/commands/sessions/daemon/daemonLog.ts
20122
+ var RING_CAPACITY = 1e3;
20123
+ var ring = [];
20124
+ var sink;
20083
20125
  function daemonLog(message) {
20084
- console.log(`${(/* @__PURE__ */ new Date()).toISOString()} [${process.pid}] ${message}`);
20126
+ emit3(`${(/* @__PURE__ */ new Date()).toISOString()} [${process.pid}] ${message}`);
20127
+ }
20128
+ function relayDaemonLog(line) {
20129
+ emit3(`[windows] ${line}`);
20130
+ }
20131
+ function emit3(line) {
20132
+ console.log(line);
20133
+ ring.push(line);
20134
+ if (ring.length > RING_CAPACITY) ring.shift();
20135
+ sink?.(line);
20136
+ }
20137
+ function setDaemonLogSink(next3) {
20138
+ sink = next3;
20139
+ }
20140
+ function recentDaemonLogLines() {
20141
+ return [...ring];
20085
20142
  }
20086
20143
 
20087
20144
  // src/commands/sessions/daemon/loadPersistedSessions.ts
@@ -20163,7 +20220,7 @@ function requestDrain(socket) {
20163
20220
  `);
20164
20221
  return new Promise((resolve17) => {
20165
20222
  const timer = setTimeout(() => resolve17(0), DRAIN_TIMEOUT_MS);
20166
- const lines = createInterface5({ input: socket });
20223
+ const lines = createInterface6({ input: socket });
20167
20224
  lines.on("error", () => {
20168
20225
  });
20169
20226
  lines.on("line", (line) => {
@@ -20324,6 +20381,8 @@ var ClientHub = class extends Set {
20324
20381
  this.persistPeak = persistPeak;
20325
20382
  }
20326
20383
  latestLimits;
20384
+ // why: log delivery is opt-in so browser tabs aren't spammed; only connections that ask via subscribe-logs receive daemonLog lines.
20385
+ logSubscribers = /* @__PURE__ */ new Set();
20327
20386
  updateLimits(rateLimits) {
20328
20387
  this.latestLimits = rateLimits;
20329
20388
  broadcast(this, { type: "limits", rateLimits });
@@ -20334,6 +20393,21 @@ var ClientHub = class extends Set {
20334
20393
  sendTo(client, { type: "limits", rateLimits: this.latestLimits });
20335
20394
  }
20336
20395
  }
20396
+ subscribeLogs(client) {
20397
+ for (const line of recentDaemonLogLines()) {
20398
+ sendTo(client, { type: "log", line });
20399
+ }
20400
+ this.logSubscribers.add(client);
20401
+ }
20402
+ unsubscribeLogs(client) {
20403
+ this.logSubscribers.delete(client);
20404
+ }
20405
+ // why: bound so it can be handed to setDaemonLogSink as a bare reference.
20406
+ emitLog = (line) => {
20407
+ for (const client of this.logSubscribers) {
20408
+ sendTo(client, { type: "log", line });
20409
+ }
20410
+ };
20337
20411
  };
20338
20412
 
20339
20413
  // src/commands/sessions/daemon/spawnPty.ts
@@ -20940,10 +21014,10 @@ async function isWindowsDaemonRunning() {
20940
21014
  import { spawn as spawn10 } from "child_process";
20941
21015
 
20942
21016
  // src/commands/sessions/daemon/logChildStream.ts
20943
- import { createInterface as createInterface6 } from "readline";
21017
+ import { createInterface as createInterface7 } from "readline";
20944
21018
  function logChildStream(stream, label2) {
20945
21019
  if (!stream) return;
20946
- const lines = createInterface6({ input: stream });
21020
+ const lines = createInterface7({ input: stream });
20947
21021
  lines.on("line", (line) => daemonLog(`[${label2}] ${line}`));
20948
21022
  lines.on("error", () => {
20949
21023
  });
@@ -21099,6 +21173,10 @@ var inbound = {
21099
21173
  created: handleCreated,
21100
21174
  sessions: handleSessions,
21101
21175
  output: handleOutput,
21176
+ // why: relay the Windows daemon's own log lines into this daemon's stream (ring + subscribers) so assist.log shows both daemons; not state.broadcast — browsers must not receive log spam.
21177
+ log: (_state, msg) => {
21178
+ if (typeof msg.line === "string") relayDaemonLog(msg.line);
21179
+ },
21102
21180
  clear: relayWithSessionId,
21103
21181
  error: (state, msg) => {
21104
21182
  daemonLog(`windows daemon: inbound error: ${msg.message}`);
@@ -21215,7 +21293,7 @@ function isWindowsIo(data) {
21215
21293
  }
21216
21294
 
21217
21295
  // src/commands/sessions/daemon/WindowsConnection.ts
21218
- import { createInterface as createInterface7 } from "readline";
21296
+ import { createInterface as createInterface8 } from "readline";
21219
21297
 
21220
21298
  // src/commands/sessions/daemon/LaunchCircuitBreaker.ts
21221
21299
  var MAX_FAILURES = 3;
@@ -21292,10 +21370,11 @@ var WindowsConnection = class {
21292
21370
  this.socket = socket;
21293
21371
  this.wire(socket);
21294
21372
  this.write(buildHello());
21373
+ this.write({ type: "subscribe-logs" });
21295
21374
  return socket;
21296
21375
  }
21297
21376
  wire(socket) {
21298
- const lines = createInterface7({ input: socket });
21377
+ const lines = createInterface8({ input: socket });
21299
21378
  lines.on("error", () => {
21300
21379
  });
21301
21380
  lines.on("line", (line) => this.deps.onLine(line));
@@ -21382,14 +21461,14 @@ var WindowsProxy = class {
21382
21461
  state;
21383
21462
  conn;
21384
21463
  healer;
21385
- constructor(clients, onSessionsChanged, connect3 = defaultConnect, heal = healWindowsDaemon) {
21464
+ constructor(clients, onSessionsChanged, connect4 = defaultConnect, heal = healWindowsDaemon) {
21386
21465
  this.state = createState(
21387
21466
  (msg) => broadcast(clients, msg),
21388
21467
  onSessionsChanged,
21389
21468
  (version2) => void this.healer.onMismatch(version2)
21390
21469
  );
21391
21470
  this.conn = new WindowsConnection({
21392
- connect: connect3,
21471
+ connect: connect4,
21393
21472
  onLine: (line) => handleInbound(this.state, line),
21394
21473
  onClose: () => this.handleClose()
21395
21474
  });
@@ -21486,6 +21565,7 @@ var SessionManager = class {
21486
21565
  }
21487
21566
  removeClient(client) {
21488
21567
  this.clients.delete(client);
21568
+ this.clients.unsubscribeLogs(client);
21489
21569
  this.onIdleChange?.(this.isIdle());
21490
21570
  }
21491
21571
  isIdle = () => this.sessions.size === 0 && this.clients.size === 0;
@@ -21566,7 +21646,7 @@ import { unlinkSync as unlinkSync19 } from "fs";
21566
21646
  import * as net3 from "net";
21567
21647
 
21568
21648
  // src/commands/sessions/daemon/handleConnection.ts
21569
- import { createInterface as createInterface8 } from "readline";
21649
+ import { createInterface as createInterface9 } from "readline";
21570
21650
 
21571
21651
  // src/commands/sessions/shared/discoverSessions.ts
21572
21652
  import * as fs31 from "fs";
@@ -21875,6 +21955,7 @@ function routed(local) {
21875
21955
  }
21876
21956
  var messageHandlers = {
21877
21957
  ping: (client) => sendTo(client, { type: "pong", pid: process.pid }),
21958
+ "subscribe-logs": (client, m) => m.clients.subscribeLogs(client),
21878
21959
  hello: (client) => sendTo(client, buildHello()),
21879
21960
  create: creator(
21880
21961
  true,
@@ -21943,7 +22024,7 @@ function handleConnection(socket, manager) {
21943
22024
  };
21944
22025
  manager.addClient(client);
21945
22026
  manager.clients.greet(client);
21946
- const lines = createInterface8({ input: socket });
22027
+ const lines = createInterface9({ input: socket });
21947
22028
  lines.on("error", () => {
21948
22029
  });
21949
22030
  lines.on("line", (line) => {
@@ -22079,7 +22160,9 @@ async function runDaemon() {
22079
22160
  daemonLog("no sessions and no connected server; exiting");
22080
22161
  process.exit(0);
22081
22162
  });
22082
- startDaemonServer(new SessionManager(checkAutoExit), checkAutoExit);
22163
+ const manager = new SessionManager(checkAutoExit);
22164
+ setDaemonLogSink(manager.clients.emitLog);
22165
+ startDaemonServer(manager, checkAutoExit);
22083
22166
  }
22084
22167
 
22085
22168
  // src/commands/sessions/daemon/registerDaemon.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@staff0rd/assist",
3
- "version": "0.321.0",
3
+ "version": "0.322.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "bin": {