ragent-cli 1.11.12 → 1.11.14

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/index.js CHANGED
@@ -31,7 +31,7 @@ var require_package = __commonJS({
31
31
  "package.json"(exports2, module2) {
32
32
  module2.exports = {
33
33
  name: "ragent-cli",
34
- version: "1.11.12",
34
+ version: "1.11.14",
35
35
  description: "CLI agent for rAgent Live \u2014 browser-first terminal control plane for AI coding agents",
36
36
  main: "dist/index.js",
37
37
  bin: {
@@ -3538,6 +3538,7 @@ function discoverTranscriptFileImpl(sessionId, agentType) {
3538
3538
  var MAX_PARTIAL_BUFFER = 256 * 1024;
3539
3539
  var MAX_REPLAY_TURNS = 1e3;
3540
3540
  var POLL_INTERVAL_MS = 800;
3541
+ var DOC_READ_DEBOUNCE_MS = 200;
3541
3542
  var REDISCOVERY_INTERVAL_MS = 5e3;
3542
3543
  var ENABLE_RETRY_DELAYS_MS = [1e3, 2e3, 5e3];
3543
3544
  var TranscriptWatcher = class {
@@ -3554,6 +3555,7 @@ var TranscriptWatcher = class {
3554
3555
  snapshot;
3555
3556
  watcher = null;
3556
3557
  pollTimer = null;
3558
+ docReadDebounceTimer = null;
3557
3559
  stopped = false;
3558
3560
  subscriberCount = 0;
3559
3561
  documentFingerprint = "";
@@ -3608,6 +3610,10 @@ var TranscriptWatcher = class {
3608
3610
  clearInterval(this.pollTimer);
3609
3611
  this.pollTimer = null;
3610
3612
  }
3613
+ if (this.docReadDebounceTimer) {
3614
+ clearTimeout(this.docReadDebounceTimer);
3615
+ this.docReadDebounceTimer = null;
3616
+ }
3611
3617
  }
3612
3618
  /** Get accumulated turns for replay (up to MAX_REPLAY_TURNS). */
3613
3619
  getReplayTurns(fromSeq) {
@@ -3666,7 +3672,16 @@ var TranscriptWatcher = class {
3666
3672
  startWatching() {
3667
3673
  try {
3668
3674
  this.watcher = fs2.watch(this.filePath, () => {
3669
- if (!this.stopped) this.readNewData();
3675
+ if (this.stopped) return;
3676
+ if (this.parser.parseDocument) {
3677
+ if (this.docReadDebounceTimer) return;
3678
+ this.docReadDebounceTimer = setTimeout(() => {
3679
+ this.docReadDebounceTimer = null;
3680
+ if (!this.stopped) this.readNewData();
3681
+ }, DOC_READ_DEBOUNCE_MS);
3682
+ return;
3683
+ }
3684
+ this.readNewData();
3670
3685
  });
3671
3686
  this.watcher.on("error", () => {
3672
3687
  this.watcher?.close();
@@ -3721,16 +3736,20 @@ var TranscriptWatcher = class {
3721
3736
  }
3722
3737
  }
3723
3738
  readDocument(force) {
3724
- let content;
3725
3739
  let stat;
3726
3740
  try {
3727
3741
  stat = fs2.statSync(this.filePath);
3728
- content = fs2.readFileSync(this.filePath, "utf-8");
3729
3742
  } catch {
3730
3743
  return;
3731
3744
  }
3732
3745
  const fingerprint = `${stat.mtimeMs}:${stat.size}`;
3733
3746
  if (!force && fingerprint === this.documentFingerprint) return;
3747
+ let content;
3748
+ try {
3749
+ content = fs2.readFileSync(this.filePath, "utf-8");
3750
+ } catch {
3751
+ return;
3752
+ }
3734
3753
  this.documentFingerprint = fingerprint;
3735
3754
  const parsedTurns = this.parser.parseDocument?.(content) ?? [];
3736
3755
  this.seq++;
@@ -9673,6 +9692,7 @@ function resolveRuntimeTranscriptSource(sessionId) {
9673
9692
  }
9674
9693
 
9675
9694
  // src/sessions.ts
9695
+ var log15 = createLogger("sessions");
9676
9696
  var isMac = os5.platform() === "darwin";
9677
9697
  var MARKDOWN_AGENT_TYPES = /* @__PURE__ */ new Set(["Claude Code", "Codex CLI", "Gemini CLI", "Antigravity CLI"]);
9678
9698
  var isTmuxAvailable = null;
@@ -10070,18 +10090,15 @@ function transcriptSourceForSession(agentType, sessionId) {
10070
10090
  }
10071
10091
  async function collectBareAgentProcesses(excludePids, processList, processByPid) {
10072
10092
  try {
10073
- const tStart = performance.now();
10074
10093
  if (!processList || !processByPid) {
10075
10094
  const list = await getProcessTable();
10076
10095
  processList = list;
10077
10096
  processByPid = new Map(list.map((p) => [p.pid, p]));
10078
10097
  }
10079
- const tInit = performance.now();
10080
10098
  const sessions = [];
10081
10099
  const seen = /* @__PURE__ */ new Set();
10082
10100
  const excluded = excludePids ?? /* @__PURE__ */ new Set();
10083
10101
  const parentByPid = new Map(processList.map((row) => [row.pid, row.ppid]));
10084
- const tParentMap = performance.now();
10085
10102
  const hasTrackedAncestor = (pid, tracked) => {
10086
10103
  const visited = /* @__PURE__ */ new Set();
10087
10104
  let current = parentByPid.get(pid) ?? 0;
@@ -10092,7 +10109,6 @@ async function collectBareAgentProcesses(excludePids, processList, processByPid)
10092
10109
  }
10093
10110
  return false;
10094
10111
  };
10095
- const tFilterStart = performance.now();
10096
10112
  const candidates = processList.filter((row) => {
10097
10113
  const { pid, tty, stat, args } = row;
10098
10114
  if (!hasControllingTty(tty)) return false;
@@ -10103,8 +10119,6 @@ async function collectBareAgentProcesses(excludePids, processList, processByPid)
10103
10119
  if (!hasKeyword) return false;
10104
10120
  return true;
10105
10121
  });
10106
- const tFilterEnd = performance.now();
10107
- const tCwdsStart = performance.now();
10108
10122
  const cwds = await Promise.all(
10109
10123
  candidates.map(async (row) => {
10110
10124
  const cwd = await getProcessWorkingDir(row.pid);
@@ -10112,40 +10126,22 @@ async function collectBareAgentProcesses(excludePids, processList, processByPid)
10112
10126
  })
10113
10127
  );
10114
10128
  const cwdByPid = new Map(cwds.map((c) => [c.pid, c.cwd]));
10115
- const tCwdsEnd = performance.now();
10116
- let tLoopAncestor = 0;
10117
- let tLoopClassify = 0;
10118
- let tLoopVscode = 0;
10119
- let tLoopMarkdown = 0;
10120
- let tLoopStartTimes = 0;
10121
- const tLoopStart = performance.now();
10122
10129
  for (const row of candidates) {
10123
10130
  const { pid, args } = row;
10124
- const t0 = performance.now();
10125
- const skip = seen.has(pid) || hasTrackedAncestor(pid, seen);
10126
- tLoopAncestor += performance.now() - t0;
10127
- if (skip) continue;
10131
+ if (seen.has(pid) || hasTrackedAncestor(pid, seen)) continue;
10128
10132
  const workingDir = cwdByPid.get(pid) || null;
10129
- const t1 = performance.now();
10130
10133
  let classification = classifyAgent(args);
10131
10134
  if (!classification) {
10132
10135
  classification = classifyAgent(args, { workingDir: workingDir ?? void 0 });
10133
10136
  }
10134
- tLoopClassify += performance.now() - t1;
10135
10137
  if (!classification) continue;
10136
10138
  seen.add(pid);
10137
10139
  const dirName = workingDir ? workingDir.split("/").pop() : null;
10138
10140
  const displayName = dirName && dirName !== "/" && dirName !== "" ? `${classification.agentType} (${dirName})` : `${classification.agentType} (pid ${pid})`;
10139
- const t2 = performance.now();
10140
10141
  const vscodeDetected = await detectVscodeEnvironment(pid, processByPid);
10141
- tLoopVscode += performance.now() - t2;
10142
10142
  const id = `process:${pid}`;
10143
- const t3 = performance.now();
10144
10143
  const mdAvail = markdownAvailableForSession(id, classification.agentType);
10145
- tLoopMarkdown += performance.now() - t3;
10146
- const t4 = performance.now();
10147
10144
  const startTimes = collectStartTimes([pid]);
10148
- tLoopStartTimes += performance.now() - t4;
10149
10145
  sessions.push({
10150
10146
  id,
10151
10147
  type: "process",
@@ -10163,20 +10159,11 @@ async function collectBareAgentProcesses(excludePids, processList, processByPid)
10163
10159
  startTimes
10164
10160
  });
10165
10161
  }
10166
- const tLoopEnd = performance.now();
10167
- console.log(`[PROFILE-BARE] Init took ${(tInit - tStart).toFixed(2)} ms`);
10168
- console.log(`[PROFILE-BARE] Parent map took ${(tParentMap - tInit).toFixed(2)} ms`);
10169
- console.log(`[PROFILE-BARE] Filtering took ${(tFilterEnd - tFilterStart).toFixed(2)} ms`);
10170
- console.log(`[PROFILE-BARE] CWDs took ${(tCwdsEnd - tCwdsStart).toFixed(2)} ms`);
10171
- console.log(`[PROFILE-BARE] Loop total took ${(tLoopEnd - tLoopStart).toFixed(2)} ms`);
10172
- console.log(` [PROFILE-BARE-LOOP] Ancestor checks: ${tLoopAncestor.toFixed(2)} ms`);
10173
- console.log(` [PROFILE-BARE-LOOP] Classify: ${tLoopClassify.toFixed(2)} ms`);
10174
- console.log(` [PROFILE-BARE-LOOP] VS Code env: ${tLoopVscode.toFixed(2)} ms`);
10175
- console.log(` [PROFILE-BARE-LOOP] Markdown check: ${tLoopMarkdown.toFixed(2)} ms`);
10176
- console.log(` [PROFILE-BARE-LOOP] Start times: ${tLoopStartTimes.toFixed(2)} ms`);
10177
10162
  return sessions;
10178
10163
  } catch (err) {
10179
- console.error("[PROFILE-BARE] Error:", err);
10164
+ log15.error("collectBareAgentProcesses failed", {
10165
+ error: err instanceof Error ? err.stack || err.message : String(err)
10166
+ });
10180
10167
  return [];
10181
10168
  }
10182
10169
  }
@@ -10342,7 +10329,7 @@ async function getChildAgentInfo(parentPid, childrenByPpid, visited = /* @__PURE
10342
10329
  }
10343
10330
 
10344
10331
  // src/auth.ts
10345
- var log15 = createLogger("auth");
10332
+ var log16 = createLogger("auth");
10346
10333
  var AuthError = class extends Error {
10347
10334
  constructor(message) {
10348
10335
  super(message);
@@ -10360,7 +10347,7 @@ function decodeJwtExp(token) {
10360
10347
  }
10361
10348
  }
10362
10349
  async function startSessionWithMachineSecret(params) {
10363
- log15.info("attempting session recovery with machine credential");
10350
+ log16.info("attempting session recovery with machine credential");
10364
10351
  const response = await fetch(`${params.portal}/api/agent/session/start`, {
10365
10352
  method: "POST",
10366
10353
  headers: { "Content-Type": "application/json" },
@@ -10393,7 +10380,7 @@ async function startSessionWithMachineSecret(params) {
10393
10380
  patch.refreshExpiresAt = data.refreshExpiresAt || "";
10394
10381
  }
10395
10382
  saveConfigPatch(patch);
10396
- log15.info("session recovered via machine credential");
10383
+ log16.info("session recovered via machine credential");
10397
10384
  return data.agentToken;
10398
10385
  }
10399
10386
  async function refreshTokenIfNeeded(params) {
@@ -10404,7 +10391,7 @@ async function refreshTokenIfNeeded(params) {
10404
10391
  const remainingSeconds = exp - Math.floor(Date.now() / 1e3);
10405
10392
  const threshold2 = remainingSeconds < 3600 ? 120 : 3600;
10406
10393
  if (remainingSeconds > threshold2) return params.agentToken;
10407
- log15.info("token expiring \u2014 refreshing", { minutesRemaining: Math.round(remainingSeconds / 60) });
10394
+ log16.info("token expiring \u2014 refreshing", { minutesRemaining: Math.round(remainingSeconds / 60) });
10408
10395
  try {
10409
10396
  const headers = { "Content-Type": "application/json" };
10410
10397
  let body = {};
@@ -10420,7 +10407,7 @@ async function refreshTokenIfNeeded(params) {
10420
10407
  });
10421
10408
  if (!response.ok) {
10422
10409
  const errorData = await response.json().catch(() => ({}));
10423
- log15.warn("token refresh failed", { error: errorData.error || response.status });
10410
+ log16.warn("token refresh failed", { error: errorData.error || response.status });
10424
10411
  if (config.machineSecret && config.hostId) {
10425
10412
  try {
10426
10413
  return await startSessionWithMachineSecret({
@@ -10431,7 +10418,7 @@ async function refreshTokenIfNeeded(params) {
10431
10418
  } catch (mcError) {
10432
10419
  if (mcError instanceof AuthError) throw mcError;
10433
10420
  const mcMessage = mcError instanceof Error ? mcError.message : String(mcError);
10434
- log15.warn("machine credential recovery failed", { error: mcMessage });
10421
+ log16.warn("machine credential recovery failed", { error: mcMessage });
10435
10422
  }
10436
10423
  }
10437
10424
  return params.agentToken;
@@ -10450,12 +10437,12 @@ async function refreshTokenIfNeeded(params) {
10450
10437
  patch.machineSecret = data.machineSecret;
10451
10438
  }
10452
10439
  saveConfigPatch(patch);
10453
- log15.info("token refreshed successfully");
10440
+ log16.info("token refreshed successfully");
10454
10441
  return data.agentToken;
10455
10442
  } catch (error) {
10456
10443
  if (error instanceof AuthError) throw error;
10457
10444
  const message = error instanceof Error ? error.message : String(error);
10458
- log15.warn("token refresh error", { error: message });
10445
+ log16.warn("token refresh error", { error: message });
10459
10446
  return params.agentToken;
10460
10447
  }
10461
10448
  }
@@ -10518,7 +10505,7 @@ async function deregisterHost(params) {
10518
10505
  body: JSON.stringify({})
10519
10506
  });
10520
10507
  if (response.status === 401 || response.status === 403) {
10521
- log15.warn("token expired \u2014 could not deregister from server. Host may remain visible in dashboard until manually removed");
10508
+ log16.warn("token expired \u2014 could not deregister from server. Host may remain visible in dashboard until manually removed");
10522
10509
  return false;
10523
10510
  }
10524
10511
  return response.ok;
@@ -10658,6 +10645,9 @@ function getQueuePressure() {
10658
10645
  else if (level < PRESSURE_LOW) pressureIsHigh = false;
10659
10646
  return { level, isHigh: pressureIsHigh };
10660
10647
  }
10648
+ function getDroppedFrameCount() {
10649
+ return droppedFrames;
10650
+ }
10661
10651
  function drainQueue() {
10662
10652
  if (!drainWs || drainWs.readyState !== import_ws.default.OPEN) {
10663
10653
  stopDrainTimer();
@@ -10741,7 +10731,7 @@ var import_node_path = require("path");
10741
10731
  var import_node_os = require("os");
10742
10732
  var import_node_string_decoder = require("string_decoder");
10743
10733
  var pty = __toESM(require("node-pty"));
10744
- var log16 = createLogger("session-streamer");
10734
+ var log17 = createLogger("session-streamer");
10745
10735
  var BACKPRESSURE_RESUME_CHECK_MS = 100;
10746
10736
  var STOP_DEBOUNCE_MS = 2e3;
10747
10737
  var MAX_CONCURRENT_STREAMS = 20;
@@ -10843,6 +10833,10 @@ var SessionStreamer = class {
10843
10833
  disconnectBufferBytes = /* @__PURE__ */ new Map();
10844
10834
  /** Timer that resumes paused PTYs once the WS queue drains. See #332. */
10845
10835
  backpressureResumeTimer = null;
10836
+ /** Dropped-frame count at the last resume-timer check. */
10837
+ lastSeenDroppedFrames = 0;
10838
+ /** Sessions whose viewers need a capture-pane resync after frame drops. */
10839
+ pendingDropResync = /* @__PURE__ */ new Set();
10846
10840
  constructor(sendFn, onStreamStopped) {
10847
10841
  this.sendFn = sendFn;
10848
10842
  this.onStreamStopped = onStreamStopped;
@@ -10853,6 +10847,14 @@ var SessionStreamer = class {
10853
10847
  * When the WS queue is saturated, PTY onData stops firing after we call
10854
10848
  * ptyProc.pause(). We need an independent loop to check pressure and
10855
10849
  * resume each paused PTY once the queue drains. See #332.
10850
+ *
10851
+ * The same loop heals tmux-pipe streams after frame drops: tmux pipes
10852
+ * have no pause primitive, so under sustained pressure the send queue
10853
+ * overflows and drops frames — severing ANSI sequences and leaving
10854
+ * every viewer garbled until the next full repaint. Once pressure
10855
+ * clears, any drop since the last check triggers a capture-pane resync
10856
+ * (one stream per tick, so the resyncs themselves don't re-saturate
10857
+ * the queue).
10856
10858
  */
10857
10859
  startBackpressureResumeTimer() {
10858
10860
  if (this.backpressureResumeTimer) return;
@@ -10864,11 +10866,32 @@ var SessionStreamer = class {
10864
10866
  try {
10865
10867
  stream.ptyProc.resume();
10866
10868
  stream.ptyPaused = false;
10867
- log16.info("pty-attach resumed after WS queue drained", { sessionId: stream.sessionId });
10869
+ log17.info("pty-attach resumed after WS queue drained", { sessionId: stream.sessionId });
10868
10870
  } catch {
10869
10871
  }
10870
10872
  }
10871
10873
  }
10874
+ const dropped = getDroppedFrameCount();
10875
+ if (dropped > this.lastSeenDroppedFrames) {
10876
+ for (const stream of this.active.values()) {
10877
+ if (stream.streamType === "tmux-pipe" && !stream.stopped && !stream.initializing) {
10878
+ this.pendingDropResync.add(stream.sessionId);
10879
+ }
10880
+ }
10881
+ this.lastSeenDroppedFrames = dropped;
10882
+ log17.warn("frames dropped under backpressure; scheduling stream resyncs", {
10883
+ droppedTotal: dropped,
10884
+ streams: this.pendingDropResync.size
10885
+ });
10886
+ }
10887
+ const next = this.pendingDropResync.values().next();
10888
+ if (!next.done) {
10889
+ this.pendingDropResync.delete(next.value);
10890
+ const stream = this.active.get(next.value);
10891
+ if (stream && !stream.stopped) {
10892
+ this.resyncStream(next.value);
10893
+ }
10894
+ }
10872
10895
  }, BACKPRESSURE_RESUME_CHECK_MS);
10873
10896
  }
10874
10897
  /**
@@ -10883,7 +10906,7 @@ var SessionStreamer = class {
10883
10906
  try {
10884
10907
  stream.ptyProc.pause();
10885
10908
  stream.ptyPaused = true;
10886
- log16.warn("pty-attach paused under WS backpressure", {
10909
+ log17.warn("pty-attach paused under WS backpressure", {
10887
10910
  sessionId: stream.sessionId,
10888
10911
  queueLevel: pressure.level.toFixed(2)
10889
10912
  });
@@ -10907,7 +10930,7 @@ var SessionStreamer = class {
10907
10930
  }
10908
10931
  }
10909
10932
  if (entries.some((e) => e.startsWith("s-"))) {
10910
- log16.info("cleaned up stale stream directories from previous run");
10933
+ log17.info("cleaned up stale stream directories from previous run");
10911
10934
  }
10912
10935
  } catch {
10913
10936
  }
@@ -10925,7 +10948,7 @@ var SessionStreamer = class {
10925
10948
  if (viewerKey) {
10926
10949
  this.active.get(sessionId)?.viewerIds.add(viewerKey);
10927
10950
  }
10928
- log16.info("cancelled pending stop (re-mounted)", { sessionId });
10951
+ log17.info("cancelled pending stop (re-mounted)", { sessionId });
10929
10952
  return true;
10930
10953
  }
10931
10954
  }
@@ -10936,7 +10959,7 @@ var SessionStreamer = class {
10936
10959
  return true;
10937
10960
  }
10938
10961
  if (this.active.size >= MAX_CONCURRENT_STREAMS) {
10939
- log16.warn("stream limit reached; rejecting", {
10962
+ log17.warn("stream limit reached; rejecting", {
10940
10963
  limit: MAX_CONCURRENT_STREAMS,
10941
10964
  sessionId
10942
10965
  });
@@ -10967,7 +10990,7 @@ var SessionStreamer = class {
10967
10990
  stream.ptyProc.write(data);
10968
10991
  } catch (error) {
10969
10992
  const message = error instanceof Error ? error.message : String(error);
10970
- log16.warn("failed to write input", { sessionId, error: message });
10993
+ log17.warn("failed to write input", { sessionId, error: message });
10971
10994
  }
10972
10995
  }
10973
10996
  /**
@@ -10981,7 +11004,7 @@ var SessionStreamer = class {
10981
11004
  } catch (error) {
10982
11005
  const message = error instanceof Error ? error.message : String(error);
10983
11006
  if (!message.includes("EBADF")) {
10984
- log16.warn("resize failed", { sessionId, error: message });
11007
+ log17.warn("resize failed", { sessionId, error: message });
10985
11008
  }
10986
11009
  }
10987
11010
  }
@@ -11007,7 +11030,7 @@ var SessionStreamer = class {
11007
11030
  this.active.delete(sessionId);
11008
11031
  this.disconnectBuffers.delete(sessionId);
11009
11032
  this.disconnectBufferBytes.delete(sessionId);
11010
- log16.info("stopped streaming", { sessionId });
11033
+ log17.info("stopped streaming", { sessionId });
11011
11034
  }, STOP_DEBOUNCE_MS);
11012
11035
  this.pendingStops.set(sessionId, timer);
11013
11036
  }
@@ -11032,7 +11055,7 @@ var SessionStreamer = class {
11032
11055
  this.pendingStops.clear();
11033
11056
  for (const [id, stream] of this.active) {
11034
11057
  this.cleanupStream(stream);
11035
- log16.info("stopped streaming", { sessionId: id });
11058
+ log17.info("stopped streaming", { sessionId: id });
11036
11059
  }
11037
11060
  this.active.clear();
11038
11061
  this.disconnectBuffers.clear();
@@ -11170,13 +11193,13 @@ var SessionStreamer = class {
11170
11193
  }
11171
11194
  stream.initializing = false;
11172
11195
  stream.initBuffer = [];
11173
- log16.info("resync capture", { sessionId });
11196
+ log17.info("resync capture", { sessionId });
11174
11197
  return true;
11175
11198
  } catch (error) {
11176
11199
  stream.initializing = false;
11177
11200
  stream.initBuffer = [];
11178
11201
  const message = error instanceof Error ? error.message : String(error);
11179
- log16.warn("failed to resync stream", { sessionId, error: message });
11202
+ log17.warn("failed to resync stream", { sessionId, error: message });
11180
11203
  return false;
11181
11204
  }
11182
11205
  }
@@ -11230,7 +11253,7 @@ var SessionStreamer = class {
11230
11253
  } catch (error) {
11231
11254
  this.cleanupStream(stream);
11232
11255
  const message = error instanceof Error ? error.message : String(error);
11233
- log16.warn("failed pipe-pane", { sessionId, error: message });
11256
+ log17.warn("failed pipe-pane", { sessionId, error: message });
11234
11257
  return false;
11235
11258
  }
11236
11259
  const catProc = (0, import_node_child_process2.spawn)("cat", [fifoPath], { env: cleanEnv, stdio: ["ignore", "pipe", "ignore"] });
@@ -11258,7 +11281,7 @@ var SessionStreamer = class {
11258
11281
  this.cleanupStream(stream);
11259
11282
  this.active.delete(sessionId);
11260
11283
  this.pendingStops.delete(sessionId);
11261
- log16.info("session stream ended", { sessionId });
11284
+ log17.info("session stream ended", { sessionId });
11262
11285
  this.onStreamStopped?.(sessionId);
11263
11286
  }
11264
11287
  });
@@ -11315,11 +11338,11 @@ var SessionStreamer = class {
11315
11338
  }
11316
11339
  stream.initializing = false;
11317
11340
  stream.initBuffer = [];
11318
- log16.info("started streaming (tmux)", { sessionId, pane: paneTarget });
11341
+ log17.info("started streaming (tmux)", { sessionId, pane: paneTarget });
11319
11342
  return true;
11320
11343
  } catch (error) {
11321
11344
  const message = error instanceof Error ? error.message : String(error);
11322
- log16.warn("failed to start stream", { sessionId, error: message });
11345
+ log17.warn("failed to start stream", { sessionId, error: message });
11323
11346
  return false;
11324
11347
  }
11325
11348
  }
@@ -11365,15 +11388,15 @@ var SessionStreamer = class {
11365
11388
  stream.stopped = true;
11366
11389
  this.active.delete(sessionId);
11367
11390
  this.pendingStops.delete(sessionId);
11368
- log16.info("session stream ended", { sessionId });
11391
+ log17.info("session stream ended", { sessionId });
11369
11392
  this.onStreamStopped?.(sessionId);
11370
11393
  }
11371
11394
  });
11372
- log16.info("started streaming (screen)", { sessionId, screen: sessionName });
11395
+ log17.info("started streaming (screen)", { sessionId, screen: sessionName });
11373
11396
  return true;
11374
11397
  } catch (error) {
11375
11398
  const message = error instanceof Error ? error.message : String(error);
11376
- log16.warn("failed to start screen stream", { sessionId, error: message });
11399
+ log17.warn("failed to start screen stream", { sessionId, error: message });
11377
11400
  return false;
11378
11401
  }
11379
11402
  }
@@ -11419,15 +11442,15 @@ var SessionStreamer = class {
11419
11442
  stream.stopped = true;
11420
11443
  this.active.delete(sessionId);
11421
11444
  this.pendingStops.delete(sessionId);
11422
- log16.info("session stream ended", { sessionId });
11445
+ log17.info("session stream ended", { sessionId });
11423
11446
  this.onStreamStopped?.(sessionId);
11424
11447
  }
11425
11448
  });
11426
- log16.info("started streaming (zellij)", { sessionId, zellij: sessionName });
11449
+ log17.info("started streaming (zellij)", { sessionId, zellij: sessionName });
11427
11450
  return true;
11428
11451
  } catch (error) {
11429
11452
  const message = error instanceof Error ? error.message : String(error);
11430
- log16.warn("failed to start zellij stream", { sessionId, error: message });
11453
+ log17.warn("failed to start zellij stream", { sessionId, error: message });
11431
11454
  return false;
11432
11455
  }
11433
11456
  }
@@ -11438,14 +11461,14 @@ var SessionStreamer = class {
11438
11461
  const pid = parseProcessPid2(sessionId);
11439
11462
  if (!pid) return false;
11440
11463
  if (!(0, import_node_fs.existsSync)(`/proc/${pid}`)) {
11441
- log16.warn("process does not exist (no /proc entry)", { pid });
11464
+ log17.warn("process does not exist (no /proc entry)", { pid });
11442
11465
  this.sendFn(sessionId, "\r\n[rAgent] Process is no longer running. It will be removed on next sync.\r\n");
11443
11466
  return false;
11444
11467
  }
11445
11468
  try {
11446
11469
  const stat = (0, import_node_fs.readFileSync)(`/proc/${pid}/stat`, "utf8");
11447
11470
  if (stat.includes(") Z")) {
11448
- log16.warn("process is a zombie", { pid });
11471
+ log17.warn("process is a zombie", { pid });
11449
11472
  this.sendFn(sessionId, "\r\n[rAgent] Process has exited (zombie). It will be removed on next sync.\r\n");
11450
11473
  return false;
11451
11474
  }
@@ -11519,14 +11542,14 @@ var SessionStreamer = class {
11519
11542
  stream.stopped = true;
11520
11543
  this.active.delete(sessionId);
11521
11544
  this.pendingStops.delete(sessionId);
11522
- log16.info("session stream ended", { sessionId });
11545
+ log17.info("session stream ended", { sessionId });
11523
11546
  this.onStreamStopped?.(sessionId);
11524
11547
  });
11525
- log16.info("started streaming (process trace)", { sessionId, pid });
11548
+ log17.info("started streaming (process trace)", { sessionId, pid });
11526
11549
  return true;
11527
11550
  } catch (error) {
11528
11551
  const message = error instanceof Error ? error.message : String(error);
11529
- log16.warn("failed to start process stream", { sessionId, error: message });
11552
+ log17.warn("failed to start process stream", { sessionId, error: message });
11530
11553
  return false;
11531
11554
  }
11532
11555
  }
@@ -11577,7 +11600,7 @@ var SessionStreamer = class {
11577
11600
 
11578
11601
  // src/crypto-channel.ts
11579
11602
  var import_node_crypto = require("crypto");
11580
- var log17 = createLogger("crypto-channel");
11603
+ var log18 = createLogger("crypto-channel");
11581
11604
  var AAD_BYTES = 4;
11582
11605
  function deriveAesKey(sessionKey) {
11583
11606
  return Buffer.from(sessionKey.slice(0, 64), "hex");
@@ -11619,7 +11642,7 @@ function decryptPayload(enc, iv, sessionKey, seq) {
11619
11642
  return decrypted.toString("utf-8");
11620
11643
  } catch (error) {
11621
11644
  const message = error instanceof Error ? error.message : String(error);
11622
- log17.warn("decrypt failed", { seq, encBytes: enc.length, error: message });
11645
+ log18.warn("decrypt failed", { seq, encBytes: enc.length, error: message });
11623
11646
  return null;
11624
11647
  }
11625
11648
  }
@@ -11653,7 +11676,7 @@ var SequenceTracker = class {
11653
11676
  // src/pty.ts
11654
11677
  var import_node_child_process3 = require("child_process");
11655
11678
  var pty2 = __toESM(require("node-pty"));
11656
- var log18 = createLogger("pty");
11679
+ var log19 = createLogger("pty");
11657
11680
  var MIN_TMUX_COLS = 20;
11658
11681
  var MAX_TMUX_COLS = 500;
11659
11682
  var MIN_TMUX_ROWS = 5;
@@ -11801,7 +11824,7 @@ async function sendInputToTmux(sessionId, data) {
11801
11824
  if (!target) return;
11802
11825
  if (!isValidTmuxSessionName(target)) {
11803
11826
  const sessionName = target.split(":")[0].split(".")[0];
11804
- log18.warn("invalid tmux session name", { sessionName });
11827
+ log19.warn("invalid tmux session name", { sessionName });
11805
11828
  return;
11806
11829
  }
11807
11830
  try {
@@ -11832,7 +11855,7 @@ async function sendInputToTmux(sessionId, data) {
11832
11855
  }
11833
11856
  } catch (error) {
11834
11857
  const message = error instanceof Error ? error.message : String(error);
11835
- log18.warn("failed to send input", { sessionId, error: message });
11858
+ log19.warn("failed to send input", { sessionId, error: message });
11836
11859
  }
11837
11860
  }
11838
11861
  async function resizeTmuxPaneBySessionId(sessionId, cols, rows) {
@@ -11841,7 +11864,7 @@ async function resizeTmuxPaneBySessionId(sessionId, cols, rows) {
11841
11864
  if (!target) return false;
11842
11865
  if (!isValidTmuxSessionName(target)) {
11843
11866
  const sessionName = target.split(":")[0].split(".")[0];
11844
- log18.warn("invalid tmux session name", { sessionName });
11867
+ log19.warn("invalid tmux session name", { sessionName });
11845
11868
  return false;
11846
11869
  }
11847
11870
  if (!Number.isFinite(cols) || !Number.isFinite(rows)) return false;
@@ -11855,7 +11878,7 @@ async function resizeTmuxPaneBySessionId(sessionId, cols, rows) {
11855
11878
  (err) => {
11856
11879
  if (err) {
11857
11880
  const message = err instanceof Error ? err.message : String(err);
11858
- log18.warn("failed to resize tmux pane", { sessionId, error: message });
11881
+ log19.warn("failed to resize tmux pane", { sessionId, error: message });
11859
11882
  resolve(false);
11860
11883
  return;
11861
11884
  }
@@ -11889,7 +11912,7 @@ async function stopAllDetachedTmuxSessions() {
11889
11912
  }
11890
11913
 
11891
11914
  // src/shell-manager.ts
11892
- var log19 = createLogger("shell");
11915
+ var log20 = createLogger("shell");
11893
11916
  var ShellManager = class {
11894
11917
  ptyProcess = null;
11895
11918
  suppressNextRespawn = false;
@@ -11930,7 +11953,7 @@ var ShellManager = class {
11930
11953
  } catch (error) {
11931
11954
  const message = error instanceof Error ? error.message : String(error);
11932
11955
  if (!message.includes("EBADF")) {
11933
- log19.warn("resize failed", { error: message });
11956
+ log20.warn("resize failed", { error: message });
11934
11957
  }
11935
11958
  }
11936
11959
  }
@@ -11946,7 +11969,7 @@ var ShellManager = class {
11946
11969
  return;
11947
11970
  }
11948
11971
  if (!this.shouldRun) return;
11949
- log19.warn("shell exited; restarting shell process");
11972
+ log20.warn("shell exited; restarting shell process");
11950
11973
  setTimeout(() => {
11951
11974
  if (this.shouldRun) this.spawnOrRespawn();
11952
11975
  }, 200);
@@ -12052,7 +12075,7 @@ var InventoryManager = class {
12052
12075
 
12053
12076
  // src/connection-manager.ts
12054
12077
  var import_ws3 = __toESM(require("ws"));
12055
- var log20 = createLogger("connection");
12078
+ var log21 = createLogger("connection");
12056
12079
  var OPPORTUNISTIC_INVENTORY_SYNC_MS = 1200;
12057
12080
  var MIN_INVENTORY_SYNC_GAP_MS = 1500;
12058
12081
  var ConnectionManager = class {
@@ -12084,7 +12107,7 @@ var ConnectionManager = class {
12084
12107
  tracker = new SequenceTracker();
12085
12108
  this.rxSeqByViewer.set(key, tracker);
12086
12109
  if (!isValid) {
12087
- log20.warn("rxSeq fell back to _legacy bucket \u2014 portal sent empty viewerId", { typeofViewerId: typeof viewerId });
12110
+ log21.warn("rxSeq fell back to _legacy bucket \u2014 portal sent empty viewerId", { typeofViewerId: typeof viewerId });
12088
12111
  }
12089
12112
  }
12090
12113
  return tracker;
@@ -12170,14 +12193,14 @@ var ConnectionManager = class {
12170
12193
  try {
12171
12194
  this.activeSocket.send(JSON.stringify({ type: "ping" }));
12172
12195
  } catch (err) {
12173
- log20.error("failed to send JSON ping", { error: err.message });
12196
+ log21.error("failed to send JSON ping", { error: err.message });
12174
12197
  }
12175
12198
  try {
12176
12199
  this.activeSocket.ping();
12177
12200
  } catch {
12178
12201
  }
12179
12202
  this.wsPongTimeout = setTimeout(() => {
12180
- log20.warn("no pong received within 10s; closing stale connection");
12203
+ log21.warn("no pong received within 10s; closing stale connection");
12181
12204
  try {
12182
12205
  this.activeSocket?.terminate();
12183
12206
  } catch {
@@ -12247,7 +12270,7 @@ var ConnectionManager = class {
12247
12270
  replayBufferedOutput(sendChunk) {
12248
12271
  const buffered = this.outputBuffer.drain();
12249
12272
  if (buffered.length > 0) {
12250
- log20.info("replaying buffered output chunks", {
12273
+ log21.info("replaying buffered output chunks", {
12251
12274
  chunks: buffered.length,
12252
12275
  bytes: buffered.reduce((sum, c) => sum + Buffer.byteLength(c, "utf8"), 0)
12253
12276
  });
@@ -12289,7 +12312,7 @@ var import_child_process6 = require("child_process");
12289
12312
  var fs5 = __toESM(require("fs"));
12290
12313
  var os8 = __toESM(require("os"));
12291
12314
  var path4 = __toESM(require("path"));
12292
- var log21 = createLogger("service");
12315
+ var log22 = createLogger("service");
12293
12316
  function assertConfiguredAgentToken() {
12294
12317
  const config = loadConfig();
12295
12318
  if (!config.agentToken) {
@@ -12355,7 +12378,7 @@ async function installSystemdService(opts = {}) {
12355
12378
  await runSystemctlUser(["restart", SERVICE_NAME]);
12356
12379
  }
12357
12380
  saveConfigPatch({ serviceBackend: "systemd" });
12358
- log21.info("installed systemd user service", { path: SERVICE_FILE });
12381
+ log22.info("installed systemd user service", { path: SERVICE_FILE });
12359
12382
  }
12360
12383
  function readFallbackPid() {
12361
12384
  try {
@@ -12394,7 +12417,7 @@ async function startPidfileService() {
12394
12417
  assertConfiguredAgentToken();
12395
12418
  const existingPid = readFallbackPid();
12396
12419
  if (existingPid && isProcessRunning(existingPid)) {
12397
- log21.info("service already running", { pid: existingPid });
12420
+ log22.info("service already running", { pid: existingPid });
12398
12421
  return;
12399
12422
  }
12400
12423
  ensureConfigDir();
@@ -12411,8 +12434,8 @@ async function startPidfileService() {
12411
12434
  fs5.writeFileSync(FALLBACK_PID_FILE, `${child.pid}
12412
12435
  `, "utf8");
12413
12436
  saveConfigPatch({ serviceBackend: "pidfile" });
12414
- log21.info("started fallback background service", { pid: child.pid });
12415
- log21.info("logs", { path: FALLBACK_LOG_FILE });
12437
+ log22.info("started fallback background service", { pid: child.pid });
12438
+ log22.info("logs", { path: FALLBACK_LOG_FILE });
12416
12439
  }
12417
12440
  async function stopPidfileService() {
12418
12441
  const pid = readFallbackPid();
@@ -12421,7 +12444,7 @@ async function stopPidfileService() {
12421
12444
  fs5.unlinkSync(FALLBACK_PID_FILE);
12422
12445
  } catch {
12423
12446
  }
12424
- log21.info("service is not running");
12447
+ log22.info("service is not running");
12425
12448
  return;
12426
12449
  }
12427
12450
  process.kill(pid, "SIGTERM");
@@ -12436,7 +12459,7 @@ async function stopPidfileService() {
12436
12459
  fs5.unlinkSync(FALLBACK_PID_FILE);
12437
12460
  } catch {
12438
12461
  }
12439
- log21.info("stopped fallback background service", { pid });
12462
+ log22.info("stopped fallback background service", { pid });
12440
12463
  }
12441
12464
  async function ensureServiceInstalled(opts = {}) {
12442
12465
  const wantsSystemd = await canUseSystemdUser();
@@ -12448,7 +12471,7 @@ async function ensureServiceInstalled(opts = {}) {
12448
12471
  if (opts.start) {
12449
12472
  await startPidfileService();
12450
12473
  } else {
12451
- log21.info("systemd user manager unavailable; using fallback pidfile backend");
12474
+ log22.info("systemd user manager unavailable; using fallback pidfile backend");
12452
12475
  }
12453
12476
  return "pidfile";
12454
12477
  }
@@ -12456,7 +12479,7 @@ async function startService() {
12456
12479
  const backend = getConfiguredServiceBackend();
12457
12480
  if (backend === "systemd") {
12458
12481
  await runSystemctlUser(["start", SERVICE_NAME]);
12459
- log21.info("started service via systemd");
12482
+ log22.info("started service via systemd");
12460
12483
  return;
12461
12484
  }
12462
12485
  if (backend === "pidfile") {
@@ -12469,7 +12492,7 @@ async function stopService() {
12469
12492
  const backend = getConfiguredServiceBackend();
12470
12493
  if (backend === "systemd") {
12471
12494
  await runSystemctlUser(["stop", SERVICE_NAME]);
12472
- log21.info("stopped service via systemd");
12495
+ log22.info("stopped service via systemd");
12473
12496
  return;
12474
12497
  }
12475
12498
  await stopPidfileService();
@@ -12487,7 +12510,7 @@ function killStaleAgentProcesses() {
12487
12510
  try {
12488
12511
  process.kill(pid, 0);
12489
12512
  process.kill(pid, "SIGTERM");
12490
- log21.info("stopped stale agent process", { pid });
12513
+ log22.info("stopped stale agent process", { pid });
12491
12514
  } catch {
12492
12515
  }
12493
12516
  fs5.unlinkSync(pidPath);
@@ -12502,7 +12525,7 @@ async function restartService() {
12502
12525
  killStaleAgentProcesses();
12503
12526
  if (backend === "systemd") {
12504
12527
  await runSystemctlUser(["restart", SERVICE_NAME]);
12505
- log21.info("restarted service via systemd");
12528
+ log22.info("restarted service via systemd");
12506
12529
  return;
12507
12530
  }
12508
12531
  await stopPidfileService();
@@ -12518,17 +12541,17 @@ async function printServiceStatus() {
12518
12541
  if (status) {
12519
12542
  process.stdout.write(status);
12520
12543
  } else {
12521
- log21.info("systemd service is not installed or has no status");
12544
+ log22.info("systemd service is not installed or has no status");
12522
12545
  }
12523
12546
  return;
12524
12547
  }
12525
12548
  const pid = readFallbackPid();
12526
12549
  if (pid && isProcessRunning(pid)) {
12527
- log21.info("fallback service running", { pid });
12528
- log21.info("logs", { path: FALLBACK_LOG_FILE });
12550
+ log22.info("fallback service running", { pid });
12551
+ log22.info("logs", { path: FALLBACK_LOG_FILE });
12529
12552
  return;
12530
12553
  }
12531
- log21.info("service is not running");
12554
+ log22.info("service is not running");
12532
12555
  }
12533
12556
  async function printServiceLogs(opts) {
12534
12557
  const lines = Number.parseInt(String(opts.lines || 100), 10) || 100;
@@ -12554,7 +12577,7 @@ async function printServiceLogs(opts) {
12554
12577
  return;
12555
12578
  }
12556
12579
  if (!fs5.existsSync(FALLBACK_LOG_FILE)) {
12557
- log21.info("no log file found", { path: FALLBACK_LOG_FILE });
12580
+ log22.info("no log file found", { path: FALLBACK_LOG_FILE });
12558
12581
  return;
12559
12582
  }
12560
12583
  if (follow) {
@@ -12586,7 +12609,7 @@ async function uninstallService() {
12586
12609
  const config = loadConfig();
12587
12610
  delete config.serviceBackend;
12588
12611
  saveConfig(config);
12589
- log21.info("service uninstalled");
12612
+ log22.info("service uninstalled");
12590
12613
  }
12591
12614
  function requestStopSelfService() {
12592
12615
  const backend = getConfiguredServiceBackend();
@@ -12937,7 +12960,7 @@ async function installLatestCliFromNpm() {
12937
12960
  }
12938
12961
 
12939
12962
  // src/control-dispatcher.ts
12940
- var log22 = createLogger("control");
12963
+ var log23 = createLogger("control");
12941
12964
  var TMUX_RESYNC_DEBOUNCE_MS = 150;
12942
12965
  var TMUX_INPUT_COALESCE_MS = 4;
12943
12966
  function collectProcessTreePids(rootPid, visited = /* @__PURE__ */ new Set()) {
@@ -13009,7 +13032,7 @@ var ControlDispatcher = class {
13009
13032
  /** Arrow form so callers can pass it directly without `.bind(this)`. */
13010
13033
  emitNativeOps = (sessionId, ops, seq) => {
13011
13034
  if (!this.sendNativeOps) {
13012
- log22.warn("native-stream ops produced but no transport sink installed", {
13035
+ log23.warn("native-stream ops produced but no transport sink installed", {
13013
13036
  sessionId,
13014
13037
  opCount: ops.length
13015
13038
  });
@@ -13078,11 +13101,11 @@ var ControlDispatcher = class {
13078
13101
  if (!sessionKey) return true;
13079
13102
  const receivedHmac = payload.hmac;
13080
13103
  if (typeof receivedHmac !== "string") {
13081
- log22.warn("control message missing HMAC signature");
13104
+ log23.warn("control message missing HMAC signature");
13082
13105
  return false;
13083
13106
  }
13084
13107
  if (!/^[0-9a-f]{64}$/i.test(receivedHmac)) {
13085
- log22.warn("control message has malformed HMAC signature");
13108
+ log23.warn("control message has malformed HMAC signature");
13086
13109
  return false;
13087
13110
  }
13088
13111
  const { hmac: _, ...payloadWithoutHmac } = payload;
@@ -13110,7 +13133,7 @@ var ControlDispatcher = class {
13110
13133
  ]);
13111
13134
  if (dangerousActions.has(action) && this.connection.sessionKey && payload._verifiedEncrypted !== true) {
13112
13135
  if (!this.verifyMessageHmac(payload)) {
13113
- log22.warn("rejecting control action \u2014 HMAC verification failed", { action });
13136
+ log23.warn("rejecting control action \u2014 HMAC verification failed", { action });
13114
13137
  return;
13115
13138
  }
13116
13139
  }
@@ -13156,10 +13179,10 @@ var ControlDispatcher = class {
13156
13179
  this.transcriptWatcher?.disableMarkdown(sessionId);
13157
13180
  try {
13158
13181
  await stopTmuxPaneBySessionId(sessionId);
13159
- log22.info("closed remote session", { sessionId });
13182
+ log23.info("closed remote session", { sessionId });
13160
13183
  } catch (error) {
13161
13184
  const message = error instanceof Error ? error.message : String(error);
13162
- log22.warn("failed to close session", { sessionId, error: message });
13185
+ log23.warn("failed to close session", { sessionId, error: message });
13163
13186
  }
13164
13187
  await delay(300);
13165
13188
  await this.syncInventory(true);
@@ -13170,7 +13193,7 @@ var ControlDispatcher = class {
13170
13193
  {
13171
13194
  const pid = parseProcessPid2(sessionId);
13172
13195
  if (pid === null) {
13173
- log22.warn("kill-process: could not parse PID", { sessionId });
13196
+ log23.warn("kill-process: could not parse PID", { sessionId });
13174
13197
  return;
13175
13198
  }
13176
13199
  this.transcriptWatcher?.disableMarkdown(sessionId);
@@ -13186,11 +13209,11 @@ var ControlDispatcher = class {
13186
13209
  const code = error.code;
13187
13210
  if (code !== "ESRCH") {
13188
13211
  const message = error instanceof Error ? error.message : String(error);
13189
- log22.warn("failed to send SIGTERM", { pid: targetPid, error: message });
13212
+ log23.warn("failed to send SIGTERM", { pid: targetPid, error: message });
13190
13213
  }
13191
13214
  }
13192
13215
  }
13193
- log22.info("sent SIGTERM to processes", { signaled, sessionId });
13216
+ log23.info("sent SIGTERM to processes", { signaled, sessionId });
13194
13217
  await new Promise((resolve) => setTimeout(resolve, 1500));
13195
13218
  for (const targetPid of processTree) {
13196
13219
  if (!isProcessAlive(targetPid)) continue;
@@ -13200,13 +13223,13 @@ var ControlDispatcher = class {
13200
13223
  const code = error.code;
13201
13224
  if (code !== "ESRCH") {
13202
13225
  const message = error instanceof Error ? error.message : String(error);
13203
- log22.warn("failed to send SIGKILL", { pid: targetPid, error: message });
13226
+ log23.warn("failed to send SIGKILL", { pid: targetPid, error: message });
13204
13227
  }
13205
13228
  }
13206
13229
  }
13207
13230
  } catch (error) {
13208
13231
  const message = error instanceof Error ? error.message : String(error);
13209
- log22.warn("failed to kill session", { sessionId, error: message });
13232
+ log23.warn("failed to kill session", { sessionId, error: message });
13210
13233
  }
13211
13234
  await this.syncInventory(true);
13212
13235
  }
@@ -13221,7 +13244,7 @@ var ControlDispatcher = class {
13221
13244
  }
13222
13245
  }
13223
13246
  const killed = await stopAllDetachedTmuxSessions();
13224
- log22.info("killed detached tmux sessions", { count: killed });
13247
+ log23.info("killed detached tmux sessions", { count: killed });
13225
13248
  await delay(300);
13226
13249
  await this.syncInventory(true);
13227
13250
  return;
@@ -13261,18 +13284,18 @@ var ControlDispatcher = class {
13261
13284
  const fileName = typeof payload.fileName === "string" ? payload.fileName : "attachment";
13262
13285
  const contentBase64 = typeof payload.contentBase64 === "string" ? payload.contentBase64 : "";
13263
13286
  if (!contentBase64 || contentBase64.length > 8 * 1024 * 1024) {
13264
- log22.warn("rejecting attachment upload \u2014 invalid size", { sessionId, fileName });
13287
+ log23.warn("rejecting attachment upload \u2014 invalid size", { sessionId, fileName });
13265
13288
  return;
13266
13289
  }
13267
13290
  let content;
13268
13291
  try {
13269
13292
  content = Buffer.from(contentBase64, "base64");
13270
13293
  } catch {
13271
- log22.warn("rejecting attachment upload \u2014 invalid base64", { sessionId, fileName });
13294
+ log23.warn("rejecting attachment upload \u2014 invalid base64", { sessionId, fileName });
13272
13295
  return;
13273
13296
  }
13274
13297
  if (content.length === 0 || content.length > 6 * 1024 * 1024) {
13275
- log22.warn("rejecting attachment upload \u2014 decoded size out of bounds", {
13298
+ log23.warn("rejecting attachment upload \u2014 decoded size out of bounds", {
13276
13299
  sessionId,
13277
13300
  fileName,
13278
13301
  bytes: content.length
@@ -13283,7 +13306,7 @@ var ControlDispatcher = class {
13283
13306
  fs6.mkdirSync(uploadDir, { recursive: true, mode: 448 });
13284
13307
  const writtenPath = path5.join(uploadDir, `${Date.now()}-${safeAttachmentName(fileName)}`);
13285
13308
  fs6.writeFileSync(writtenPath, content, { mode: 384 });
13286
- log22.info("attachment uploaded", { sessionId, path: writtenPath, bytes: content.length });
13309
+ log23.info("attachment uploaded", { sessionId, path: writtenPath, bytes: content.length });
13287
13310
  this.handleInput(writtenPath, sessionId);
13288
13311
  }
13289
13312
  /** Handle input routing to the correct target. */
@@ -13346,7 +13369,7 @@ var ControlDispatcher = class {
13346
13369
  this.tmuxResizeState.delete(sessionId);
13347
13370
  }
13348
13371
  const message = error instanceof Error ? error.message : String(error);
13349
- log22.warn("tmux resize failed", { sessionId, error: message });
13372
+ log23.warn("tmux resize failed", { sessionId, error: message });
13350
13373
  });
13351
13374
  } else if (sessionId.startsWith("screen:") || sessionId.startsWith("zellij:")) {
13352
13375
  this.streamer.resize(sessionId, cols, rows);
@@ -13354,30 +13377,30 @@ var ControlDispatcher = class {
13354
13377
  }
13355
13378
  /** Update the installed connector package, then restart when a service backend exists. */
13356
13379
  async updateAgentFromNpm() {
13357
- log22.info("updating ragent CLI", { current: CURRENT_VERSION });
13380
+ log23.info("updating ragent CLI", { current: CURRENT_VERSION });
13358
13381
  try {
13359
13382
  await installLatestCliFromNpm();
13360
13383
  } catch (error) {
13361
13384
  const message = error instanceof Error ? error.message : String(error);
13362
- log22.error("failed to update ragent CLI", { error: message });
13385
+ log23.error("failed to update ragent CLI", { error: message });
13363
13386
  return;
13364
13387
  }
13365
13388
  const backend = getConfiguredServiceBackend();
13366
13389
  if (!backend) {
13367
- log22.warn("ragent CLI updated, but no service backend is configured; restart the connector manually to use the new version");
13390
+ log23.warn("ragent CLI updated, but no service backend is configured; restart the connector manually to use the new version");
13368
13391
  return;
13369
13392
  }
13370
- log22.info("ragent CLI updated; restarting connector service", { backend });
13393
+ log23.info("ragent CLI updated; restarting connector service", { backend });
13371
13394
  requestRestartSelfService();
13372
13395
  }
13373
13396
  /** Handle provision request from dashboard. */
13374
13397
  async handleProvision(payload) {
13375
13398
  const provReq = validateProvisionRequest(payload);
13376
13399
  if (!provReq) {
13377
- log22.warn("rejecting provision request \u2014 malformed payload");
13400
+ log23.warn("rejecting provision request \u2014 malformed payload");
13378
13401
  return;
13379
13402
  }
13380
- log22.info("provision request", { name: provReq.manifest.name, provisionId: provReq.provisionId });
13403
+ log23.info("provision request", { name: provReq.manifest.name, provisionId: provReq.provisionId });
13381
13404
  const sendProgress = (progress) => {
13382
13405
  const ws = this.connection.activeSocket;
13383
13406
  if (ws && ws.readyState === import_ws4.default.OPEN && this.connection.activeGroups.registryGroup) {
@@ -13425,7 +13448,7 @@ var ControlDispatcher = class {
13425
13448
  status: "unavailable",
13426
13449
  reason: result.reason
13427
13450
  });
13428
- log22.info("could not enable markdown", { sessionId, reason: result.reason });
13451
+ log23.info("could not enable markdown", { sessionId, reason: result.reason });
13429
13452
  } else {
13430
13453
  this.sendMarkdownStatus({
13431
13454
  type: "markdown",
@@ -13459,24 +13482,24 @@ var ControlDispatcher = class {
13459
13482
  const sessionName = typeof payload?.sessionName === "string" && payload.sessionName.trim().length > 0 ? payload.sessionName.trim() : `agent-${Date.now().toString(36)}`;
13460
13483
  const cmd = typeof payload?.command === "string" && payload.command.trim().length > 0 ? payload.command.trim() : null;
13461
13484
  if (!cmd) {
13462
- log22.warn("start-agent: no command provided, ignoring");
13485
+ log23.warn("start-agent: no command provided, ignoring");
13463
13486
  return;
13464
13487
  }
13465
13488
  if (sessionName.length > 128 || !/^[a-zA-Z0-9_-]+$/.test(sessionName)) {
13466
- log22.warn("start-agent: invalid session name, ignoring");
13489
+ log23.warn("start-agent: invalid session name, ignoring");
13467
13490
  return;
13468
13491
  }
13469
13492
  const danger = detectDangerousCommand(cmd);
13470
13493
  if (danger) {
13471
13494
  if (!this._approvalEnforcer) {
13472
- log22.warn("start-agent: rejected dangerous command (no approval enforcer)", {
13495
+ log23.warn("start-agent: rejected dangerous command (no approval enforcer)", {
13473
13496
  category: danger.category,
13474
13497
  pattern: danger.pattern,
13475
13498
  command: cmd
13476
13499
  });
13477
13500
  return;
13478
13501
  }
13479
- log22.info("start-agent: dangerous command \u2014 awaiting approval", {
13502
+ log23.info("start-agent: dangerous command \u2014 awaiting approval", {
13480
13503
  category: danger.category,
13481
13504
  pattern: danger.pattern,
13482
13505
  sessionName
@@ -13487,28 +13510,28 @@ var ControlDispatcher = class {
13487
13510
  sessionName
13488
13511
  );
13489
13512
  if (response === null) {
13490
- log22.warn("start-agent: dangerous command not covered by approval policy, rejecting", {
13513
+ log23.warn("start-agent: dangerous command not covered by approval policy, rejecting", {
13491
13514
  category: danger.category,
13492
13515
  command: cmd
13493
13516
  });
13494
13517
  return;
13495
13518
  }
13496
13519
  if (response.type !== "approved") {
13497
- log22.warn("start-agent: dangerous command denied or timed out", {
13520
+ log23.warn("start-agent: dangerous command denied or timed out", {
13498
13521
  category: danger.category,
13499
13522
  sessionName,
13500
13523
  responseType: response.type
13501
13524
  });
13502
13525
  return;
13503
13526
  }
13504
- log22.info("start-agent: dangerous command approved", {
13527
+ log23.info("start-agent: dangerous command approved", {
13505
13528
  category: danger.category,
13506
13529
  sessionName
13507
13530
  });
13508
13531
  }
13509
13532
  const rawWorkingDir = typeof payload?.workingDir === "string" && payload.workingDir.trim().length > 0 ? payload.workingDir.trim() : void 0;
13510
13533
  if (rawWorkingDir !== void 0 && !isSafeWorkingDir(rawWorkingDir)) {
13511
- log22.warn("start-agent: rejected unsafe workingDir", { workingDir: rawWorkingDir });
13534
+ log23.warn("start-agent: rejected unsafe workingDir", { workingDir: rawWorkingDir });
13512
13535
  return;
13513
13536
  }
13514
13537
  const workingDir = rawWorkingDir;
@@ -13557,7 +13580,7 @@ var ControlDispatcher = class {
13557
13580
  }
13558
13581
  if (outcome) {
13559
13582
  if (outcome.ok) {
13560
- log22.info("start-agent: launched native-stream", {
13583
+ log23.info("start-agent: launched native-stream", {
13561
13584
  sessionId: outcome.sessionId,
13562
13585
  kind: outcome.kind,
13563
13586
  source: outcome.transcriptSource
@@ -13565,7 +13588,7 @@ var ControlDispatcher = class {
13565
13588
  await this.syncInventory(true);
13566
13589
  return;
13567
13590
  }
13568
- log22.info(
13591
+ log23.info(
13569
13592
  "start-agent: native-stream unavailable; falling through to tmux file-watch",
13570
13593
  { reason: outcome.reason, kind: outcome.kind }
13571
13594
  );
@@ -13585,11 +13608,11 @@ var ControlDispatcher = class {
13585
13608
  let tmuxLaunchOk = false;
13586
13609
  try {
13587
13610
  (0, import_child_process8.execFileSync)("tmux", tmuxArgs, { stdio: "ignore" });
13588
- log22.info("started agent session", { sessionName, command: cmd });
13611
+ log23.info("started agent session", { sessionName, command: cmd });
13589
13612
  tmuxLaunchOk = true;
13590
13613
  } catch (error) {
13591
13614
  const message = error instanceof Error ? error.message : String(error);
13592
- log22.error("failed to start agent session", { sessionName, error: message });
13615
+ log23.error("failed to start agent session", { sessionName, error: message });
13593
13616
  }
13594
13617
  if (tmuxLaunchOk && pendingFallbackOutcome && pendingFallbackOutcome.userMessage) {
13595
13618
  const tmuxSessionId = this.discoverNewlyCreatedPaneId(sessionName);
@@ -13628,7 +13651,7 @@ var ControlDispatcher = class {
13628
13651
  return `tmux:${sessionName}:${info}`;
13629
13652
  }
13630
13653
  } catch (err) {
13631
- log22.warn("display-message failed; status block target may not bind", {
13654
+ log23.warn("display-message failed; status block target may not bind", {
13632
13655
  sessionName,
13633
13656
  err: err instanceof Error ? err.message : String(err)
13634
13657
  });
@@ -13896,7 +13919,7 @@ function isGrantExpired(grant) {
13896
13919
  }
13897
13920
 
13898
13921
  // src/approval-enforcer.ts
13899
- var log23 = createLogger("approval");
13922
+ var log24 = createLogger("approval");
13900
13923
  var ApprovalEnforcer = class {
13901
13924
  policy;
13902
13925
  secret;
@@ -13920,7 +13943,7 @@ var ApprovalEnforcer = class {
13920
13943
  async checkCommand(command, hostId, sessionId) {
13921
13944
  const request = matchPolicy(command, this.policy, hostId, sessionId);
13922
13945
  if (!request) return null;
13923
- log23.info("approval pending", {
13946
+ log24.info("approval pending", {
13924
13947
  action: request.action,
13925
13948
  severity: request.severity,
13926
13949
  requestId: request.requestId
@@ -13929,7 +13952,7 @@ var ApprovalEnforcer = class {
13929
13952
  const timer = setTimeout(() => {
13930
13953
  this.pendingRequests.delete(request.requestId);
13931
13954
  const response = { type: "timeout" };
13932
- log23.info("approval timeout", {
13955
+ log24.info("approval timeout", {
13933
13956
  action: request.action,
13934
13957
  severity: request.severity,
13935
13958
  requestId: request.requestId
@@ -13951,7 +13974,7 @@ var ApprovalEnforcer = class {
13951
13974
  * {@link handleResponse}.
13952
13975
  */
13953
13976
  async requestApproval(request) {
13954
- log23.info("approval pending (direct)", {
13977
+ log24.info("approval pending (direct)", {
13955
13978
  action: request.action,
13956
13979
  severity: request.severity,
13957
13980
  requestId: request.requestId
@@ -13960,7 +13983,7 @@ var ApprovalEnforcer = class {
13960
13983
  const timer = setTimeout(() => {
13961
13984
  this.pendingRequests.delete(request.requestId);
13962
13985
  const response = { type: "timeout" };
13963
- log23.info("approval timeout (direct)", {
13986
+ log24.info("approval timeout (direct)", {
13964
13987
  action: request.action,
13965
13988
  severity: request.severity,
13966
13989
  requestId: request.requestId
@@ -13980,7 +14003,7 @@ var ApprovalEnforcer = class {
13980
14003
  if (!requestId) return;
13981
14004
  const pending = this.pendingRequests.get(requestId);
13982
14005
  if (!pending) {
13983
- log23.warn("received response for unknown approval request", { requestId });
14006
+ log24.warn("received response for unknown approval request", { requestId });
13984
14007
  return;
13985
14008
  }
13986
14009
  if (response.type === "approved") {
@@ -13989,7 +14012,7 @@ var ApprovalEnforcer = class {
13989
14012
  pending.request
13990
14013
  );
13991
14014
  if (bindingMismatch) {
13992
- log23.info("approval rejected (grant binding mismatch)", {
14015
+ log24.info("approval rejected (grant binding mismatch)", {
13993
14016
  action: pending.request.action,
13994
14017
  severity: pending.request.severity,
13995
14018
  requestId,
@@ -14009,7 +14032,7 @@ var ApprovalEnforcer = class {
14009
14032
  return;
14010
14033
  }
14011
14034
  if (!this.acceptGrant(response.grant)) {
14012
- log23.info("approval rejected (invalid grant)", {
14035
+ log24.info("approval rejected (invalid grant)", {
14013
14036
  action: pending.request.action,
14014
14037
  severity: pending.request.severity,
14015
14038
  requestId
@@ -14019,13 +14042,13 @@ var ApprovalEnforcer = class {
14019
14042
  pending.resolve({ type: "denied", denial: { requestId, deniedBy: "system", deniedAt: (/* @__PURE__ */ new Date()).toISOString(), reason: "Invalid or expired grant" } });
14020
14043
  return;
14021
14044
  }
14022
- log23.info("approval approved", {
14045
+ log24.info("approval approved", {
14023
14046
  action: pending.request.action,
14024
14047
  severity: pending.request.severity,
14025
14048
  requestId
14026
14049
  });
14027
14050
  } else if (response.type === "denied") {
14028
- log23.info("approval denied", {
14051
+ log24.info("approval denied", {
14029
14052
  action: pending.request.action,
14030
14053
  severity: pending.request.severity,
14031
14054
  requestId,
@@ -14066,7 +14089,7 @@ var ApprovalEnforcer = class {
14066
14089
  for (const [id, entry] of this.pendingRequests) {
14067
14090
  clearTimeout(entry.timer);
14068
14091
  this.pendingRequests.delete(id);
14069
- log23.info("approval stopped", {
14092
+ log24.info("approval stopped", {
14070
14093
  action: entry.request.action,
14071
14094
  severity: entry.request.severity,
14072
14095
  requestId: id
@@ -14102,7 +14125,7 @@ var ApprovalEnforcer = class {
14102
14125
  if (entry.request.sessionId !== sessionId) continue;
14103
14126
  clearTimeout(entry.timer);
14104
14127
  this.pendingRequests.delete(id);
14105
- log23.info("approval cancelled (session torn down)", {
14128
+ log24.info("approval cancelled (session torn down)", {
14106
14129
  action: entry.request.action,
14107
14130
  severity: entry.request.severity,
14108
14131
  requestId: id,
@@ -14157,7 +14180,7 @@ var ApprovalEnforcer = class {
14157
14180
  };
14158
14181
 
14159
14182
  // src/agent.ts
14160
- var log24 = createLogger("agent");
14183
+ var log25 = createLogger("agent");
14161
14184
  var MAX_TRANSPORT_CHUNK_BYTES = 24 * 1024;
14162
14185
  function pidFilePath(hostId) {
14163
14186
  return path6.join(CONFIG_DIR, `agent-${hostId}.pid`);
@@ -14242,15 +14265,15 @@ async function runAgent(rawOptions) {
14242
14265
  const config = loadConfig();
14243
14266
  if (config.redaction?.enabled === false || rawOptions.redact === false) {
14244
14267
  setRedactionEnabled(false);
14245
- log24.info("secret redaction disabled");
14268
+ log25.info("secret redaction disabled");
14246
14269
  }
14247
- log24.info("connector started", { hostName: options.hostName, hostId: options.hostId });
14248
- log24.info("portal", { portal: options.portal });
14270
+ log25.info("connector started", { hostName: options.hostName, hostId: options.hostId });
14271
+ log25.info("portal", { portal: options.portal });
14249
14272
  try {
14250
14273
  const existingSessions = await collectSessionInventory(options.hostId, options.command);
14251
14274
  const tmuxCount = existingSessions.filter((s) => s.type === "tmux").length;
14252
14275
  if (tmuxCount > 0) {
14253
- log24.info("found existing tmux sessions", { count: tmuxCount });
14276
+ log25.info("found existing tmux sessions", { count: tmuxCount });
14254
14277
  }
14255
14278
  } catch {
14256
14279
  }
@@ -14484,7 +14507,7 @@ async function runAgent(rawOptions) {
14484
14507
  dispatcher.setApprovalEnforcer(null);
14485
14508
  }
14486
14509
  ws.on("open", async () => {
14487
- log24.info("connector connected to relay");
14510
+ log25.info("connector connected to relay");
14488
14511
  conn.resetReconnectDelay();
14489
14512
  ws.send(JSON.stringify({ type: "joinGroup", group: groups.privateGroup }));
14490
14513
  ws.send(JSON.stringify({ type: "joinGroup", group: groups.registryGroup }));
@@ -14552,9 +14575,9 @@ async function runAgent(rawOptions) {
14552
14575
  const inSeq = typeof payload.seq === "number" ? payload.seq : null;
14553
14576
  const rxSeq = conn.getRxSeqForViewer(payload.viewerId);
14554
14577
  if (inSeq === null) {
14555
- log24.warn("rejecting encrypted input frame without seq (#310)");
14578
+ log25.warn("rejecting encrypted input frame without seq (#310)");
14556
14579
  } else if (!rxSeq.accept(inSeq)) {
14557
- log24.warn("rejecting replayed/out-of-order input", {
14580
+ log25.warn("rejecting replayed/out-of-order input", {
14558
14581
  seq: inSeq,
14559
14582
  lastSeen: rxSeq.lastSeq,
14560
14583
  viewerId: typeof payload.viewerId === "string" ? payload.viewerId : "_legacy"
@@ -14567,13 +14590,13 @@ async function runAgent(rawOptions) {
14567
14590
  inSeq
14568
14591
  );
14569
14592
  if (inputData === null) {
14570
- log24.warn("failed to decrypt input \u2014 ignoring");
14593
+ log25.warn("failed to decrypt input \u2014 ignoring");
14571
14594
  }
14572
14595
  }
14573
14596
  } else if (typeof payload.data === "string" && !conn.sessionKey) {
14574
14597
  inputData = payload.data;
14575
14598
  } else if (conn.sessionKey) {
14576
- log24.warn("rejecting plaintext input frame while encrypted channel is active");
14599
+ log25.warn("rejecting plaintext input frame while encrypted channel is active");
14577
14600
  }
14578
14601
  if (inputData !== null) {
14579
14602
  const sid = typeof payload.sessionId === "string" ? payload.sessionId.trim() : "";
@@ -14581,7 +14604,7 @@ async function runAgent(rawOptions) {
14581
14604
  }
14582
14605
  } else if (payload.type === "resize" && Number.isInteger(payload.cols) && Number.isInteger(payload.rows)) {
14583
14606
  if (conn.sessionKey && !dispatcher.verifyMessageHmac(payload)) {
14584
- log24.warn("rejecting resize frame \u2014 HMAC verification failed");
14607
+ log25.warn("rejecting resize frame \u2014 HMAC verification failed");
14585
14608
  return;
14586
14609
  }
14587
14610
  const sid = typeof payload.sessionId === "string" ? payload.sessionId.trim() : "";
@@ -14593,11 +14616,11 @@ async function runAgent(rawOptions) {
14593
14616
  const inSeq = typeof payload.seq === "number" ? payload.seq : null;
14594
14617
  const rxSeq = conn.getRxSeqForViewer(payload.viewerId);
14595
14618
  if (inSeq === null) {
14596
- log24.warn("rejecting encrypted control frame without seq");
14619
+ log25.warn("rejecting encrypted control frame without seq");
14597
14620
  return;
14598
14621
  }
14599
14622
  if (!rxSeq.accept(inSeq)) {
14600
- log24.warn("rejecting replayed/out-of-order control", {
14623
+ log25.warn("rejecting replayed/out-of-order control", {
14601
14624
  seq: inSeq,
14602
14625
  lastSeen: rxSeq.lastSeq,
14603
14626
  viewerId: typeof payload.viewerId === "string" ? payload.viewerId : "_legacy"
@@ -14611,7 +14634,7 @@ async function runAgent(rawOptions) {
14611
14634
  inSeq
14612
14635
  );
14613
14636
  if (decrypted === null) {
14614
- log24.warn("failed to decrypt control \u2014 ignoring");
14637
+ log25.warn("failed to decrypt control \u2014 ignoring");
14615
14638
  return;
14616
14639
  }
14617
14640
  try {
@@ -14620,11 +14643,11 @@ async function runAgent(rawOptions) {
14620
14643
  _verifiedEncrypted: true
14621
14644
  };
14622
14645
  } catch {
14623
- log24.warn("failed to parse encrypted control payload");
14646
+ log25.warn("failed to parse encrypted control payload");
14624
14647
  return;
14625
14648
  }
14626
14649
  } else if (conn.sessionKey && payload.action === "upload-file") {
14627
- log24.warn("rejecting plaintext attachment upload while encrypted channel is active");
14650
+ log25.warn("rejecting plaintext attachment upload while encrypted channel is active");
14628
14651
  return;
14629
14652
  }
14630
14653
  await dispatcher.handleControlAction(controlPayload);
@@ -14644,13 +14667,13 @@ async function runAgent(rawOptions) {
14644
14667
  }
14645
14668
  });
14646
14669
  ws.on("error", (error) => {
14647
- log24.error("websocket error", { error: error.message });
14670
+ log25.error("websocket error", { error: error.message });
14648
14671
  });
14649
14672
  ws.on("close", (code, reason) => {
14650
14673
  const fields = {};
14651
14674
  if (code) fields.code = code;
14652
14675
  if (reason.length > 0) fields.reason = reason.toString();
14653
- log24.info("relay disconnected; output will be buffered until reconnect", fields);
14676
+ log25.info("relay disconnected; output will be buffered until reconnect", fields);
14654
14677
  conn.cleanup();
14655
14678
  resolve();
14656
14679
  });
@@ -14667,35 +14690,35 @@ async function runAgent(rawOptions) {
14667
14690
  });
14668
14691
  inventory.updateOptions(options);
14669
14692
  dispatcher.updateOptions(options);
14670
- log24.info("recovered from auth failure via machine credential; reconnecting");
14693
+ log25.info("recovered from auth failure via machine credential; reconnecting");
14671
14694
  continue;
14672
14695
  } catch (mcError) {
14673
14696
  if (mcError instanceof AuthError) {
14674
- log24.error("auth recovery failed", { error: mcError.message });
14697
+ log25.error("auth recovery failed", { error: mcError.message });
14675
14698
  } else {
14676
14699
  const mcMsg = mcError instanceof Error ? mcError.message : String(mcError);
14677
- log24.error("machine credential recovery failed", { error: mcMsg });
14700
+ log25.error("machine credential recovery failed", { error: mcMsg });
14678
14701
  }
14679
14702
  }
14680
14703
  }
14681
- log24.error("auth error", { error: error.message });
14682
- log24.error(
14704
+ log25.error("auth error", { error: error.message });
14705
+ log25.error(
14683
14706
  "connector token is invalid or revoked. Stopping. Re-connect with: ragent connect --token <token>"
14684
14707
  );
14685
14708
  dispatcher.shouldRun = false;
14686
14709
  break;
14687
14710
  }
14688
14711
  const message = error instanceof Error ? error.message : String(error);
14689
- log24.error("relay connect failed", { error: message });
14712
+ log25.error("relay connect failed", { error: message });
14690
14713
  }
14691
14714
  if (!dispatcher.shouldRun) break;
14692
14715
  if (dispatcher.reconnectRequested) {
14693
- log24.info("reconnecting to relay");
14716
+ log25.info("reconnecting to relay");
14694
14717
  await wait(300);
14695
14718
  continue;
14696
14719
  }
14697
14720
  const jitteredDelay = conn.reconnectDelay * (0.5 + Math.random());
14698
- log24.info("disconnected; reconnecting", { seconds: Math.round(jitteredDelay / 1e3) });
14721
+ log25.info("disconnected; reconnecting", { seconds: Math.round(jitteredDelay / 1e3) });
14699
14722
  await wait(jitteredDelay);
14700
14723
  conn.reconnectDelay = Math.min(conn.reconnectDelay * 1.5, MAX_RECONNECT_DELAY_MS);
14701
14724
  }
@@ -14795,7 +14818,7 @@ function printCommandArt(title, subtitle = "remote agent control") {
14795
14818
  }
14796
14819
 
14797
14820
  // src/commands/connect.ts
14798
- var log25 = createLogger("connect");
14821
+ var log26 = createLogger("connect");
14799
14822
  async function connectMachine(opts) {
14800
14823
  const portal = opts.portal || DEFAULT_PORTAL;
14801
14824
  const hostId = sanitizeHostId(opts.id || inferHostId());
@@ -14827,12 +14850,12 @@ async function connectMachine(opts) {
14827
14850
  nextConfig.refreshExpiresAt = claimed.refreshExpiresAt;
14828
14851
  }
14829
14852
  saveConfig(nextConfig);
14830
- log25.info("machine connected", { hostName, hostId });
14831
- log25.info("machine name (override with --name <friendly-name>)", { hostName });
14832
- log25.info("config saved", { path: CONFIG_FILE });
14853
+ log26.info("machine connected", { hostName, hostId });
14854
+ log26.info("machine name (override with --name <friendly-name>)", { hostName });
14855
+ log26.info("config saved", { path: CONFIG_FILE });
14833
14856
  if (opts.asService) {
14834
14857
  await ensureServiceInstalled({ enable: true, start: true });
14835
- log25.info("service mode enabled");
14858
+ log26.info("service mode enabled");
14836
14859
  return;
14837
14860
  }
14838
14861
  if (opts.run !== false) {
@@ -14852,14 +14875,14 @@ function registerConnectCommand(program2) {
14852
14875
  await connectMachine(opts);
14853
14876
  } catch (error) {
14854
14877
  const message = error instanceof Error ? error.message : String(error);
14855
- log25.error("connect failed", { error: message });
14878
+ log26.error("connect failed", { error: message });
14856
14879
  process.exit(1);
14857
14880
  }
14858
14881
  });
14859
14882
  }
14860
14883
 
14861
14884
  // src/commands/run.ts
14862
- var log26 = createLogger("run");
14885
+ var log27 = createLogger("run");
14863
14886
  function registerRunCommand(program2) {
14864
14887
  program2.command("run").description("Run connector for a connected machine").option("--portal <url>", "Portal base URL").option("--agent-token <token>", "Connector token").option("-i, --id <id>", "Machine ID").option("-n, --name <name>", "Machine name").option("-c, --command <command>", "CLI command to run").option("--no-redact", "Disable secret redaction in terminal output").action(async (opts) => {
14865
14888
  try {
@@ -14867,7 +14890,7 @@ function registerRunCommand(program2) {
14867
14890
  await runAgent(opts);
14868
14891
  } catch (error) {
14869
14892
  const message = error instanceof Error ? error.message : String(error);
14870
- log26.error("run failed", { error: message });
14893
+ log27.error("run failed", { error: message });
14871
14894
  process.exit(1);
14872
14895
  }
14873
14896
  });
@@ -14875,7 +14898,7 @@ function registerRunCommand(program2) {
14875
14898
 
14876
14899
  // src/commands/doctor.ts
14877
14900
  var os12 = __toESM(require("os"));
14878
- var log27 = createLogger("doctor");
14901
+ var log28 = createLogger("doctor");
14879
14902
  async function runDoctor(opts) {
14880
14903
  const options = resolveRunOptions(opts);
14881
14904
  const checks = [];
@@ -14911,27 +14934,27 @@ async function runDoctor(opts) {
14911
14934
  console.log(`${check.ok ? "PASS" : "FAIL"} ${check.name}: ${check.detail}`);
14912
14935
  });
14913
14936
  if (!platformOk) {
14914
- log27.info("Linux is required for the connector");
14937
+ log28.info("Linux is required for the connector");
14915
14938
  }
14916
14939
  if (!tmuxOk) {
14917
14940
  const recipe = await chooseTmuxInstallCommand();
14918
14941
  if (recipe) {
14919
- log27.info("tmux install suggestion", { command: recipe.command });
14942
+ log28.info("tmux install suggestion", { command: recipe.command });
14920
14943
  }
14921
14944
  if (opts.fix) {
14922
14945
  try {
14923
14946
  const installed = await installTmuxInteractively();
14924
14947
  if (installed) {
14925
- log27.info("tmux installation complete");
14948
+ log28.info("tmux installation complete");
14926
14949
  } else {
14927
- log27.info("tmux installation skipped or incomplete");
14950
+ log28.info("tmux installation skipped or incomplete");
14928
14951
  }
14929
14952
  } catch (error) {
14930
14953
  const message = error instanceof Error ? error.message : String(error);
14931
- log27.error("failed to install tmux", { error: message });
14954
+ log28.error("failed to install tmux", { error: message });
14932
14955
  }
14933
14956
  } else {
14934
- log27.info("run `ragent doctor --fix` to install missing dependencies interactively");
14957
+ log28.info("run `ragent doctor --fix` to install missing dependencies interactively");
14935
14958
  }
14936
14959
  }
14937
14960
  }
@@ -14943,30 +14966,30 @@ function registerDoctorCommand(program2) {
14943
14966
  }
14944
14967
 
14945
14968
  // src/commands/update.ts
14946
- var log28 = createLogger("update");
14969
+ var log29 = createLogger("update");
14947
14970
  function registerUpdateCommand(program2) {
14948
14971
  program2.command("update").description("Update ragent CLI from npm").option("--check", "Check for updates only; do not install").option("--no-restart", "Do not restart the service after updating").action(async (opts) => {
14949
14972
  printCommandArt("Update", "checking npm registry for newer ragent-cli versions");
14950
14973
  const latestVersion = await checkForUpdate({ force: true });
14951
14974
  if (!latestVersion) {
14952
- log28.info("you are up to date", { version: CURRENT_VERSION });
14975
+ log29.info("you are up to date", { version: CURRENT_VERSION });
14953
14976
  return;
14954
14977
  }
14955
- log28.info("update available", { current: CURRENT_VERSION, latest: latestVersion });
14978
+ log29.info("update available", { current: CURRENT_VERSION, latest: latestVersion });
14956
14979
  if (opts.check) return;
14957
14980
  await installLatestCliFromNpm();
14958
- log28.info("updated", { version: latestVersion });
14981
+ log29.info("updated", { version: latestVersion });
14959
14982
  const backend = getConfiguredServiceBackend();
14960
14983
  if (backend && opts.restart) {
14961
- log28.info("restarting service", { backend });
14984
+ log29.info("restarting service", { backend });
14962
14985
  try {
14963
14986
  await restartService();
14964
14987
  } catch (err) {
14965
- log28.error("failed to restart service", { error: err instanceof Error ? err.message : String(err) });
14966
- log28.info("please restart manually: ragent service restart");
14988
+ log29.error("failed to restart service", { error: err instanceof Error ? err.message : String(err) });
14989
+ log29.info("please restart manually: ragent service restart");
14967
14990
  }
14968
14991
  } else if (!backend) {
14969
- log28.info("no service backend detected. If ragent is running manually, restart it to use the new version");
14992
+ log29.info("no service backend detected. If ragent is running manually, restart it to use the new version");
14970
14993
  }
14971
14994
  });
14972
14995
  }
@@ -14990,7 +15013,7 @@ function registerSessionsCommand(program2) {
14990
15013
  }
14991
15014
 
14992
15015
  // src/commands/service.ts
14993
- var log29 = createLogger("service-cmd");
15016
+ var log30 = createLogger("service-cmd");
14994
15017
  function registerServiceCommand(program2) {
14995
15018
  const service = program2.command("service").description("Manage background connector service");
14996
15019
  service.command("install").description("Install service (systemd user unit when available)").option("--start", "Start service immediately").option("--no-enable", "Do not enable autostart in systemd").action(async (opts) => {
@@ -15001,7 +15024,7 @@ function registerServiceCommand(program2) {
15001
15024
  });
15002
15025
  } catch (error) {
15003
15026
  const message = error instanceof Error ? error.message : String(error);
15004
- log29.error("service install failed", { error: message });
15027
+ log30.error("service install failed", { error: message });
15005
15028
  process.exit(1);
15006
15029
  }
15007
15030
  });
@@ -15010,7 +15033,7 @@ function registerServiceCommand(program2) {
15010
15033
  await startService();
15011
15034
  } catch (error) {
15012
15035
  const message = error instanceof Error ? error.message : String(error);
15013
- log29.error("service start failed", { error: message });
15036
+ log30.error("service start failed", { error: message });
15014
15037
  process.exit(1);
15015
15038
  }
15016
15039
  });
@@ -15019,7 +15042,7 @@ function registerServiceCommand(program2) {
15019
15042
  await stopService();
15020
15043
  } catch (error) {
15021
15044
  const message = error instanceof Error ? error.message : String(error);
15022
- log29.error("service stop failed", { error: message });
15045
+ log30.error("service stop failed", { error: message });
15023
15046
  process.exit(1);
15024
15047
  }
15025
15048
  });
@@ -15028,7 +15051,7 @@ function registerServiceCommand(program2) {
15028
15051
  await restartService();
15029
15052
  } catch (error) {
15030
15053
  const message = error instanceof Error ? error.message : String(error);
15031
- log29.error("service restart failed", { error: message });
15054
+ log30.error("service restart failed", { error: message });
15032
15055
  process.exit(1);
15033
15056
  }
15034
15057
  });
@@ -15037,7 +15060,7 @@ function registerServiceCommand(program2) {
15037
15060
  await printServiceStatus();
15038
15061
  } catch (error) {
15039
15062
  const message = error instanceof Error ? error.message : String(error);
15040
- log29.error("service status failed", { error: message });
15063
+ log30.error("service status failed", { error: message });
15041
15064
  process.exit(1);
15042
15065
  }
15043
15066
  });
@@ -15046,7 +15069,7 @@ function registerServiceCommand(program2) {
15046
15069
  await printServiceLogs(opts);
15047
15070
  } catch (error) {
15048
15071
  const message = error instanceof Error ? error.message : String(error);
15049
- log29.error("service logs failed", { error: message });
15072
+ log30.error("service logs failed", { error: message });
15050
15073
  process.exit(1);
15051
15074
  }
15052
15075
  });
@@ -15055,7 +15078,7 @@ function registerServiceCommand(program2) {
15055
15078
  await uninstallService();
15056
15079
  } catch (error) {
15057
15080
  const message = error instanceof Error ? error.message : String(error);
15058
- log29.error("service uninstall failed", { error: message });
15081
+ log30.error("service uninstall failed", { error: message });
15059
15082
  process.exit(1);
15060
15083
  }
15061
15084
  });
@@ -15063,7 +15086,7 @@ function registerServiceCommand(program2) {
15063
15086
 
15064
15087
  // src/commands/uninstall.ts
15065
15088
  var fs8 = __toESM(require("fs"));
15066
- var log30 = createLogger("uninstall");
15089
+ var log31 = createLogger("uninstall");
15067
15090
  async function uninstallAgent(opts) {
15068
15091
  const config = loadConfig();
15069
15092
  const hostName = config.hostName || config.hostId || "this machine";
@@ -15073,12 +15096,12 @@ async function uninstallAgent(opts) {
15073
15096
  false
15074
15097
  );
15075
15098
  if (!confirmed) {
15076
- log30.info("uninstall cancelled");
15099
+ log31.info("uninstall cancelled");
15077
15100
  return;
15078
15101
  }
15079
15102
  }
15080
15103
  if (config.portal && config.agentToken) {
15081
- log30.info("deregistering from server");
15104
+ log31.info("deregistering from server");
15082
15105
  try {
15083
15106
  const token = await refreshTokenIfNeeded({
15084
15107
  portal: config.portal,
@@ -15086,24 +15109,24 @@ async function uninstallAgent(opts) {
15086
15109
  });
15087
15110
  const ok = await deregisterHost({ portal: config.portal, agentToken: token });
15088
15111
  if (ok) {
15089
- log30.info("host removed from server");
15112
+ log31.info("host removed from server");
15090
15113
  }
15091
15114
  } catch {
15092
- log30.warn("could not reach server \u2014 host may need manual removal from dashboard");
15115
+ log31.warn("could not reach server \u2014 host may need manual removal from dashboard");
15093
15116
  }
15094
15117
  }
15095
- log30.info("stopping and removing service");
15118
+ log31.info("stopping and removing service");
15096
15119
  await uninstallService().catch(() => void 0);
15097
15120
  if (fs8.existsSync(CONFIG_DIR)) {
15098
15121
  fs8.rmSync(CONFIG_DIR, { recursive: true, force: true });
15099
- log30.info("removed config directory", { path: CONFIG_DIR });
15122
+ log31.info("removed config directory", { path: CONFIG_DIR });
15100
15123
  }
15101
15124
  try {
15102
15125
  await execAsync(`npm unlink -g ${PACKAGE_NAME}`, { timeout: 15e3 });
15103
- log30.info("unlinked global package", { package: PACKAGE_NAME });
15126
+ log31.info("unlinked global package", { package: PACKAGE_NAME });
15104
15127
  } catch {
15105
15128
  }
15106
- log30.info("uninstall complete. rAgent has been removed from this machine");
15129
+ log31.info("uninstall complete. rAgent has been removed from this machine");
15107
15130
  }
15108
15131
  function registerUninstallCommand(parent) {
15109
15132
  parent.command("uninstall").description("Remove rAgent from this machine (stops service, deletes config, unlinks CLI)").option("-y, --yes", "Skip confirmation prompt").action(async (opts) => {
@@ -15112,7 +15135,7 @@ function registerUninstallCommand(parent) {
15112
15135
  await uninstallAgent(opts);
15113
15136
  } catch (error) {
15114
15137
  const message = error instanceof Error ? error.message : String(error);
15115
- log30.error("uninstall failed", { error: message });
15138
+ log31.error("uninstall failed", { error: message });
15116
15139
  process.exit(1);
15117
15140
  }
15118
15141
  });
@@ -15171,10 +15194,10 @@ function registerDiscoverCommand(program2) {
15171
15194
  }
15172
15195
 
15173
15196
  // src/index.ts
15174
- var log31 = createLogger("cli");
15197
+ var log32 = createLogger("cli");
15175
15198
  process.on("unhandledRejection", (reason) => {
15176
15199
  const message = reason instanceof Error ? reason.stack || reason.message : String(reason);
15177
- log31.error("unhandled promise rejection", { error: message });
15200
+ log32.error("unhandled promise rejection", { error: message });
15178
15201
  });
15179
15202
  import_commander.program.name("ragent").description("Connect machines to rAgent Live").version(CURRENT_VERSION);
15180
15203
  registerConnectCommand(import_commander.program);