ragent-cli 1.7.2 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +92 -15
  2. package/package.json +2 -2
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.7.2",
34
+ version: "1.8.0",
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: {
@@ -89,7 +89,7 @@ var require_package = __commonJS({
89
89
  "@changesets/cli": "^2.29.8",
90
90
  "@eslint/js": "^10.0.1",
91
91
  "@types/figlet": "^1.7.0",
92
- "@types/node": "^25.3.0",
92
+ "@types/node": "^20.17.0",
93
93
  "@types/ws": "^8.5.13",
94
94
  eslint: "^10.0.2",
95
95
  tsup: "^8.4.0",
@@ -609,13 +609,21 @@ function detectAgentType(command) {
609
609
  const cmd = command.toLowerCase();
610
610
  const parts = cmd.split(/\s+/);
611
611
  const binary = parts[0]?.split("/").pop() ?? "";
612
- const rawScriptArg = binary === "node" && parts[1] ? parts[1].split("/").pop() ?? "" : "";
612
+ let rawScriptArg = "";
613
+ if (binary === "node") {
614
+ for (let i = 1; i < parts.length; i++) {
615
+ if (!parts[i].startsWith("-")) {
616
+ rawScriptArg = parts[i].split("/").pop() ?? "";
617
+ break;
618
+ }
619
+ }
620
+ }
613
621
  const scriptArg = rawScriptArg.replace(/\.m?js$/, "");
614
622
  if (binary === "claude" || binary === "claude-code" || scriptArg === "cli" && cmd.includes("claude-code")) {
615
623
  if (cmd.includes("--chrome-native-host")) return void 0;
616
624
  return "Claude Code";
617
625
  }
618
- if (binary === "codex" || scriptArg === "codex" && cmd.includes("@openai/codex") || cmd.includes("codex-cli")) return "Codex CLI";
626
+ if (binary === "codex" || scriptArg === "codex" || cmd.includes("codex-cli")) return "Codex CLI";
619
627
  if (binary === "aider") return "aider";
620
628
  if (binary === "cursor") {
621
629
  if (isElectronProcess(cmd)) return void 0;
@@ -625,9 +633,9 @@ function detectAgentType(command) {
625
633
  if (isElectronProcess(cmd)) return void 0;
626
634
  return "Windsurf";
627
635
  }
628
- if (binary === "gemini" || scriptArg === "gemini" && cmd.includes("gemini-cli")) return "Gemini CLI";
636
+ if (binary === "gemini" || scriptArg === "gemini") return "Gemini CLI";
629
637
  if (binary === "amazon-q" || binary === "amazon_q") return "Amazon Q";
630
- if (binary === "copilot" || scriptArg === "copilot" && cmd.includes("@github/copilot")) return "Copilot CLI";
638
+ if (binary === "copilot" || scriptArg === "copilot") return "Copilot CLI";
631
639
  return void 0;
632
640
  }
633
641
  function sessionInventoryFingerprint(sessions) {
@@ -942,7 +950,7 @@ var SECRET_PATTERNS = [
942
950
  /eyJ[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}/g
943
951
  // JWT
944
952
  ];
945
- var redactionEnabled = false;
953
+ var redactionEnabled = true;
946
954
  function setRedactionEnabled(enabled) {
947
955
  redactionEnabled = enabled;
948
956
  }
@@ -1037,6 +1045,7 @@ var import_node_os = require("os");
1037
1045
  var import_node_string_decoder = require("string_decoder");
1038
1046
  var pty = __toESM(require("node-pty"));
1039
1047
  var STOP_DEBOUNCE_MS = 2e3;
1048
+ var MAX_CONCURRENT_STREAMS = 20;
1040
1049
  var MAX_SESSION_BUFFER_BYTES = 64 * 1024;
1041
1050
  function parsePaneTarget(sessionId) {
1042
1051
  if (!sessionId.startsWith("tmux:")) return null;
@@ -1143,6 +1152,12 @@ var SessionStreamer = class {
1143
1152
  if (this.active.has(sessionId)) {
1144
1153
  return true;
1145
1154
  }
1155
+ if (this.active.size >= MAX_CONCURRENT_STREAMS) {
1156
+ console.warn(
1157
+ `[rAgent] Stream limit reached (${MAX_CONCURRENT_STREAMS}). Rejecting: ${sessionId}`
1158
+ );
1159
+ return false;
1160
+ }
1146
1161
  if (sessionId.startsWith("tmux:")) {
1147
1162
  return this.startTmuxStream(sessionId);
1148
1163
  }
@@ -2694,6 +2709,10 @@ var ControlDispatcher = class {
2694
2709
  console.warn("[rAgent] Control message missing HMAC signature.");
2695
2710
  return false;
2696
2711
  }
2712
+ if (!/^[0-9a-f]{64}$/i.test(receivedHmac)) {
2713
+ console.warn("[rAgent] Control message has malformed HMAC signature.");
2714
+ return false;
2715
+ }
2697
2716
  const { hmac: _, ...payloadWithoutHmac } = payload;
2698
2717
  const canonical = JSON.stringify(payloadWithoutHmac, Object.keys(payloadWithoutHmac).sort());
2699
2718
  const expected = crypto2.createHmac("sha256", sessionKey).update(canonical).digest("hex");
@@ -2710,7 +2729,9 @@ var ControlDispatcher = class {
2710
2729
  "stop-session",
2711
2730
  "stop-detached",
2712
2731
  "disconnect",
2713
- "kill-process"
2732
+ "kill-process",
2733
+ "start-agent",
2734
+ "provision"
2714
2735
  ]);
2715
2736
  if (dangerousActions.has(action) && this.connection.sessionKey) {
2716
2737
  if (!this.verifyMessageHmac(payload)) {
@@ -2790,6 +2811,9 @@ var ControlDispatcher = class {
2790
2811
  case "start-agent":
2791
2812
  await this.handleStartAgent(payload);
2792
2813
  return;
2814
+ case "provision":
2815
+ await this.handleProvision(payload);
2816
+ return;
2793
2817
  case "stream-session":
2794
2818
  this.handleStreamSession(sessionId);
2795
2819
  return;
@@ -2829,8 +2853,11 @@ var ControlDispatcher = class {
2829
2853
  }
2830
2854
  /** Handle provision request from dashboard. */
2831
2855
  async handleProvision(payload) {
2832
- const provReq = payload;
2833
- if (!provReq.provisionId || !provReq.manifest) return;
2856
+ const provReq = validateProvisionRequest(payload);
2857
+ if (!provReq) {
2858
+ console.warn("[rAgent] Rejecting provision request \u2014 malformed payload.");
2859
+ return;
2860
+ }
2834
2861
  console.log(`[rAgent] Provision request: ${provReq.manifest.name} (${provReq.provisionId})`);
2835
2862
  const sendProgress = (progress) => {
2836
2863
  const ws = this.connection.activeSocket;
@@ -2972,6 +2999,56 @@ var ControlDispatcher = class {
2972
2999
  }
2973
3000
  }
2974
3001
  };
3002
+ var VALID_INSTALL_METHODS = /* @__PURE__ */ new Set(["npm", "pip", "binary", "custom"]);
3003
+ var VALID_RUNTIMES = /* @__PURE__ */ new Set(["node", "python", "none"]);
3004
+ function validateProvisionRequest(payload) {
3005
+ if (typeof payload.provisionId !== "string" || !payload.provisionId) return null;
3006
+ if (typeof payload.sessionName !== "string" || !payload.sessionName) return null;
3007
+ if (typeof payload.command !== "string" || !payload.command) return null;
3008
+ const manifest = payload.manifest;
3009
+ if (!manifest || typeof manifest !== "object" || Array.isArray(manifest)) return null;
3010
+ const m = manifest;
3011
+ if (typeof m.id !== "string" || !m.id) return null;
3012
+ if (typeof m.name !== "string" || !m.name) return null;
3013
+ if (typeof m.installMethod !== "string" || !VALID_INSTALL_METHODS.has(m.installMethod)) return null;
3014
+ if (typeof m.installCommand !== "string") return null;
3015
+ if (typeof m.checkCommand !== "string") return null;
3016
+ let prerequisites;
3017
+ if (m.prerequisites !== void 0 && m.prerequisites !== null) {
3018
+ if (typeof m.prerequisites !== "object" || Array.isArray(m.prerequisites)) return null;
3019
+ const p = m.prerequisites;
3020
+ if (typeof p.runtime !== "string" || !VALID_RUNTIMES.has(p.runtime)) return null;
3021
+ prerequisites = {
3022
+ runtime: p.runtime,
3023
+ minVersion: typeof p.minVersion === "string" ? p.minVersion : void 0
3024
+ };
3025
+ }
3026
+ if (payload.workingDir !== void 0 && typeof payload.workingDir !== "string") return null;
3027
+ if (payload.envVars !== void 0 && (typeof payload.envVars !== "object" || payload.envVars === null || Array.isArray(payload.envVars))) return null;
3028
+ let validatedEnvVars;
3029
+ if (payload.envVars && typeof payload.envVars === "object") {
3030
+ const entries = Object.entries(payload.envVars);
3031
+ for (const [, v] of entries) {
3032
+ if (typeof v !== "string") return null;
3033
+ }
3034
+ validatedEnvVars = payload.envVars;
3035
+ }
3036
+ return {
3037
+ provisionId: payload.provisionId,
3038
+ sessionName: payload.sessionName,
3039
+ command: payload.command,
3040
+ workingDir: typeof payload.workingDir === "string" ? payload.workingDir : void 0,
3041
+ envVars: validatedEnvVars,
3042
+ manifest: {
3043
+ id: m.id,
3044
+ name: m.name,
3045
+ installMethod: m.installMethod,
3046
+ installCommand: m.installCommand,
3047
+ checkCommand: m.checkCommand,
3048
+ prerequisites
3049
+ }
3050
+ };
3051
+ }
2975
3052
 
2976
3053
  // src/transcript-watcher.ts
2977
3054
  var fs3 = __toESM(require("fs"));
@@ -3568,9 +3645,9 @@ async function runAgent(rawOptions) {
3568
3645
  }
3569
3646
  const lockPath = acquirePidLock(options.hostId);
3570
3647
  const config = loadConfig();
3571
- if (config.redaction?.enabled) {
3572
- setRedactionEnabled(true);
3573
- console.log("[rAgent] Secret redaction enabled.");
3648
+ if (config.redaction?.enabled === false || rawOptions.redact === false) {
3649
+ setRedactionEnabled(false);
3650
+ console.log("[rAgent] Secret redaction disabled.");
3574
3651
  }
3575
3652
  console.log(`[rAgent] Connector started for ${options.hostName} (${options.hostId})`);
3576
3653
  console.log(`[rAgent] Portal: ${options.portal}`);
@@ -3755,7 +3832,7 @@ async function runAgent(rawOptions) {
3755
3832
  } else if (payload.type === "start-agent") {
3756
3833
  await dispatcher.handleControlAction({ ...payload, action: "start-agent" });
3757
3834
  } else if (payload.type === "provision") {
3758
- await dispatcher.handleProvision(payload);
3835
+ await dispatcher.handleControlAction({ ...payload, action: "provision" });
3759
3836
  }
3760
3837
  }
3761
3838
  if (msg.type === "message" && msg.group === groups.registryGroup) {
@@ -3977,7 +4054,7 @@ function registerConnectCommand(program2) {
3977
4054
 
3978
4055
  // src/commands/run.ts
3979
4056
  function registerRunCommand(program2) {
3980
- 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").action(async (opts) => {
4057
+ 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) => {
3981
4058
  try {
3982
4059
  printCommandArt("Run Connector", "streaming terminal session to portal");
3983
4060
  await runAgent(opts);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ragent-cli",
3
- "version": "1.7.2",
3
+ "version": "1.8.0",
4
4
  "description": "CLI agent for rAgent Live — browser-first terminal control plane for AI coding agents",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -58,7 +58,7 @@
58
58
  "@changesets/cli": "^2.29.8",
59
59
  "@eslint/js": "^10.0.1",
60
60
  "@types/figlet": "^1.7.0",
61
- "@types/node": "^25.3.0",
61
+ "@types/node": "^20.17.0",
62
62
  "@types/ws": "^8.5.13",
63
63
  "eslint": "^10.0.2",
64
64
  "tsup": "^8.4.0",