ragent-cli 1.11.13 → 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.13",
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: {
@@ -9692,6 +9692,7 @@ function resolveRuntimeTranscriptSource(sessionId) {
9692
9692
  }
9693
9693
 
9694
9694
  // src/sessions.ts
9695
+ var log15 = createLogger("sessions");
9695
9696
  var isMac = os5.platform() === "darwin";
9696
9697
  var MARKDOWN_AGENT_TYPES = /* @__PURE__ */ new Set(["Claude Code", "Codex CLI", "Gemini CLI", "Antigravity CLI"]);
9697
9698
  var isTmuxAvailable = null;
@@ -10089,18 +10090,15 @@ function transcriptSourceForSession(agentType, sessionId) {
10089
10090
  }
10090
10091
  async function collectBareAgentProcesses(excludePids, processList, processByPid) {
10091
10092
  try {
10092
- const tStart = performance.now();
10093
10093
  if (!processList || !processByPid) {
10094
10094
  const list = await getProcessTable();
10095
10095
  processList = list;
10096
10096
  processByPid = new Map(list.map((p) => [p.pid, p]));
10097
10097
  }
10098
- const tInit = performance.now();
10099
10098
  const sessions = [];
10100
10099
  const seen = /* @__PURE__ */ new Set();
10101
10100
  const excluded = excludePids ?? /* @__PURE__ */ new Set();
10102
10101
  const parentByPid = new Map(processList.map((row) => [row.pid, row.ppid]));
10103
- const tParentMap = performance.now();
10104
10102
  const hasTrackedAncestor = (pid, tracked) => {
10105
10103
  const visited = /* @__PURE__ */ new Set();
10106
10104
  let current = parentByPid.get(pid) ?? 0;
@@ -10111,7 +10109,6 @@ async function collectBareAgentProcesses(excludePids, processList, processByPid)
10111
10109
  }
10112
10110
  return false;
10113
10111
  };
10114
- const tFilterStart = performance.now();
10115
10112
  const candidates = processList.filter((row) => {
10116
10113
  const { pid, tty, stat, args } = row;
10117
10114
  if (!hasControllingTty(tty)) return false;
@@ -10122,8 +10119,6 @@ async function collectBareAgentProcesses(excludePids, processList, processByPid)
10122
10119
  if (!hasKeyword) return false;
10123
10120
  return true;
10124
10121
  });
10125
- const tFilterEnd = performance.now();
10126
- const tCwdsStart = performance.now();
10127
10122
  const cwds = await Promise.all(
10128
10123
  candidates.map(async (row) => {
10129
10124
  const cwd = await getProcessWorkingDir(row.pid);
@@ -10131,40 +10126,22 @@ async function collectBareAgentProcesses(excludePids, processList, processByPid)
10131
10126
  })
10132
10127
  );
10133
10128
  const cwdByPid = new Map(cwds.map((c) => [c.pid, c.cwd]));
10134
- const tCwdsEnd = performance.now();
10135
- let tLoopAncestor = 0;
10136
- let tLoopClassify = 0;
10137
- let tLoopVscode = 0;
10138
- let tLoopMarkdown = 0;
10139
- let tLoopStartTimes = 0;
10140
- const tLoopStart = performance.now();
10141
10129
  for (const row of candidates) {
10142
10130
  const { pid, args } = row;
10143
- const t0 = performance.now();
10144
- const skip = seen.has(pid) || hasTrackedAncestor(pid, seen);
10145
- tLoopAncestor += performance.now() - t0;
10146
- if (skip) continue;
10131
+ if (seen.has(pid) || hasTrackedAncestor(pid, seen)) continue;
10147
10132
  const workingDir = cwdByPid.get(pid) || null;
10148
- const t1 = performance.now();
10149
10133
  let classification = classifyAgent(args);
10150
10134
  if (!classification) {
10151
10135
  classification = classifyAgent(args, { workingDir: workingDir ?? void 0 });
10152
10136
  }
10153
- tLoopClassify += performance.now() - t1;
10154
10137
  if (!classification) continue;
10155
10138
  seen.add(pid);
10156
10139
  const dirName = workingDir ? workingDir.split("/").pop() : null;
10157
10140
  const displayName = dirName && dirName !== "/" && dirName !== "" ? `${classification.agentType} (${dirName})` : `${classification.agentType} (pid ${pid})`;
10158
- const t2 = performance.now();
10159
10141
  const vscodeDetected = await detectVscodeEnvironment(pid, processByPid);
10160
- tLoopVscode += performance.now() - t2;
10161
10142
  const id = `process:${pid}`;
10162
- const t3 = performance.now();
10163
10143
  const mdAvail = markdownAvailableForSession(id, classification.agentType);
10164
- tLoopMarkdown += performance.now() - t3;
10165
- const t4 = performance.now();
10166
10144
  const startTimes = collectStartTimes([pid]);
10167
- tLoopStartTimes += performance.now() - t4;
10168
10145
  sessions.push({
10169
10146
  id,
10170
10147
  type: "process",
@@ -10182,20 +10159,11 @@ async function collectBareAgentProcesses(excludePids, processList, processByPid)
10182
10159
  startTimes
10183
10160
  });
10184
10161
  }
10185
- const tLoopEnd = performance.now();
10186
- console.log(`[PROFILE-BARE] Init took ${(tInit - tStart).toFixed(2)} ms`);
10187
- console.log(`[PROFILE-BARE] Parent map took ${(tParentMap - tInit).toFixed(2)} ms`);
10188
- console.log(`[PROFILE-BARE] Filtering took ${(tFilterEnd - tFilterStart).toFixed(2)} ms`);
10189
- console.log(`[PROFILE-BARE] CWDs took ${(tCwdsEnd - tCwdsStart).toFixed(2)} ms`);
10190
- console.log(`[PROFILE-BARE] Loop total took ${(tLoopEnd - tLoopStart).toFixed(2)} ms`);
10191
- console.log(` [PROFILE-BARE-LOOP] Ancestor checks: ${tLoopAncestor.toFixed(2)} ms`);
10192
- console.log(` [PROFILE-BARE-LOOP] Classify: ${tLoopClassify.toFixed(2)} ms`);
10193
- console.log(` [PROFILE-BARE-LOOP] VS Code env: ${tLoopVscode.toFixed(2)} ms`);
10194
- console.log(` [PROFILE-BARE-LOOP] Markdown check: ${tLoopMarkdown.toFixed(2)} ms`);
10195
- console.log(` [PROFILE-BARE-LOOP] Start times: ${tLoopStartTimes.toFixed(2)} ms`);
10196
10162
  return sessions;
10197
10163
  } catch (err) {
10198
- console.error("[PROFILE-BARE] Error:", err);
10164
+ log15.error("collectBareAgentProcesses failed", {
10165
+ error: err instanceof Error ? err.stack || err.message : String(err)
10166
+ });
10199
10167
  return [];
10200
10168
  }
10201
10169
  }
@@ -10361,7 +10329,7 @@ async function getChildAgentInfo(parentPid, childrenByPpid, visited = /* @__PURE
10361
10329
  }
10362
10330
 
10363
10331
  // src/auth.ts
10364
- var log15 = createLogger("auth");
10332
+ var log16 = createLogger("auth");
10365
10333
  var AuthError = class extends Error {
10366
10334
  constructor(message) {
10367
10335
  super(message);
@@ -10379,7 +10347,7 @@ function decodeJwtExp(token) {
10379
10347
  }
10380
10348
  }
10381
10349
  async function startSessionWithMachineSecret(params) {
10382
- log15.info("attempting session recovery with machine credential");
10350
+ log16.info("attempting session recovery with machine credential");
10383
10351
  const response = await fetch(`${params.portal}/api/agent/session/start`, {
10384
10352
  method: "POST",
10385
10353
  headers: { "Content-Type": "application/json" },
@@ -10412,7 +10380,7 @@ async function startSessionWithMachineSecret(params) {
10412
10380
  patch.refreshExpiresAt = data.refreshExpiresAt || "";
10413
10381
  }
10414
10382
  saveConfigPatch(patch);
10415
- log15.info("session recovered via machine credential");
10383
+ log16.info("session recovered via machine credential");
10416
10384
  return data.agentToken;
10417
10385
  }
10418
10386
  async function refreshTokenIfNeeded(params) {
@@ -10423,7 +10391,7 @@ async function refreshTokenIfNeeded(params) {
10423
10391
  const remainingSeconds = exp - Math.floor(Date.now() / 1e3);
10424
10392
  const threshold2 = remainingSeconds < 3600 ? 120 : 3600;
10425
10393
  if (remainingSeconds > threshold2) return params.agentToken;
10426
- log15.info("token expiring \u2014 refreshing", { minutesRemaining: Math.round(remainingSeconds / 60) });
10394
+ log16.info("token expiring \u2014 refreshing", { minutesRemaining: Math.round(remainingSeconds / 60) });
10427
10395
  try {
10428
10396
  const headers = { "Content-Type": "application/json" };
10429
10397
  let body = {};
@@ -10439,7 +10407,7 @@ async function refreshTokenIfNeeded(params) {
10439
10407
  });
10440
10408
  if (!response.ok) {
10441
10409
  const errorData = await response.json().catch(() => ({}));
10442
- log15.warn("token refresh failed", { error: errorData.error || response.status });
10410
+ log16.warn("token refresh failed", { error: errorData.error || response.status });
10443
10411
  if (config.machineSecret && config.hostId) {
10444
10412
  try {
10445
10413
  return await startSessionWithMachineSecret({
@@ -10450,7 +10418,7 @@ async function refreshTokenIfNeeded(params) {
10450
10418
  } catch (mcError) {
10451
10419
  if (mcError instanceof AuthError) throw mcError;
10452
10420
  const mcMessage = mcError instanceof Error ? mcError.message : String(mcError);
10453
- log15.warn("machine credential recovery failed", { error: mcMessage });
10421
+ log16.warn("machine credential recovery failed", { error: mcMessage });
10454
10422
  }
10455
10423
  }
10456
10424
  return params.agentToken;
@@ -10469,12 +10437,12 @@ async function refreshTokenIfNeeded(params) {
10469
10437
  patch.machineSecret = data.machineSecret;
10470
10438
  }
10471
10439
  saveConfigPatch(patch);
10472
- log15.info("token refreshed successfully");
10440
+ log16.info("token refreshed successfully");
10473
10441
  return data.agentToken;
10474
10442
  } catch (error) {
10475
10443
  if (error instanceof AuthError) throw error;
10476
10444
  const message = error instanceof Error ? error.message : String(error);
10477
- log15.warn("token refresh error", { error: message });
10445
+ log16.warn("token refresh error", { error: message });
10478
10446
  return params.agentToken;
10479
10447
  }
10480
10448
  }
@@ -10537,7 +10505,7 @@ async function deregisterHost(params) {
10537
10505
  body: JSON.stringify({})
10538
10506
  });
10539
10507
  if (response.status === 401 || response.status === 403) {
10540
- 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");
10541
10509
  return false;
10542
10510
  }
10543
10511
  return response.ok;
@@ -10677,6 +10645,9 @@ function getQueuePressure() {
10677
10645
  else if (level < PRESSURE_LOW) pressureIsHigh = false;
10678
10646
  return { level, isHigh: pressureIsHigh };
10679
10647
  }
10648
+ function getDroppedFrameCount() {
10649
+ return droppedFrames;
10650
+ }
10680
10651
  function drainQueue() {
10681
10652
  if (!drainWs || drainWs.readyState !== import_ws.default.OPEN) {
10682
10653
  stopDrainTimer();
@@ -10760,7 +10731,7 @@ var import_node_path = require("path");
10760
10731
  var import_node_os = require("os");
10761
10732
  var import_node_string_decoder = require("string_decoder");
10762
10733
  var pty = __toESM(require("node-pty"));
10763
- var log16 = createLogger("session-streamer");
10734
+ var log17 = createLogger("session-streamer");
10764
10735
  var BACKPRESSURE_RESUME_CHECK_MS = 100;
10765
10736
  var STOP_DEBOUNCE_MS = 2e3;
10766
10737
  var MAX_CONCURRENT_STREAMS = 20;
@@ -10862,6 +10833,10 @@ var SessionStreamer = class {
10862
10833
  disconnectBufferBytes = /* @__PURE__ */ new Map();
10863
10834
  /** Timer that resumes paused PTYs once the WS queue drains. See #332. */
10864
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();
10865
10840
  constructor(sendFn, onStreamStopped) {
10866
10841
  this.sendFn = sendFn;
10867
10842
  this.onStreamStopped = onStreamStopped;
@@ -10872,6 +10847,14 @@ var SessionStreamer = class {
10872
10847
  * When the WS queue is saturated, PTY onData stops firing after we call
10873
10848
  * ptyProc.pause(). We need an independent loop to check pressure and
10874
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).
10875
10858
  */
10876
10859
  startBackpressureResumeTimer() {
10877
10860
  if (this.backpressureResumeTimer) return;
@@ -10883,11 +10866,32 @@ var SessionStreamer = class {
10883
10866
  try {
10884
10867
  stream.ptyProc.resume();
10885
10868
  stream.ptyPaused = false;
10886
- 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 });
10887
10870
  } catch {
10888
10871
  }
10889
10872
  }
10890
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
+ }
10891
10895
  }, BACKPRESSURE_RESUME_CHECK_MS);
10892
10896
  }
10893
10897
  /**
@@ -10902,7 +10906,7 @@ var SessionStreamer = class {
10902
10906
  try {
10903
10907
  stream.ptyProc.pause();
10904
10908
  stream.ptyPaused = true;
10905
- log16.warn("pty-attach paused under WS backpressure", {
10909
+ log17.warn("pty-attach paused under WS backpressure", {
10906
10910
  sessionId: stream.sessionId,
10907
10911
  queueLevel: pressure.level.toFixed(2)
10908
10912
  });
@@ -10926,7 +10930,7 @@ var SessionStreamer = class {
10926
10930
  }
10927
10931
  }
10928
10932
  if (entries.some((e) => e.startsWith("s-"))) {
10929
- log16.info("cleaned up stale stream directories from previous run");
10933
+ log17.info("cleaned up stale stream directories from previous run");
10930
10934
  }
10931
10935
  } catch {
10932
10936
  }
@@ -10944,7 +10948,7 @@ var SessionStreamer = class {
10944
10948
  if (viewerKey) {
10945
10949
  this.active.get(sessionId)?.viewerIds.add(viewerKey);
10946
10950
  }
10947
- log16.info("cancelled pending stop (re-mounted)", { sessionId });
10951
+ log17.info("cancelled pending stop (re-mounted)", { sessionId });
10948
10952
  return true;
10949
10953
  }
10950
10954
  }
@@ -10955,7 +10959,7 @@ var SessionStreamer = class {
10955
10959
  return true;
10956
10960
  }
10957
10961
  if (this.active.size >= MAX_CONCURRENT_STREAMS) {
10958
- log16.warn("stream limit reached; rejecting", {
10962
+ log17.warn("stream limit reached; rejecting", {
10959
10963
  limit: MAX_CONCURRENT_STREAMS,
10960
10964
  sessionId
10961
10965
  });
@@ -10986,7 +10990,7 @@ var SessionStreamer = class {
10986
10990
  stream.ptyProc.write(data);
10987
10991
  } catch (error) {
10988
10992
  const message = error instanceof Error ? error.message : String(error);
10989
- log16.warn("failed to write input", { sessionId, error: message });
10993
+ log17.warn("failed to write input", { sessionId, error: message });
10990
10994
  }
10991
10995
  }
10992
10996
  /**
@@ -11000,7 +11004,7 @@ var SessionStreamer = class {
11000
11004
  } catch (error) {
11001
11005
  const message = error instanceof Error ? error.message : String(error);
11002
11006
  if (!message.includes("EBADF")) {
11003
- log16.warn("resize failed", { sessionId, error: message });
11007
+ log17.warn("resize failed", { sessionId, error: message });
11004
11008
  }
11005
11009
  }
11006
11010
  }
@@ -11026,7 +11030,7 @@ var SessionStreamer = class {
11026
11030
  this.active.delete(sessionId);
11027
11031
  this.disconnectBuffers.delete(sessionId);
11028
11032
  this.disconnectBufferBytes.delete(sessionId);
11029
- log16.info("stopped streaming", { sessionId });
11033
+ log17.info("stopped streaming", { sessionId });
11030
11034
  }, STOP_DEBOUNCE_MS);
11031
11035
  this.pendingStops.set(sessionId, timer);
11032
11036
  }
@@ -11051,7 +11055,7 @@ var SessionStreamer = class {
11051
11055
  this.pendingStops.clear();
11052
11056
  for (const [id, stream] of this.active) {
11053
11057
  this.cleanupStream(stream);
11054
- log16.info("stopped streaming", { sessionId: id });
11058
+ log17.info("stopped streaming", { sessionId: id });
11055
11059
  }
11056
11060
  this.active.clear();
11057
11061
  this.disconnectBuffers.clear();
@@ -11189,13 +11193,13 @@ var SessionStreamer = class {
11189
11193
  }
11190
11194
  stream.initializing = false;
11191
11195
  stream.initBuffer = [];
11192
- log16.info("resync capture", { sessionId });
11196
+ log17.info("resync capture", { sessionId });
11193
11197
  return true;
11194
11198
  } catch (error) {
11195
11199
  stream.initializing = false;
11196
11200
  stream.initBuffer = [];
11197
11201
  const message = error instanceof Error ? error.message : String(error);
11198
- log16.warn("failed to resync stream", { sessionId, error: message });
11202
+ log17.warn("failed to resync stream", { sessionId, error: message });
11199
11203
  return false;
11200
11204
  }
11201
11205
  }
@@ -11249,7 +11253,7 @@ var SessionStreamer = class {
11249
11253
  } catch (error) {
11250
11254
  this.cleanupStream(stream);
11251
11255
  const message = error instanceof Error ? error.message : String(error);
11252
- log16.warn("failed pipe-pane", { sessionId, error: message });
11256
+ log17.warn("failed pipe-pane", { sessionId, error: message });
11253
11257
  return false;
11254
11258
  }
11255
11259
  const catProc = (0, import_node_child_process2.spawn)("cat", [fifoPath], { env: cleanEnv, stdio: ["ignore", "pipe", "ignore"] });
@@ -11277,7 +11281,7 @@ var SessionStreamer = class {
11277
11281
  this.cleanupStream(stream);
11278
11282
  this.active.delete(sessionId);
11279
11283
  this.pendingStops.delete(sessionId);
11280
- log16.info("session stream ended", { sessionId });
11284
+ log17.info("session stream ended", { sessionId });
11281
11285
  this.onStreamStopped?.(sessionId);
11282
11286
  }
11283
11287
  });
@@ -11334,11 +11338,11 @@ var SessionStreamer = class {
11334
11338
  }
11335
11339
  stream.initializing = false;
11336
11340
  stream.initBuffer = [];
11337
- log16.info("started streaming (tmux)", { sessionId, pane: paneTarget });
11341
+ log17.info("started streaming (tmux)", { sessionId, pane: paneTarget });
11338
11342
  return true;
11339
11343
  } catch (error) {
11340
11344
  const message = error instanceof Error ? error.message : String(error);
11341
- log16.warn("failed to start stream", { sessionId, error: message });
11345
+ log17.warn("failed to start stream", { sessionId, error: message });
11342
11346
  return false;
11343
11347
  }
11344
11348
  }
@@ -11384,15 +11388,15 @@ var SessionStreamer = class {
11384
11388
  stream.stopped = true;
11385
11389
  this.active.delete(sessionId);
11386
11390
  this.pendingStops.delete(sessionId);
11387
- log16.info("session stream ended", { sessionId });
11391
+ log17.info("session stream ended", { sessionId });
11388
11392
  this.onStreamStopped?.(sessionId);
11389
11393
  }
11390
11394
  });
11391
- log16.info("started streaming (screen)", { sessionId, screen: sessionName });
11395
+ log17.info("started streaming (screen)", { sessionId, screen: sessionName });
11392
11396
  return true;
11393
11397
  } catch (error) {
11394
11398
  const message = error instanceof Error ? error.message : String(error);
11395
- log16.warn("failed to start screen stream", { sessionId, error: message });
11399
+ log17.warn("failed to start screen stream", { sessionId, error: message });
11396
11400
  return false;
11397
11401
  }
11398
11402
  }
@@ -11438,15 +11442,15 @@ var SessionStreamer = class {
11438
11442
  stream.stopped = true;
11439
11443
  this.active.delete(sessionId);
11440
11444
  this.pendingStops.delete(sessionId);
11441
- log16.info("session stream ended", { sessionId });
11445
+ log17.info("session stream ended", { sessionId });
11442
11446
  this.onStreamStopped?.(sessionId);
11443
11447
  }
11444
11448
  });
11445
- log16.info("started streaming (zellij)", { sessionId, zellij: sessionName });
11449
+ log17.info("started streaming (zellij)", { sessionId, zellij: sessionName });
11446
11450
  return true;
11447
11451
  } catch (error) {
11448
11452
  const message = error instanceof Error ? error.message : String(error);
11449
- log16.warn("failed to start zellij stream", { sessionId, error: message });
11453
+ log17.warn("failed to start zellij stream", { sessionId, error: message });
11450
11454
  return false;
11451
11455
  }
11452
11456
  }
@@ -11457,14 +11461,14 @@ var SessionStreamer = class {
11457
11461
  const pid = parseProcessPid2(sessionId);
11458
11462
  if (!pid) return false;
11459
11463
  if (!(0, import_node_fs.existsSync)(`/proc/${pid}`)) {
11460
- log16.warn("process does not exist (no /proc entry)", { pid });
11464
+ log17.warn("process does not exist (no /proc entry)", { pid });
11461
11465
  this.sendFn(sessionId, "\r\n[rAgent] Process is no longer running. It will be removed on next sync.\r\n");
11462
11466
  return false;
11463
11467
  }
11464
11468
  try {
11465
11469
  const stat = (0, import_node_fs.readFileSync)(`/proc/${pid}/stat`, "utf8");
11466
11470
  if (stat.includes(") Z")) {
11467
- log16.warn("process is a zombie", { pid });
11471
+ log17.warn("process is a zombie", { pid });
11468
11472
  this.sendFn(sessionId, "\r\n[rAgent] Process has exited (zombie). It will be removed on next sync.\r\n");
11469
11473
  return false;
11470
11474
  }
@@ -11538,14 +11542,14 @@ var SessionStreamer = class {
11538
11542
  stream.stopped = true;
11539
11543
  this.active.delete(sessionId);
11540
11544
  this.pendingStops.delete(sessionId);
11541
- log16.info("session stream ended", { sessionId });
11545
+ log17.info("session stream ended", { sessionId });
11542
11546
  this.onStreamStopped?.(sessionId);
11543
11547
  });
11544
- log16.info("started streaming (process trace)", { sessionId, pid });
11548
+ log17.info("started streaming (process trace)", { sessionId, pid });
11545
11549
  return true;
11546
11550
  } catch (error) {
11547
11551
  const message = error instanceof Error ? error.message : String(error);
11548
- log16.warn("failed to start process stream", { sessionId, error: message });
11552
+ log17.warn("failed to start process stream", { sessionId, error: message });
11549
11553
  return false;
11550
11554
  }
11551
11555
  }
@@ -11596,7 +11600,7 @@ var SessionStreamer = class {
11596
11600
 
11597
11601
  // src/crypto-channel.ts
11598
11602
  var import_node_crypto = require("crypto");
11599
- var log17 = createLogger("crypto-channel");
11603
+ var log18 = createLogger("crypto-channel");
11600
11604
  var AAD_BYTES = 4;
11601
11605
  function deriveAesKey(sessionKey) {
11602
11606
  return Buffer.from(sessionKey.slice(0, 64), "hex");
@@ -11638,7 +11642,7 @@ function decryptPayload(enc, iv, sessionKey, seq) {
11638
11642
  return decrypted.toString("utf-8");
11639
11643
  } catch (error) {
11640
11644
  const message = error instanceof Error ? error.message : String(error);
11641
- log17.warn("decrypt failed", { seq, encBytes: enc.length, error: message });
11645
+ log18.warn("decrypt failed", { seq, encBytes: enc.length, error: message });
11642
11646
  return null;
11643
11647
  }
11644
11648
  }
@@ -11672,7 +11676,7 @@ var SequenceTracker = class {
11672
11676
  // src/pty.ts
11673
11677
  var import_node_child_process3 = require("child_process");
11674
11678
  var pty2 = __toESM(require("node-pty"));
11675
- var log18 = createLogger("pty");
11679
+ var log19 = createLogger("pty");
11676
11680
  var MIN_TMUX_COLS = 20;
11677
11681
  var MAX_TMUX_COLS = 500;
11678
11682
  var MIN_TMUX_ROWS = 5;
@@ -11820,7 +11824,7 @@ async function sendInputToTmux(sessionId, data) {
11820
11824
  if (!target) return;
11821
11825
  if (!isValidTmuxSessionName(target)) {
11822
11826
  const sessionName = target.split(":")[0].split(".")[0];
11823
- log18.warn("invalid tmux session name", { sessionName });
11827
+ log19.warn("invalid tmux session name", { sessionName });
11824
11828
  return;
11825
11829
  }
11826
11830
  try {
@@ -11851,7 +11855,7 @@ async function sendInputToTmux(sessionId, data) {
11851
11855
  }
11852
11856
  } catch (error) {
11853
11857
  const message = error instanceof Error ? error.message : String(error);
11854
- log18.warn("failed to send input", { sessionId, error: message });
11858
+ log19.warn("failed to send input", { sessionId, error: message });
11855
11859
  }
11856
11860
  }
11857
11861
  async function resizeTmuxPaneBySessionId(sessionId, cols, rows) {
@@ -11860,7 +11864,7 @@ async function resizeTmuxPaneBySessionId(sessionId, cols, rows) {
11860
11864
  if (!target) return false;
11861
11865
  if (!isValidTmuxSessionName(target)) {
11862
11866
  const sessionName = target.split(":")[0].split(".")[0];
11863
- log18.warn("invalid tmux session name", { sessionName });
11867
+ log19.warn("invalid tmux session name", { sessionName });
11864
11868
  return false;
11865
11869
  }
11866
11870
  if (!Number.isFinite(cols) || !Number.isFinite(rows)) return false;
@@ -11874,7 +11878,7 @@ async function resizeTmuxPaneBySessionId(sessionId, cols, rows) {
11874
11878
  (err) => {
11875
11879
  if (err) {
11876
11880
  const message = err instanceof Error ? err.message : String(err);
11877
- log18.warn("failed to resize tmux pane", { sessionId, error: message });
11881
+ log19.warn("failed to resize tmux pane", { sessionId, error: message });
11878
11882
  resolve(false);
11879
11883
  return;
11880
11884
  }
@@ -11908,7 +11912,7 @@ async function stopAllDetachedTmuxSessions() {
11908
11912
  }
11909
11913
 
11910
11914
  // src/shell-manager.ts
11911
- var log19 = createLogger("shell");
11915
+ var log20 = createLogger("shell");
11912
11916
  var ShellManager = class {
11913
11917
  ptyProcess = null;
11914
11918
  suppressNextRespawn = false;
@@ -11949,7 +11953,7 @@ var ShellManager = class {
11949
11953
  } catch (error) {
11950
11954
  const message = error instanceof Error ? error.message : String(error);
11951
11955
  if (!message.includes("EBADF")) {
11952
- log19.warn("resize failed", { error: message });
11956
+ log20.warn("resize failed", { error: message });
11953
11957
  }
11954
11958
  }
11955
11959
  }
@@ -11965,7 +11969,7 @@ var ShellManager = class {
11965
11969
  return;
11966
11970
  }
11967
11971
  if (!this.shouldRun) return;
11968
- log19.warn("shell exited; restarting shell process");
11972
+ log20.warn("shell exited; restarting shell process");
11969
11973
  setTimeout(() => {
11970
11974
  if (this.shouldRun) this.spawnOrRespawn();
11971
11975
  }, 200);
@@ -12071,7 +12075,7 @@ var InventoryManager = class {
12071
12075
 
12072
12076
  // src/connection-manager.ts
12073
12077
  var import_ws3 = __toESM(require("ws"));
12074
- var log20 = createLogger("connection");
12078
+ var log21 = createLogger("connection");
12075
12079
  var OPPORTUNISTIC_INVENTORY_SYNC_MS = 1200;
12076
12080
  var MIN_INVENTORY_SYNC_GAP_MS = 1500;
12077
12081
  var ConnectionManager = class {
@@ -12103,7 +12107,7 @@ var ConnectionManager = class {
12103
12107
  tracker = new SequenceTracker();
12104
12108
  this.rxSeqByViewer.set(key, tracker);
12105
12109
  if (!isValid) {
12106
- 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 });
12107
12111
  }
12108
12112
  }
12109
12113
  return tracker;
@@ -12189,14 +12193,14 @@ var ConnectionManager = class {
12189
12193
  try {
12190
12194
  this.activeSocket.send(JSON.stringify({ type: "ping" }));
12191
12195
  } catch (err) {
12192
- log20.error("failed to send JSON ping", { error: err.message });
12196
+ log21.error("failed to send JSON ping", { error: err.message });
12193
12197
  }
12194
12198
  try {
12195
12199
  this.activeSocket.ping();
12196
12200
  } catch {
12197
12201
  }
12198
12202
  this.wsPongTimeout = setTimeout(() => {
12199
- log20.warn("no pong received within 10s; closing stale connection");
12203
+ log21.warn("no pong received within 10s; closing stale connection");
12200
12204
  try {
12201
12205
  this.activeSocket?.terminate();
12202
12206
  } catch {
@@ -12266,7 +12270,7 @@ var ConnectionManager = class {
12266
12270
  replayBufferedOutput(sendChunk) {
12267
12271
  const buffered = this.outputBuffer.drain();
12268
12272
  if (buffered.length > 0) {
12269
- log20.info("replaying buffered output chunks", {
12273
+ log21.info("replaying buffered output chunks", {
12270
12274
  chunks: buffered.length,
12271
12275
  bytes: buffered.reduce((sum, c) => sum + Buffer.byteLength(c, "utf8"), 0)
12272
12276
  });
@@ -12308,7 +12312,7 @@ var import_child_process6 = require("child_process");
12308
12312
  var fs5 = __toESM(require("fs"));
12309
12313
  var os8 = __toESM(require("os"));
12310
12314
  var path4 = __toESM(require("path"));
12311
- var log21 = createLogger("service");
12315
+ var log22 = createLogger("service");
12312
12316
  function assertConfiguredAgentToken() {
12313
12317
  const config = loadConfig();
12314
12318
  if (!config.agentToken) {
@@ -12374,7 +12378,7 @@ async function installSystemdService(opts = {}) {
12374
12378
  await runSystemctlUser(["restart", SERVICE_NAME]);
12375
12379
  }
12376
12380
  saveConfigPatch({ serviceBackend: "systemd" });
12377
- log21.info("installed systemd user service", { path: SERVICE_FILE });
12381
+ log22.info("installed systemd user service", { path: SERVICE_FILE });
12378
12382
  }
12379
12383
  function readFallbackPid() {
12380
12384
  try {
@@ -12413,7 +12417,7 @@ async function startPidfileService() {
12413
12417
  assertConfiguredAgentToken();
12414
12418
  const existingPid = readFallbackPid();
12415
12419
  if (existingPid && isProcessRunning(existingPid)) {
12416
- log21.info("service already running", { pid: existingPid });
12420
+ log22.info("service already running", { pid: existingPid });
12417
12421
  return;
12418
12422
  }
12419
12423
  ensureConfigDir();
@@ -12430,8 +12434,8 @@ async function startPidfileService() {
12430
12434
  fs5.writeFileSync(FALLBACK_PID_FILE, `${child.pid}
12431
12435
  `, "utf8");
12432
12436
  saveConfigPatch({ serviceBackend: "pidfile" });
12433
- log21.info("started fallback background service", { pid: child.pid });
12434
- 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 });
12435
12439
  }
12436
12440
  async function stopPidfileService() {
12437
12441
  const pid = readFallbackPid();
@@ -12440,7 +12444,7 @@ async function stopPidfileService() {
12440
12444
  fs5.unlinkSync(FALLBACK_PID_FILE);
12441
12445
  } catch {
12442
12446
  }
12443
- log21.info("service is not running");
12447
+ log22.info("service is not running");
12444
12448
  return;
12445
12449
  }
12446
12450
  process.kill(pid, "SIGTERM");
@@ -12455,7 +12459,7 @@ async function stopPidfileService() {
12455
12459
  fs5.unlinkSync(FALLBACK_PID_FILE);
12456
12460
  } catch {
12457
12461
  }
12458
- log21.info("stopped fallback background service", { pid });
12462
+ log22.info("stopped fallback background service", { pid });
12459
12463
  }
12460
12464
  async function ensureServiceInstalled(opts = {}) {
12461
12465
  const wantsSystemd = await canUseSystemdUser();
@@ -12467,7 +12471,7 @@ async function ensureServiceInstalled(opts = {}) {
12467
12471
  if (opts.start) {
12468
12472
  await startPidfileService();
12469
12473
  } else {
12470
- log21.info("systemd user manager unavailable; using fallback pidfile backend");
12474
+ log22.info("systemd user manager unavailable; using fallback pidfile backend");
12471
12475
  }
12472
12476
  return "pidfile";
12473
12477
  }
@@ -12475,7 +12479,7 @@ async function startService() {
12475
12479
  const backend = getConfiguredServiceBackend();
12476
12480
  if (backend === "systemd") {
12477
12481
  await runSystemctlUser(["start", SERVICE_NAME]);
12478
- log21.info("started service via systemd");
12482
+ log22.info("started service via systemd");
12479
12483
  return;
12480
12484
  }
12481
12485
  if (backend === "pidfile") {
@@ -12488,7 +12492,7 @@ async function stopService() {
12488
12492
  const backend = getConfiguredServiceBackend();
12489
12493
  if (backend === "systemd") {
12490
12494
  await runSystemctlUser(["stop", SERVICE_NAME]);
12491
- log21.info("stopped service via systemd");
12495
+ log22.info("stopped service via systemd");
12492
12496
  return;
12493
12497
  }
12494
12498
  await stopPidfileService();
@@ -12506,7 +12510,7 @@ function killStaleAgentProcesses() {
12506
12510
  try {
12507
12511
  process.kill(pid, 0);
12508
12512
  process.kill(pid, "SIGTERM");
12509
- log21.info("stopped stale agent process", { pid });
12513
+ log22.info("stopped stale agent process", { pid });
12510
12514
  } catch {
12511
12515
  }
12512
12516
  fs5.unlinkSync(pidPath);
@@ -12521,7 +12525,7 @@ async function restartService() {
12521
12525
  killStaleAgentProcesses();
12522
12526
  if (backend === "systemd") {
12523
12527
  await runSystemctlUser(["restart", SERVICE_NAME]);
12524
- log21.info("restarted service via systemd");
12528
+ log22.info("restarted service via systemd");
12525
12529
  return;
12526
12530
  }
12527
12531
  await stopPidfileService();
@@ -12537,17 +12541,17 @@ async function printServiceStatus() {
12537
12541
  if (status) {
12538
12542
  process.stdout.write(status);
12539
12543
  } else {
12540
- log21.info("systemd service is not installed or has no status");
12544
+ log22.info("systemd service is not installed or has no status");
12541
12545
  }
12542
12546
  return;
12543
12547
  }
12544
12548
  const pid = readFallbackPid();
12545
12549
  if (pid && isProcessRunning(pid)) {
12546
- log21.info("fallback service running", { pid });
12547
- log21.info("logs", { path: FALLBACK_LOG_FILE });
12550
+ log22.info("fallback service running", { pid });
12551
+ log22.info("logs", { path: FALLBACK_LOG_FILE });
12548
12552
  return;
12549
12553
  }
12550
- log21.info("service is not running");
12554
+ log22.info("service is not running");
12551
12555
  }
12552
12556
  async function printServiceLogs(opts) {
12553
12557
  const lines = Number.parseInt(String(opts.lines || 100), 10) || 100;
@@ -12573,7 +12577,7 @@ async function printServiceLogs(opts) {
12573
12577
  return;
12574
12578
  }
12575
12579
  if (!fs5.existsSync(FALLBACK_LOG_FILE)) {
12576
- log21.info("no log file found", { path: FALLBACK_LOG_FILE });
12580
+ log22.info("no log file found", { path: FALLBACK_LOG_FILE });
12577
12581
  return;
12578
12582
  }
12579
12583
  if (follow) {
@@ -12605,7 +12609,7 @@ async function uninstallService() {
12605
12609
  const config = loadConfig();
12606
12610
  delete config.serviceBackend;
12607
12611
  saveConfig(config);
12608
- log21.info("service uninstalled");
12612
+ log22.info("service uninstalled");
12609
12613
  }
12610
12614
  function requestStopSelfService() {
12611
12615
  const backend = getConfiguredServiceBackend();
@@ -12956,7 +12960,7 @@ async function installLatestCliFromNpm() {
12956
12960
  }
12957
12961
 
12958
12962
  // src/control-dispatcher.ts
12959
- var log22 = createLogger("control");
12963
+ var log23 = createLogger("control");
12960
12964
  var TMUX_RESYNC_DEBOUNCE_MS = 150;
12961
12965
  var TMUX_INPUT_COALESCE_MS = 4;
12962
12966
  function collectProcessTreePids(rootPid, visited = /* @__PURE__ */ new Set()) {
@@ -13028,7 +13032,7 @@ var ControlDispatcher = class {
13028
13032
  /** Arrow form so callers can pass it directly without `.bind(this)`. */
13029
13033
  emitNativeOps = (sessionId, ops, seq) => {
13030
13034
  if (!this.sendNativeOps) {
13031
- log22.warn("native-stream ops produced but no transport sink installed", {
13035
+ log23.warn("native-stream ops produced but no transport sink installed", {
13032
13036
  sessionId,
13033
13037
  opCount: ops.length
13034
13038
  });
@@ -13097,11 +13101,11 @@ var ControlDispatcher = class {
13097
13101
  if (!sessionKey) return true;
13098
13102
  const receivedHmac = payload.hmac;
13099
13103
  if (typeof receivedHmac !== "string") {
13100
- log22.warn("control message missing HMAC signature");
13104
+ log23.warn("control message missing HMAC signature");
13101
13105
  return false;
13102
13106
  }
13103
13107
  if (!/^[0-9a-f]{64}$/i.test(receivedHmac)) {
13104
- log22.warn("control message has malformed HMAC signature");
13108
+ log23.warn("control message has malformed HMAC signature");
13105
13109
  return false;
13106
13110
  }
13107
13111
  const { hmac: _, ...payloadWithoutHmac } = payload;
@@ -13129,7 +13133,7 @@ var ControlDispatcher = class {
13129
13133
  ]);
13130
13134
  if (dangerousActions.has(action) && this.connection.sessionKey && payload._verifiedEncrypted !== true) {
13131
13135
  if (!this.verifyMessageHmac(payload)) {
13132
- log22.warn("rejecting control action \u2014 HMAC verification failed", { action });
13136
+ log23.warn("rejecting control action \u2014 HMAC verification failed", { action });
13133
13137
  return;
13134
13138
  }
13135
13139
  }
@@ -13175,10 +13179,10 @@ var ControlDispatcher = class {
13175
13179
  this.transcriptWatcher?.disableMarkdown(sessionId);
13176
13180
  try {
13177
13181
  await stopTmuxPaneBySessionId(sessionId);
13178
- log22.info("closed remote session", { sessionId });
13182
+ log23.info("closed remote session", { sessionId });
13179
13183
  } catch (error) {
13180
13184
  const message = error instanceof Error ? error.message : String(error);
13181
- log22.warn("failed to close session", { sessionId, error: message });
13185
+ log23.warn("failed to close session", { sessionId, error: message });
13182
13186
  }
13183
13187
  await delay(300);
13184
13188
  await this.syncInventory(true);
@@ -13189,7 +13193,7 @@ var ControlDispatcher = class {
13189
13193
  {
13190
13194
  const pid = parseProcessPid2(sessionId);
13191
13195
  if (pid === null) {
13192
- log22.warn("kill-process: could not parse PID", { sessionId });
13196
+ log23.warn("kill-process: could not parse PID", { sessionId });
13193
13197
  return;
13194
13198
  }
13195
13199
  this.transcriptWatcher?.disableMarkdown(sessionId);
@@ -13205,11 +13209,11 @@ var ControlDispatcher = class {
13205
13209
  const code = error.code;
13206
13210
  if (code !== "ESRCH") {
13207
13211
  const message = error instanceof Error ? error.message : String(error);
13208
- log22.warn("failed to send SIGTERM", { pid: targetPid, error: message });
13212
+ log23.warn("failed to send SIGTERM", { pid: targetPid, error: message });
13209
13213
  }
13210
13214
  }
13211
13215
  }
13212
- log22.info("sent SIGTERM to processes", { signaled, sessionId });
13216
+ log23.info("sent SIGTERM to processes", { signaled, sessionId });
13213
13217
  await new Promise((resolve) => setTimeout(resolve, 1500));
13214
13218
  for (const targetPid of processTree) {
13215
13219
  if (!isProcessAlive(targetPid)) continue;
@@ -13219,13 +13223,13 @@ var ControlDispatcher = class {
13219
13223
  const code = error.code;
13220
13224
  if (code !== "ESRCH") {
13221
13225
  const message = error instanceof Error ? error.message : String(error);
13222
- log22.warn("failed to send SIGKILL", { pid: targetPid, error: message });
13226
+ log23.warn("failed to send SIGKILL", { pid: targetPid, error: message });
13223
13227
  }
13224
13228
  }
13225
13229
  }
13226
13230
  } catch (error) {
13227
13231
  const message = error instanceof Error ? error.message : String(error);
13228
- log22.warn("failed to kill session", { sessionId, error: message });
13232
+ log23.warn("failed to kill session", { sessionId, error: message });
13229
13233
  }
13230
13234
  await this.syncInventory(true);
13231
13235
  }
@@ -13240,7 +13244,7 @@ var ControlDispatcher = class {
13240
13244
  }
13241
13245
  }
13242
13246
  const killed = await stopAllDetachedTmuxSessions();
13243
- log22.info("killed detached tmux sessions", { count: killed });
13247
+ log23.info("killed detached tmux sessions", { count: killed });
13244
13248
  await delay(300);
13245
13249
  await this.syncInventory(true);
13246
13250
  return;
@@ -13280,18 +13284,18 @@ var ControlDispatcher = class {
13280
13284
  const fileName = typeof payload.fileName === "string" ? payload.fileName : "attachment";
13281
13285
  const contentBase64 = typeof payload.contentBase64 === "string" ? payload.contentBase64 : "";
13282
13286
  if (!contentBase64 || contentBase64.length > 8 * 1024 * 1024) {
13283
- log22.warn("rejecting attachment upload \u2014 invalid size", { sessionId, fileName });
13287
+ log23.warn("rejecting attachment upload \u2014 invalid size", { sessionId, fileName });
13284
13288
  return;
13285
13289
  }
13286
13290
  let content;
13287
13291
  try {
13288
13292
  content = Buffer.from(contentBase64, "base64");
13289
13293
  } catch {
13290
- log22.warn("rejecting attachment upload \u2014 invalid base64", { sessionId, fileName });
13294
+ log23.warn("rejecting attachment upload \u2014 invalid base64", { sessionId, fileName });
13291
13295
  return;
13292
13296
  }
13293
13297
  if (content.length === 0 || content.length > 6 * 1024 * 1024) {
13294
- log22.warn("rejecting attachment upload \u2014 decoded size out of bounds", {
13298
+ log23.warn("rejecting attachment upload \u2014 decoded size out of bounds", {
13295
13299
  sessionId,
13296
13300
  fileName,
13297
13301
  bytes: content.length
@@ -13302,7 +13306,7 @@ var ControlDispatcher = class {
13302
13306
  fs6.mkdirSync(uploadDir, { recursive: true, mode: 448 });
13303
13307
  const writtenPath = path5.join(uploadDir, `${Date.now()}-${safeAttachmentName(fileName)}`);
13304
13308
  fs6.writeFileSync(writtenPath, content, { mode: 384 });
13305
- log22.info("attachment uploaded", { sessionId, path: writtenPath, bytes: content.length });
13309
+ log23.info("attachment uploaded", { sessionId, path: writtenPath, bytes: content.length });
13306
13310
  this.handleInput(writtenPath, sessionId);
13307
13311
  }
13308
13312
  /** Handle input routing to the correct target. */
@@ -13365,7 +13369,7 @@ var ControlDispatcher = class {
13365
13369
  this.tmuxResizeState.delete(sessionId);
13366
13370
  }
13367
13371
  const message = error instanceof Error ? error.message : String(error);
13368
- log22.warn("tmux resize failed", { sessionId, error: message });
13372
+ log23.warn("tmux resize failed", { sessionId, error: message });
13369
13373
  });
13370
13374
  } else if (sessionId.startsWith("screen:") || sessionId.startsWith("zellij:")) {
13371
13375
  this.streamer.resize(sessionId, cols, rows);
@@ -13373,30 +13377,30 @@ var ControlDispatcher = class {
13373
13377
  }
13374
13378
  /** Update the installed connector package, then restart when a service backend exists. */
13375
13379
  async updateAgentFromNpm() {
13376
- log22.info("updating ragent CLI", { current: CURRENT_VERSION });
13380
+ log23.info("updating ragent CLI", { current: CURRENT_VERSION });
13377
13381
  try {
13378
13382
  await installLatestCliFromNpm();
13379
13383
  } catch (error) {
13380
13384
  const message = error instanceof Error ? error.message : String(error);
13381
- log22.error("failed to update ragent CLI", { error: message });
13385
+ log23.error("failed to update ragent CLI", { error: message });
13382
13386
  return;
13383
13387
  }
13384
13388
  const backend = getConfiguredServiceBackend();
13385
13389
  if (!backend) {
13386
- 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");
13387
13391
  return;
13388
13392
  }
13389
- log22.info("ragent CLI updated; restarting connector service", { backend });
13393
+ log23.info("ragent CLI updated; restarting connector service", { backend });
13390
13394
  requestRestartSelfService();
13391
13395
  }
13392
13396
  /** Handle provision request from dashboard. */
13393
13397
  async handleProvision(payload) {
13394
13398
  const provReq = validateProvisionRequest(payload);
13395
13399
  if (!provReq) {
13396
- log22.warn("rejecting provision request \u2014 malformed payload");
13400
+ log23.warn("rejecting provision request \u2014 malformed payload");
13397
13401
  return;
13398
13402
  }
13399
- log22.info("provision request", { name: provReq.manifest.name, provisionId: provReq.provisionId });
13403
+ log23.info("provision request", { name: provReq.manifest.name, provisionId: provReq.provisionId });
13400
13404
  const sendProgress = (progress) => {
13401
13405
  const ws = this.connection.activeSocket;
13402
13406
  if (ws && ws.readyState === import_ws4.default.OPEN && this.connection.activeGroups.registryGroup) {
@@ -13444,7 +13448,7 @@ var ControlDispatcher = class {
13444
13448
  status: "unavailable",
13445
13449
  reason: result.reason
13446
13450
  });
13447
- log22.info("could not enable markdown", { sessionId, reason: result.reason });
13451
+ log23.info("could not enable markdown", { sessionId, reason: result.reason });
13448
13452
  } else {
13449
13453
  this.sendMarkdownStatus({
13450
13454
  type: "markdown",
@@ -13478,24 +13482,24 @@ var ControlDispatcher = class {
13478
13482
  const sessionName = typeof payload?.sessionName === "string" && payload.sessionName.trim().length > 0 ? payload.sessionName.trim() : `agent-${Date.now().toString(36)}`;
13479
13483
  const cmd = typeof payload?.command === "string" && payload.command.trim().length > 0 ? payload.command.trim() : null;
13480
13484
  if (!cmd) {
13481
- log22.warn("start-agent: no command provided, ignoring");
13485
+ log23.warn("start-agent: no command provided, ignoring");
13482
13486
  return;
13483
13487
  }
13484
13488
  if (sessionName.length > 128 || !/^[a-zA-Z0-9_-]+$/.test(sessionName)) {
13485
- log22.warn("start-agent: invalid session name, ignoring");
13489
+ log23.warn("start-agent: invalid session name, ignoring");
13486
13490
  return;
13487
13491
  }
13488
13492
  const danger = detectDangerousCommand(cmd);
13489
13493
  if (danger) {
13490
13494
  if (!this._approvalEnforcer) {
13491
- log22.warn("start-agent: rejected dangerous command (no approval enforcer)", {
13495
+ log23.warn("start-agent: rejected dangerous command (no approval enforcer)", {
13492
13496
  category: danger.category,
13493
13497
  pattern: danger.pattern,
13494
13498
  command: cmd
13495
13499
  });
13496
13500
  return;
13497
13501
  }
13498
- log22.info("start-agent: dangerous command \u2014 awaiting approval", {
13502
+ log23.info("start-agent: dangerous command \u2014 awaiting approval", {
13499
13503
  category: danger.category,
13500
13504
  pattern: danger.pattern,
13501
13505
  sessionName
@@ -13506,28 +13510,28 @@ var ControlDispatcher = class {
13506
13510
  sessionName
13507
13511
  );
13508
13512
  if (response === null) {
13509
- 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", {
13510
13514
  category: danger.category,
13511
13515
  command: cmd
13512
13516
  });
13513
13517
  return;
13514
13518
  }
13515
13519
  if (response.type !== "approved") {
13516
- log22.warn("start-agent: dangerous command denied or timed out", {
13520
+ log23.warn("start-agent: dangerous command denied or timed out", {
13517
13521
  category: danger.category,
13518
13522
  sessionName,
13519
13523
  responseType: response.type
13520
13524
  });
13521
13525
  return;
13522
13526
  }
13523
- log22.info("start-agent: dangerous command approved", {
13527
+ log23.info("start-agent: dangerous command approved", {
13524
13528
  category: danger.category,
13525
13529
  sessionName
13526
13530
  });
13527
13531
  }
13528
13532
  const rawWorkingDir = typeof payload?.workingDir === "string" && payload.workingDir.trim().length > 0 ? payload.workingDir.trim() : void 0;
13529
13533
  if (rawWorkingDir !== void 0 && !isSafeWorkingDir(rawWorkingDir)) {
13530
- log22.warn("start-agent: rejected unsafe workingDir", { workingDir: rawWorkingDir });
13534
+ log23.warn("start-agent: rejected unsafe workingDir", { workingDir: rawWorkingDir });
13531
13535
  return;
13532
13536
  }
13533
13537
  const workingDir = rawWorkingDir;
@@ -13576,7 +13580,7 @@ var ControlDispatcher = class {
13576
13580
  }
13577
13581
  if (outcome) {
13578
13582
  if (outcome.ok) {
13579
- log22.info("start-agent: launched native-stream", {
13583
+ log23.info("start-agent: launched native-stream", {
13580
13584
  sessionId: outcome.sessionId,
13581
13585
  kind: outcome.kind,
13582
13586
  source: outcome.transcriptSource
@@ -13584,7 +13588,7 @@ var ControlDispatcher = class {
13584
13588
  await this.syncInventory(true);
13585
13589
  return;
13586
13590
  }
13587
- log22.info(
13591
+ log23.info(
13588
13592
  "start-agent: native-stream unavailable; falling through to tmux file-watch",
13589
13593
  { reason: outcome.reason, kind: outcome.kind }
13590
13594
  );
@@ -13604,11 +13608,11 @@ var ControlDispatcher = class {
13604
13608
  let tmuxLaunchOk = false;
13605
13609
  try {
13606
13610
  (0, import_child_process8.execFileSync)("tmux", tmuxArgs, { stdio: "ignore" });
13607
- log22.info("started agent session", { sessionName, command: cmd });
13611
+ log23.info("started agent session", { sessionName, command: cmd });
13608
13612
  tmuxLaunchOk = true;
13609
13613
  } catch (error) {
13610
13614
  const message = error instanceof Error ? error.message : String(error);
13611
- log22.error("failed to start agent session", { sessionName, error: message });
13615
+ log23.error("failed to start agent session", { sessionName, error: message });
13612
13616
  }
13613
13617
  if (tmuxLaunchOk && pendingFallbackOutcome && pendingFallbackOutcome.userMessage) {
13614
13618
  const tmuxSessionId = this.discoverNewlyCreatedPaneId(sessionName);
@@ -13647,7 +13651,7 @@ var ControlDispatcher = class {
13647
13651
  return `tmux:${sessionName}:${info}`;
13648
13652
  }
13649
13653
  } catch (err) {
13650
- log22.warn("display-message failed; status block target may not bind", {
13654
+ log23.warn("display-message failed; status block target may not bind", {
13651
13655
  sessionName,
13652
13656
  err: err instanceof Error ? err.message : String(err)
13653
13657
  });
@@ -13915,7 +13919,7 @@ function isGrantExpired(grant) {
13915
13919
  }
13916
13920
 
13917
13921
  // src/approval-enforcer.ts
13918
- var log23 = createLogger("approval");
13922
+ var log24 = createLogger("approval");
13919
13923
  var ApprovalEnforcer = class {
13920
13924
  policy;
13921
13925
  secret;
@@ -13939,7 +13943,7 @@ var ApprovalEnforcer = class {
13939
13943
  async checkCommand(command, hostId, sessionId) {
13940
13944
  const request = matchPolicy(command, this.policy, hostId, sessionId);
13941
13945
  if (!request) return null;
13942
- log23.info("approval pending", {
13946
+ log24.info("approval pending", {
13943
13947
  action: request.action,
13944
13948
  severity: request.severity,
13945
13949
  requestId: request.requestId
@@ -13948,7 +13952,7 @@ var ApprovalEnforcer = class {
13948
13952
  const timer = setTimeout(() => {
13949
13953
  this.pendingRequests.delete(request.requestId);
13950
13954
  const response = { type: "timeout" };
13951
- log23.info("approval timeout", {
13955
+ log24.info("approval timeout", {
13952
13956
  action: request.action,
13953
13957
  severity: request.severity,
13954
13958
  requestId: request.requestId
@@ -13970,7 +13974,7 @@ var ApprovalEnforcer = class {
13970
13974
  * {@link handleResponse}.
13971
13975
  */
13972
13976
  async requestApproval(request) {
13973
- log23.info("approval pending (direct)", {
13977
+ log24.info("approval pending (direct)", {
13974
13978
  action: request.action,
13975
13979
  severity: request.severity,
13976
13980
  requestId: request.requestId
@@ -13979,7 +13983,7 @@ var ApprovalEnforcer = class {
13979
13983
  const timer = setTimeout(() => {
13980
13984
  this.pendingRequests.delete(request.requestId);
13981
13985
  const response = { type: "timeout" };
13982
- log23.info("approval timeout (direct)", {
13986
+ log24.info("approval timeout (direct)", {
13983
13987
  action: request.action,
13984
13988
  severity: request.severity,
13985
13989
  requestId: request.requestId
@@ -13999,7 +14003,7 @@ var ApprovalEnforcer = class {
13999
14003
  if (!requestId) return;
14000
14004
  const pending = this.pendingRequests.get(requestId);
14001
14005
  if (!pending) {
14002
- log23.warn("received response for unknown approval request", { requestId });
14006
+ log24.warn("received response for unknown approval request", { requestId });
14003
14007
  return;
14004
14008
  }
14005
14009
  if (response.type === "approved") {
@@ -14008,7 +14012,7 @@ var ApprovalEnforcer = class {
14008
14012
  pending.request
14009
14013
  );
14010
14014
  if (bindingMismatch) {
14011
- log23.info("approval rejected (grant binding mismatch)", {
14015
+ log24.info("approval rejected (grant binding mismatch)", {
14012
14016
  action: pending.request.action,
14013
14017
  severity: pending.request.severity,
14014
14018
  requestId,
@@ -14028,7 +14032,7 @@ var ApprovalEnforcer = class {
14028
14032
  return;
14029
14033
  }
14030
14034
  if (!this.acceptGrant(response.grant)) {
14031
- log23.info("approval rejected (invalid grant)", {
14035
+ log24.info("approval rejected (invalid grant)", {
14032
14036
  action: pending.request.action,
14033
14037
  severity: pending.request.severity,
14034
14038
  requestId
@@ -14038,13 +14042,13 @@ var ApprovalEnforcer = class {
14038
14042
  pending.resolve({ type: "denied", denial: { requestId, deniedBy: "system", deniedAt: (/* @__PURE__ */ new Date()).toISOString(), reason: "Invalid or expired grant" } });
14039
14043
  return;
14040
14044
  }
14041
- log23.info("approval approved", {
14045
+ log24.info("approval approved", {
14042
14046
  action: pending.request.action,
14043
14047
  severity: pending.request.severity,
14044
14048
  requestId
14045
14049
  });
14046
14050
  } else if (response.type === "denied") {
14047
- log23.info("approval denied", {
14051
+ log24.info("approval denied", {
14048
14052
  action: pending.request.action,
14049
14053
  severity: pending.request.severity,
14050
14054
  requestId,
@@ -14085,7 +14089,7 @@ var ApprovalEnforcer = class {
14085
14089
  for (const [id, entry] of this.pendingRequests) {
14086
14090
  clearTimeout(entry.timer);
14087
14091
  this.pendingRequests.delete(id);
14088
- log23.info("approval stopped", {
14092
+ log24.info("approval stopped", {
14089
14093
  action: entry.request.action,
14090
14094
  severity: entry.request.severity,
14091
14095
  requestId: id
@@ -14121,7 +14125,7 @@ var ApprovalEnforcer = class {
14121
14125
  if (entry.request.sessionId !== sessionId) continue;
14122
14126
  clearTimeout(entry.timer);
14123
14127
  this.pendingRequests.delete(id);
14124
- log23.info("approval cancelled (session torn down)", {
14128
+ log24.info("approval cancelled (session torn down)", {
14125
14129
  action: entry.request.action,
14126
14130
  severity: entry.request.severity,
14127
14131
  requestId: id,
@@ -14176,7 +14180,7 @@ var ApprovalEnforcer = class {
14176
14180
  };
14177
14181
 
14178
14182
  // src/agent.ts
14179
- var log24 = createLogger("agent");
14183
+ var log25 = createLogger("agent");
14180
14184
  var MAX_TRANSPORT_CHUNK_BYTES = 24 * 1024;
14181
14185
  function pidFilePath(hostId) {
14182
14186
  return path6.join(CONFIG_DIR, `agent-${hostId}.pid`);
@@ -14261,15 +14265,15 @@ async function runAgent(rawOptions) {
14261
14265
  const config = loadConfig();
14262
14266
  if (config.redaction?.enabled === false || rawOptions.redact === false) {
14263
14267
  setRedactionEnabled(false);
14264
- log24.info("secret redaction disabled");
14268
+ log25.info("secret redaction disabled");
14265
14269
  }
14266
- log24.info("connector started", { hostName: options.hostName, hostId: options.hostId });
14267
- log24.info("portal", { portal: options.portal });
14270
+ log25.info("connector started", { hostName: options.hostName, hostId: options.hostId });
14271
+ log25.info("portal", { portal: options.portal });
14268
14272
  try {
14269
14273
  const existingSessions = await collectSessionInventory(options.hostId, options.command);
14270
14274
  const tmuxCount = existingSessions.filter((s) => s.type === "tmux").length;
14271
14275
  if (tmuxCount > 0) {
14272
- log24.info("found existing tmux sessions", { count: tmuxCount });
14276
+ log25.info("found existing tmux sessions", { count: tmuxCount });
14273
14277
  }
14274
14278
  } catch {
14275
14279
  }
@@ -14503,7 +14507,7 @@ async function runAgent(rawOptions) {
14503
14507
  dispatcher.setApprovalEnforcer(null);
14504
14508
  }
14505
14509
  ws.on("open", async () => {
14506
- log24.info("connector connected to relay");
14510
+ log25.info("connector connected to relay");
14507
14511
  conn.resetReconnectDelay();
14508
14512
  ws.send(JSON.stringify({ type: "joinGroup", group: groups.privateGroup }));
14509
14513
  ws.send(JSON.stringify({ type: "joinGroup", group: groups.registryGroup }));
@@ -14571,9 +14575,9 @@ async function runAgent(rawOptions) {
14571
14575
  const inSeq = typeof payload.seq === "number" ? payload.seq : null;
14572
14576
  const rxSeq = conn.getRxSeqForViewer(payload.viewerId);
14573
14577
  if (inSeq === null) {
14574
- log24.warn("rejecting encrypted input frame without seq (#310)");
14578
+ log25.warn("rejecting encrypted input frame without seq (#310)");
14575
14579
  } else if (!rxSeq.accept(inSeq)) {
14576
- log24.warn("rejecting replayed/out-of-order input", {
14580
+ log25.warn("rejecting replayed/out-of-order input", {
14577
14581
  seq: inSeq,
14578
14582
  lastSeen: rxSeq.lastSeq,
14579
14583
  viewerId: typeof payload.viewerId === "string" ? payload.viewerId : "_legacy"
@@ -14586,13 +14590,13 @@ async function runAgent(rawOptions) {
14586
14590
  inSeq
14587
14591
  );
14588
14592
  if (inputData === null) {
14589
- log24.warn("failed to decrypt input \u2014 ignoring");
14593
+ log25.warn("failed to decrypt input \u2014 ignoring");
14590
14594
  }
14591
14595
  }
14592
14596
  } else if (typeof payload.data === "string" && !conn.sessionKey) {
14593
14597
  inputData = payload.data;
14594
14598
  } else if (conn.sessionKey) {
14595
- log24.warn("rejecting plaintext input frame while encrypted channel is active");
14599
+ log25.warn("rejecting plaintext input frame while encrypted channel is active");
14596
14600
  }
14597
14601
  if (inputData !== null) {
14598
14602
  const sid = typeof payload.sessionId === "string" ? payload.sessionId.trim() : "";
@@ -14600,7 +14604,7 @@ async function runAgent(rawOptions) {
14600
14604
  }
14601
14605
  } else if (payload.type === "resize" && Number.isInteger(payload.cols) && Number.isInteger(payload.rows)) {
14602
14606
  if (conn.sessionKey && !dispatcher.verifyMessageHmac(payload)) {
14603
- log24.warn("rejecting resize frame \u2014 HMAC verification failed");
14607
+ log25.warn("rejecting resize frame \u2014 HMAC verification failed");
14604
14608
  return;
14605
14609
  }
14606
14610
  const sid = typeof payload.sessionId === "string" ? payload.sessionId.trim() : "";
@@ -14612,11 +14616,11 @@ async function runAgent(rawOptions) {
14612
14616
  const inSeq = typeof payload.seq === "number" ? payload.seq : null;
14613
14617
  const rxSeq = conn.getRxSeqForViewer(payload.viewerId);
14614
14618
  if (inSeq === null) {
14615
- log24.warn("rejecting encrypted control frame without seq");
14619
+ log25.warn("rejecting encrypted control frame without seq");
14616
14620
  return;
14617
14621
  }
14618
14622
  if (!rxSeq.accept(inSeq)) {
14619
- log24.warn("rejecting replayed/out-of-order control", {
14623
+ log25.warn("rejecting replayed/out-of-order control", {
14620
14624
  seq: inSeq,
14621
14625
  lastSeen: rxSeq.lastSeq,
14622
14626
  viewerId: typeof payload.viewerId === "string" ? payload.viewerId : "_legacy"
@@ -14630,7 +14634,7 @@ async function runAgent(rawOptions) {
14630
14634
  inSeq
14631
14635
  );
14632
14636
  if (decrypted === null) {
14633
- log24.warn("failed to decrypt control \u2014 ignoring");
14637
+ log25.warn("failed to decrypt control \u2014 ignoring");
14634
14638
  return;
14635
14639
  }
14636
14640
  try {
@@ -14639,11 +14643,11 @@ async function runAgent(rawOptions) {
14639
14643
  _verifiedEncrypted: true
14640
14644
  };
14641
14645
  } catch {
14642
- log24.warn("failed to parse encrypted control payload");
14646
+ log25.warn("failed to parse encrypted control payload");
14643
14647
  return;
14644
14648
  }
14645
14649
  } else if (conn.sessionKey && payload.action === "upload-file") {
14646
- log24.warn("rejecting plaintext attachment upload while encrypted channel is active");
14650
+ log25.warn("rejecting plaintext attachment upload while encrypted channel is active");
14647
14651
  return;
14648
14652
  }
14649
14653
  await dispatcher.handleControlAction(controlPayload);
@@ -14663,13 +14667,13 @@ async function runAgent(rawOptions) {
14663
14667
  }
14664
14668
  });
14665
14669
  ws.on("error", (error) => {
14666
- log24.error("websocket error", { error: error.message });
14670
+ log25.error("websocket error", { error: error.message });
14667
14671
  });
14668
14672
  ws.on("close", (code, reason) => {
14669
14673
  const fields = {};
14670
14674
  if (code) fields.code = code;
14671
14675
  if (reason.length > 0) fields.reason = reason.toString();
14672
- log24.info("relay disconnected; output will be buffered until reconnect", fields);
14676
+ log25.info("relay disconnected; output will be buffered until reconnect", fields);
14673
14677
  conn.cleanup();
14674
14678
  resolve();
14675
14679
  });
@@ -14686,35 +14690,35 @@ async function runAgent(rawOptions) {
14686
14690
  });
14687
14691
  inventory.updateOptions(options);
14688
14692
  dispatcher.updateOptions(options);
14689
- log24.info("recovered from auth failure via machine credential; reconnecting");
14693
+ log25.info("recovered from auth failure via machine credential; reconnecting");
14690
14694
  continue;
14691
14695
  } catch (mcError) {
14692
14696
  if (mcError instanceof AuthError) {
14693
- log24.error("auth recovery failed", { error: mcError.message });
14697
+ log25.error("auth recovery failed", { error: mcError.message });
14694
14698
  } else {
14695
14699
  const mcMsg = mcError instanceof Error ? mcError.message : String(mcError);
14696
- log24.error("machine credential recovery failed", { error: mcMsg });
14700
+ log25.error("machine credential recovery failed", { error: mcMsg });
14697
14701
  }
14698
14702
  }
14699
14703
  }
14700
- log24.error("auth error", { error: error.message });
14701
- log24.error(
14704
+ log25.error("auth error", { error: error.message });
14705
+ log25.error(
14702
14706
  "connector token is invalid or revoked. Stopping. Re-connect with: ragent connect --token <token>"
14703
14707
  );
14704
14708
  dispatcher.shouldRun = false;
14705
14709
  break;
14706
14710
  }
14707
14711
  const message = error instanceof Error ? error.message : String(error);
14708
- log24.error("relay connect failed", { error: message });
14712
+ log25.error("relay connect failed", { error: message });
14709
14713
  }
14710
14714
  if (!dispatcher.shouldRun) break;
14711
14715
  if (dispatcher.reconnectRequested) {
14712
- log24.info("reconnecting to relay");
14716
+ log25.info("reconnecting to relay");
14713
14717
  await wait(300);
14714
14718
  continue;
14715
14719
  }
14716
14720
  const jitteredDelay = conn.reconnectDelay * (0.5 + Math.random());
14717
- log24.info("disconnected; reconnecting", { seconds: Math.round(jitteredDelay / 1e3) });
14721
+ log25.info("disconnected; reconnecting", { seconds: Math.round(jitteredDelay / 1e3) });
14718
14722
  await wait(jitteredDelay);
14719
14723
  conn.reconnectDelay = Math.min(conn.reconnectDelay * 1.5, MAX_RECONNECT_DELAY_MS);
14720
14724
  }
@@ -14814,7 +14818,7 @@ function printCommandArt(title, subtitle = "remote agent control") {
14814
14818
  }
14815
14819
 
14816
14820
  // src/commands/connect.ts
14817
- var log25 = createLogger("connect");
14821
+ var log26 = createLogger("connect");
14818
14822
  async function connectMachine(opts) {
14819
14823
  const portal = opts.portal || DEFAULT_PORTAL;
14820
14824
  const hostId = sanitizeHostId(opts.id || inferHostId());
@@ -14846,12 +14850,12 @@ async function connectMachine(opts) {
14846
14850
  nextConfig.refreshExpiresAt = claimed.refreshExpiresAt;
14847
14851
  }
14848
14852
  saveConfig(nextConfig);
14849
- log25.info("machine connected", { hostName, hostId });
14850
- log25.info("machine name (override with --name <friendly-name>)", { hostName });
14851
- 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 });
14852
14856
  if (opts.asService) {
14853
14857
  await ensureServiceInstalled({ enable: true, start: true });
14854
- log25.info("service mode enabled");
14858
+ log26.info("service mode enabled");
14855
14859
  return;
14856
14860
  }
14857
14861
  if (opts.run !== false) {
@@ -14871,14 +14875,14 @@ function registerConnectCommand(program2) {
14871
14875
  await connectMachine(opts);
14872
14876
  } catch (error) {
14873
14877
  const message = error instanceof Error ? error.message : String(error);
14874
- log25.error("connect failed", { error: message });
14878
+ log26.error("connect failed", { error: message });
14875
14879
  process.exit(1);
14876
14880
  }
14877
14881
  });
14878
14882
  }
14879
14883
 
14880
14884
  // src/commands/run.ts
14881
- var log26 = createLogger("run");
14885
+ var log27 = createLogger("run");
14882
14886
  function registerRunCommand(program2) {
14883
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) => {
14884
14888
  try {
@@ -14886,7 +14890,7 @@ function registerRunCommand(program2) {
14886
14890
  await runAgent(opts);
14887
14891
  } catch (error) {
14888
14892
  const message = error instanceof Error ? error.message : String(error);
14889
- log26.error("run failed", { error: message });
14893
+ log27.error("run failed", { error: message });
14890
14894
  process.exit(1);
14891
14895
  }
14892
14896
  });
@@ -14894,7 +14898,7 @@ function registerRunCommand(program2) {
14894
14898
 
14895
14899
  // src/commands/doctor.ts
14896
14900
  var os12 = __toESM(require("os"));
14897
- var log27 = createLogger("doctor");
14901
+ var log28 = createLogger("doctor");
14898
14902
  async function runDoctor(opts) {
14899
14903
  const options = resolveRunOptions(opts);
14900
14904
  const checks = [];
@@ -14930,27 +14934,27 @@ async function runDoctor(opts) {
14930
14934
  console.log(`${check.ok ? "PASS" : "FAIL"} ${check.name}: ${check.detail}`);
14931
14935
  });
14932
14936
  if (!platformOk) {
14933
- log27.info("Linux is required for the connector");
14937
+ log28.info("Linux is required for the connector");
14934
14938
  }
14935
14939
  if (!tmuxOk) {
14936
14940
  const recipe = await chooseTmuxInstallCommand();
14937
14941
  if (recipe) {
14938
- log27.info("tmux install suggestion", { command: recipe.command });
14942
+ log28.info("tmux install suggestion", { command: recipe.command });
14939
14943
  }
14940
14944
  if (opts.fix) {
14941
14945
  try {
14942
14946
  const installed = await installTmuxInteractively();
14943
14947
  if (installed) {
14944
- log27.info("tmux installation complete");
14948
+ log28.info("tmux installation complete");
14945
14949
  } else {
14946
- log27.info("tmux installation skipped or incomplete");
14950
+ log28.info("tmux installation skipped or incomplete");
14947
14951
  }
14948
14952
  } catch (error) {
14949
14953
  const message = error instanceof Error ? error.message : String(error);
14950
- log27.error("failed to install tmux", { error: message });
14954
+ log28.error("failed to install tmux", { error: message });
14951
14955
  }
14952
14956
  } else {
14953
- log27.info("run `ragent doctor --fix` to install missing dependencies interactively");
14957
+ log28.info("run `ragent doctor --fix` to install missing dependencies interactively");
14954
14958
  }
14955
14959
  }
14956
14960
  }
@@ -14962,30 +14966,30 @@ function registerDoctorCommand(program2) {
14962
14966
  }
14963
14967
 
14964
14968
  // src/commands/update.ts
14965
- var log28 = createLogger("update");
14969
+ var log29 = createLogger("update");
14966
14970
  function registerUpdateCommand(program2) {
14967
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) => {
14968
14972
  printCommandArt("Update", "checking npm registry for newer ragent-cli versions");
14969
14973
  const latestVersion = await checkForUpdate({ force: true });
14970
14974
  if (!latestVersion) {
14971
- log28.info("you are up to date", { version: CURRENT_VERSION });
14975
+ log29.info("you are up to date", { version: CURRENT_VERSION });
14972
14976
  return;
14973
14977
  }
14974
- log28.info("update available", { current: CURRENT_VERSION, latest: latestVersion });
14978
+ log29.info("update available", { current: CURRENT_VERSION, latest: latestVersion });
14975
14979
  if (opts.check) return;
14976
14980
  await installLatestCliFromNpm();
14977
- log28.info("updated", { version: latestVersion });
14981
+ log29.info("updated", { version: latestVersion });
14978
14982
  const backend = getConfiguredServiceBackend();
14979
14983
  if (backend && opts.restart) {
14980
- log28.info("restarting service", { backend });
14984
+ log29.info("restarting service", { backend });
14981
14985
  try {
14982
14986
  await restartService();
14983
14987
  } catch (err) {
14984
- log28.error("failed to restart service", { error: err instanceof Error ? err.message : String(err) });
14985
- 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");
14986
14990
  }
14987
14991
  } else if (!backend) {
14988
- 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");
14989
14993
  }
14990
14994
  });
14991
14995
  }
@@ -15009,7 +15013,7 @@ function registerSessionsCommand(program2) {
15009
15013
  }
15010
15014
 
15011
15015
  // src/commands/service.ts
15012
- var log29 = createLogger("service-cmd");
15016
+ var log30 = createLogger("service-cmd");
15013
15017
  function registerServiceCommand(program2) {
15014
15018
  const service = program2.command("service").description("Manage background connector service");
15015
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) => {
@@ -15020,7 +15024,7 @@ function registerServiceCommand(program2) {
15020
15024
  });
15021
15025
  } catch (error) {
15022
15026
  const message = error instanceof Error ? error.message : String(error);
15023
- log29.error("service install failed", { error: message });
15027
+ log30.error("service install failed", { error: message });
15024
15028
  process.exit(1);
15025
15029
  }
15026
15030
  });
@@ -15029,7 +15033,7 @@ function registerServiceCommand(program2) {
15029
15033
  await startService();
15030
15034
  } catch (error) {
15031
15035
  const message = error instanceof Error ? error.message : String(error);
15032
- log29.error("service start failed", { error: message });
15036
+ log30.error("service start failed", { error: message });
15033
15037
  process.exit(1);
15034
15038
  }
15035
15039
  });
@@ -15038,7 +15042,7 @@ function registerServiceCommand(program2) {
15038
15042
  await stopService();
15039
15043
  } catch (error) {
15040
15044
  const message = error instanceof Error ? error.message : String(error);
15041
- log29.error("service stop failed", { error: message });
15045
+ log30.error("service stop failed", { error: message });
15042
15046
  process.exit(1);
15043
15047
  }
15044
15048
  });
@@ -15047,7 +15051,7 @@ function registerServiceCommand(program2) {
15047
15051
  await restartService();
15048
15052
  } catch (error) {
15049
15053
  const message = error instanceof Error ? error.message : String(error);
15050
- log29.error("service restart failed", { error: message });
15054
+ log30.error("service restart failed", { error: message });
15051
15055
  process.exit(1);
15052
15056
  }
15053
15057
  });
@@ -15056,7 +15060,7 @@ function registerServiceCommand(program2) {
15056
15060
  await printServiceStatus();
15057
15061
  } catch (error) {
15058
15062
  const message = error instanceof Error ? error.message : String(error);
15059
- log29.error("service status failed", { error: message });
15063
+ log30.error("service status failed", { error: message });
15060
15064
  process.exit(1);
15061
15065
  }
15062
15066
  });
@@ -15065,7 +15069,7 @@ function registerServiceCommand(program2) {
15065
15069
  await printServiceLogs(opts);
15066
15070
  } catch (error) {
15067
15071
  const message = error instanceof Error ? error.message : String(error);
15068
- log29.error("service logs failed", { error: message });
15072
+ log30.error("service logs failed", { error: message });
15069
15073
  process.exit(1);
15070
15074
  }
15071
15075
  });
@@ -15074,7 +15078,7 @@ function registerServiceCommand(program2) {
15074
15078
  await uninstallService();
15075
15079
  } catch (error) {
15076
15080
  const message = error instanceof Error ? error.message : String(error);
15077
- log29.error("service uninstall failed", { error: message });
15081
+ log30.error("service uninstall failed", { error: message });
15078
15082
  process.exit(1);
15079
15083
  }
15080
15084
  });
@@ -15082,7 +15086,7 @@ function registerServiceCommand(program2) {
15082
15086
 
15083
15087
  // src/commands/uninstall.ts
15084
15088
  var fs8 = __toESM(require("fs"));
15085
- var log30 = createLogger("uninstall");
15089
+ var log31 = createLogger("uninstall");
15086
15090
  async function uninstallAgent(opts) {
15087
15091
  const config = loadConfig();
15088
15092
  const hostName = config.hostName || config.hostId || "this machine";
@@ -15092,12 +15096,12 @@ async function uninstallAgent(opts) {
15092
15096
  false
15093
15097
  );
15094
15098
  if (!confirmed) {
15095
- log30.info("uninstall cancelled");
15099
+ log31.info("uninstall cancelled");
15096
15100
  return;
15097
15101
  }
15098
15102
  }
15099
15103
  if (config.portal && config.agentToken) {
15100
- log30.info("deregistering from server");
15104
+ log31.info("deregistering from server");
15101
15105
  try {
15102
15106
  const token = await refreshTokenIfNeeded({
15103
15107
  portal: config.portal,
@@ -15105,24 +15109,24 @@ async function uninstallAgent(opts) {
15105
15109
  });
15106
15110
  const ok = await deregisterHost({ portal: config.portal, agentToken: token });
15107
15111
  if (ok) {
15108
- log30.info("host removed from server");
15112
+ log31.info("host removed from server");
15109
15113
  }
15110
15114
  } catch {
15111
- 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");
15112
15116
  }
15113
15117
  }
15114
- log30.info("stopping and removing service");
15118
+ log31.info("stopping and removing service");
15115
15119
  await uninstallService().catch(() => void 0);
15116
15120
  if (fs8.existsSync(CONFIG_DIR)) {
15117
15121
  fs8.rmSync(CONFIG_DIR, { recursive: true, force: true });
15118
- log30.info("removed config directory", { path: CONFIG_DIR });
15122
+ log31.info("removed config directory", { path: CONFIG_DIR });
15119
15123
  }
15120
15124
  try {
15121
15125
  await execAsync(`npm unlink -g ${PACKAGE_NAME}`, { timeout: 15e3 });
15122
- log30.info("unlinked global package", { package: PACKAGE_NAME });
15126
+ log31.info("unlinked global package", { package: PACKAGE_NAME });
15123
15127
  } catch {
15124
15128
  }
15125
- log30.info("uninstall complete. rAgent has been removed from this machine");
15129
+ log31.info("uninstall complete. rAgent has been removed from this machine");
15126
15130
  }
15127
15131
  function registerUninstallCommand(parent) {
15128
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) => {
@@ -15131,7 +15135,7 @@ function registerUninstallCommand(parent) {
15131
15135
  await uninstallAgent(opts);
15132
15136
  } catch (error) {
15133
15137
  const message = error instanceof Error ? error.message : String(error);
15134
- log30.error("uninstall failed", { error: message });
15138
+ log31.error("uninstall failed", { error: message });
15135
15139
  process.exit(1);
15136
15140
  }
15137
15141
  });
@@ -15190,10 +15194,10 @@ function registerDiscoverCommand(program2) {
15190
15194
  }
15191
15195
 
15192
15196
  // src/index.ts
15193
- var log31 = createLogger("cli");
15197
+ var log32 = createLogger("cli");
15194
15198
  process.on("unhandledRejection", (reason) => {
15195
15199
  const message = reason instanceof Error ? reason.stack || reason.message : String(reason);
15196
- log31.error("unhandled promise rejection", { error: message });
15200
+ log32.error("unhandled promise rejection", { error: message });
15197
15201
  });
15198
15202
  import_commander.program.name("ragent").description("Connect machines to rAgent Live").version(CURRENT_VERSION);
15199
15203
  registerConnectCommand(import_commander.program);