ragent-cli 1.7.3 → 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 +80 -11
  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.3",
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",
@@ -950,7 +950,7 @@ var SECRET_PATTERNS = [
950
950
  /eyJ[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}/g
951
951
  // JWT
952
952
  ];
953
- var redactionEnabled = false;
953
+ var redactionEnabled = true;
954
954
  function setRedactionEnabled(enabled) {
955
955
  redactionEnabled = enabled;
956
956
  }
@@ -1045,6 +1045,7 @@ var import_node_os = require("os");
1045
1045
  var import_node_string_decoder = require("string_decoder");
1046
1046
  var pty = __toESM(require("node-pty"));
1047
1047
  var STOP_DEBOUNCE_MS = 2e3;
1048
+ var MAX_CONCURRENT_STREAMS = 20;
1048
1049
  var MAX_SESSION_BUFFER_BYTES = 64 * 1024;
1049
1050
  function parsePaneTarget(sessionId) {
1050
1051
  if (!sessionId.startsWith("tmux:")) return null;
@@ -1151,6 +1152,12 @@ var SessionStreamer = class {
1151
1152
  if (this.active.has(sessionId)) {
1152
1153
  return true;
1153
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
+ }
1154
1161
  if (sessionId.startsWith("tmux:")) {
1155
1162
  return this.startTmuxStream(sessionId);
1156
1163
  }
@@ -2702,6 +2709,10 @@ var ControlDispatcher = class {
2702
2709
  console.warn("[rAgent] Control message missing HMAC signature.");
2703
2710
  return false;
2704
2711
  }
2712
+ if (!/^[0-9a-f]{64}$/i.test(receivedHmac)) {
2713
+ console.warn("[rAgent] Control message has malformed HMAC signature.");
2714
+ return false;
2715
+ }
2705
2716
  const { hmac: _, ...payloadWithoutHmac } = payload;
2706
2717
  const canonical = JSON.stringify(payloadWithoutHmac, Object.keys(payloadWithoutHmac).sort());
2707
2718
  const expected = crypto2.createHmac("sha256", sessionKey).update(canonical).digest("hex");
@@ -2718,7 +2729,9 @@ var ControlDispatcher = class {
2718
2729
  "stop-session",
2719
2730
  "stop-detached",
2720
2731
  "disconnect",
2721
- "kill-process"
2732
+ "kill-process",
2733
+ "start-agent",
2734
+ "provision"
2722
2735
  ]);
2723
2736
  if (dangerousActions.has(action) && this.connection.sessionKey) {
2724
2737
  if (!this.verifyMessageHmac(payload)) {
@@ -2798,6 +2811,9 @@ var ControlDispatcher = class {
2798
2811
  case "start-agent":
2799
2812
  await this.handleStartAgent(payload);
2800
2813
  return;
2814
+ case "provision":
2815
+ await this.handleProvision(payload);
2816
+ return;
2801
2817
  case "stream-session":
2802
2818
  this.handleStreamSession(sessionId);
2803
2819
  return;
@@ -2837,8 +2853,11 @@ var ControlDispatcher = class {
2837
2853
  }
2838
2854
  /** Handle provision request from dashboard. */
2839
2855
  async handleProvision(payload) {
2840
- const provReq = payload;
2841
- 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
+ }
2842
2861
  console.log(`[rAgent] Provision request: ${provReq.manifest.name} (${provReq.provisionId})`);
2843
2862
  const sendProgress = (progress) => {
2844
2863
  const ws = this.connection.activeSocket;
@@ -2980,6 +2999,56 @@ var ControlDispatcher = class {
2980
2999
  }
2981
3000
  }
2982
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
+ }
2983
3052
 
2984
3053
  // src/transcript-watcher.ts
2985
3054
  var fs3 = __toESM(require("fs"));
@@ -3576,9 +3645,9 @@ async function runAgent(rawOptions) {
3576
3645
  }
3577
3646
  const lockPath = acquirePidLock(options.hostId);
3578
3647
  const config = loadConfig();
3579
- if (config.redaction?.enabled) {
3580
- setRedactionEnabled(true);
3581
- 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.");
3582
3651
  }
3583
3652
  console.log(`[rAgent] Connector started for ${options.hostName} (${options.hostId})`);
3584
3653
  console.log(`[rAgent] Portal: ${options.portal}`);
@@ -3763,7 +3832,7 @@ async function runAgent(rawOptions) {
3763
3832
  } else if (payload.type === "start-agent") {
3764
3833
  await dispatcher.handleControlAction({ ...payload, action: "start-agent" });
3765
3834
  } else if (payload.type === "provision") {
3766
- await dispatcher.handleProvision(payload);
3835
+ await dispatcher.handleControlAction({ ...payload, action: "provision" });
3767
3836
  }
3768
3837
  }
3769
3838
  if (msg.type === "message" && msg.group === groups.registryGroup) {
@@ -3985,7 +4054,7 @@ function registerConnectCommand(program2) {
3985
4054
 
3986
4055
  // src/commands/run.ts
3987
4056
  function registerRunCommand(program2) {
3988
- 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) => {
3989
4058
  try {
3990
4059
  printCommandArt("Run Connector", "streaming terminal session to portal");
3991
4060
  await runAgent(opts);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ragent-cli",
3
- "version": "1.7.3",
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",