agent-relay 2.1.27-beta.0 → 2.1.27-beta.2

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.
@@ -3648,7 +3648,14 @@ program
3648
3648
  return s;
3649
3649
  return `'${s.replace(/'/g, `'\"'\"'`)}'`;
3650
3650
  };
3651
- const remoteCommandFallback = [providerConfig.command, ...providerConfig.args].map(shellEscape).join(' ');
3651
+ // Build the fallback command to run on the remote workspace.
3652
+ // For Cursor, the installer creates both "agent" (primary) and "cursor-agent" (legacy)
3653
+ // symlinks. Try the primary first, fall back to legacy if not found.
3654
+ const primaryCmd = [providerConfig.command, ...providerConfig.args].map(shellEscape).join(' ');
3655
+ const fallbackCmd = provider === 'cursor'
3656
+ ? `command -v agent >/dev/null 2>&1 && ${primaryCmd} || cursor-agent ${providerConfig.args.map(shellEscape).join(' ')}`
3657
+ : primaryCmd;
3658
+ const remoteCommandFallback = fallbackCmd;
3652
3659
  // When --token is provided (from dashboard CLI command), skip cloud config requirement.
3653
3660
  // The token authenticates directly with the /start endpoint.
3654
3661
  const cliToken = options.token;
@@ -3856,6 +3863,18 @@ program
3856
3863
  }
3857
3864
  stdin.resume();
3858
3865
  const onStdinData = (data) => {
3866
+ // Escape (0x1b) or Ctrl+C (0x03) after auth success → close session
3867
+ if (authDetected && (data[0] === 0x1b || data[0] === 0x03)) {
3868
+ cleanup();
3869
+ clearTimeout(timer);
3870
+ try {
3871
+ stream.close();
3872
+ }
3873
+ catch {
3874
+ // ignore
3875
+ }
3876
+ return;
3877
+ }
3859
3878
  stream.write(data);
3860
3879
  };
3861
3880
  stdin.on('data', onStdinData);
@@ -3870,28 +3889,26 @@ program
3870
3889
  }
3871
3890
  stdin.pause();
3872
3891
  };
3873
- // Auto-close the session when auth success is detected
3892
+ // Notify user when auth success is detected
3874
3893
  const closeOnAuthSuccess = () => {
3875
3894
  authDetected = true;
3876
- // Brief delay so the user sees the success message
3877
- setTimeout(() => {
3878
- cleanup();
3879
- clearTimeout(timer);
3880
- try {
3881
- stream.close();
3882
- }
3883
- catch {
3884
- // ignore
3885
- }
3886
- }, 1500);
3895
+ // Don't try to auto-navigate post-login prompts (trust directory,
3896
+ // bypass permissions, etc.) they vary by CLI version and are fragile
3897
+ // to automate. Just tell the user they're done.
3898
+ stdout.write('\n');
3899
+ stdout.write(green(' ✓ Authentication successful!') + '\n');
3900
+ stdout.write(dim(' Press Escape or Ctrl+C to exit.') + '\n');
3901
+ stdout.write('\n');
3887
3902
  };
3888
3903
  stream.on('data', (data) => {
3889
3904
  stdout.write(data);
3890
- // Accumulate output for pattern matching (keep last 2KB to avoid memory growth)
3905
+ // Accumulate output for pattern matching (keep last 8KB to avoid memory growth)
3906
+ // Ink-based CLIs use heavy ANSI escape codes, so raw output is much
3907
+ // larger than visible text. 8KB ensures success patterns aren't truncated.
3891
3908
  const text = data.toString();
3892
3909
  outputBuffer += text;
3893
- if (outputBuffer.length > 2048) {
3894
- outputBuffer = outputBuffer.slice(-2048);
3910
+ if (outputBuffer.length > 8192) {
3911
+ outputBuffer = outputBuffer.slice(-8192);
3895
3912
  }
3896
3913
  // Check for auth success patterns
3897
3914
  if (!authDetected && successPatterns.length > 0) {
@@ -3972,13 +3989,20 @@ program
3972
3989
  ? start.provider.trim()
3973
3990
  : provider;
3974
3991
  try {
3992
+ const completeHeaders = { 'Content-Type': 'application/json' };
3993
+ if (!cliToken && cloudConfig.apiKey) {
3994
+ completeHeaders['Authorization'] = `Bearer ${cloudConfig.apiKey}`;
3995
+ }
3975
3996
  const response = await fetch(`${CLOUD_URL}/api/auth/ssh/complete`, {
3976
3997
  method: 'POST',
3977
- headers: {
3978
- 'Authorization': `Bearer ${cloudConfig.apiKey}`,
3979
- 'Content-Type': 'application/json',
3980
- },
3981
- body: JSON.stringify({ sessionId: start.sessionId, workspaceId: start.workspaceId, provider: providerForComplete, success }),
3998
+ headers: completeHeaders,
3999
+ body: JSON.stringify({
4000
+ sessionId: start.sessionId,
4001
+ workspaceId: start.workspaceId,
4002
+ provider: providerForComplete,
4003
+ success,
4004
+ ...(cliToken && { token: cliToken }),
4005
+ }),
3982
4006
  });
3983
4007
  if (!response.ok) {
3984
4008
  let details = response.statusText;
@@ -4008,6 +4032,12 @@ program
4008
4032
  console.log('');
4009
4033
  console.log(red(`Remote auth command exited with code ${exitCode}.`));
4010
4034
  }
4035
+ // Exit code 127 = command not found
4036
+ if (execResult?.exitCode === 127) {
4037
+ console.log('');
4038
+ console.log(yellow(`The ${providerConfig.displayName} CLI ("${providerConfig.command}") is not installed on this workspace.`));
4039
+ console.log(dim('Ask your workspace administrator to install it, or check the workspace Dockerfile.'));
4040
+ }
4011
4041
  process.exit(1);
4012
4042
  }
4013
4043
  console.log('');