agent-relay 2.0.18 → 2.0.20

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 (165) hide show
  1. package/bin/relay-pty-darwin-arm64 +0 -0
  2. package/bin/relay-pty-darwin-x64 +0 -0
  3. package/bin/relay-pty-linux-x64 +0 -0
  4. package/dist/dashboard/out/404.html +1 -1
  5. package/dist/dashboard/out/_next/static/chunks/320-a6304232cd0ee2ce.js +1 -0
  6. package/dist/dashboard/out/_next/static/chunks/631-16b905e5920f9b59.js +1 -0
  7. package/dist/dashboard/out/_next/static/chunks/app/providers/page-ecb16ffd3b36262b.js +1 -0
  8. package/dist/dashboard/out/_next/static/css/{45361ce86b2847c4.css → 6892f8422896ef7a.css} +1 -1
  9. package/dist/dashboard/out/app/onboarding.html +1 -1
  10. package/dist/dashboard/out/app/onboarding.txt +1 -1
  11. package/dist/dashboard/out/app.html +1 -1
  12. package/dist/dashboard/out/app.txt +2 -2
  13. package/dist/dashboard/out/cloud/link.html +1 -1
  14. package/dist/dashboard/out/cloud/link.txt +1 -1
  15. package/dist/dashboard/out/complete-profile.html +2 -2
  16. package/dist/dashboard/out/complete-profile.txt +1 -1
  17. package/dist/dashboard/out/connect-repos.html +1 -1
  18. package/dist/dashboard/out/connect-repos.txt +1 -1
  19. package/dist/dashboard/out/history.html +1 -1
  20. package/dist/dashboard/out/history.txt +1 -1
  21. package/dist/dashboard/out/index.html +1 -1
  22. package/dist/dashboard/out/index.txt +2 -2
  23. package/dist/dashboard/out/login.html +2 -2
  24. package/dist/dashboard/out/login.txt +1 -1
  25. package/dist/dashboard/out/metrics.html +1 -1
  26. package/dist/dashboard/out/metrics.txt +1 -1
  27. package/dist/dashboard/out/pricing.html +2 -2
  28. package/dist/dashboard/out/pricing.txt +1 -1
  29. package/dist/dashboard/out/providers/setup/claude.html +1 -1
  30. package/dist/dashboard/out/providers/setup/claude.txt +1 -1
  31. package/dist/dashboard/out/providers/setup/codex.html +1 -1
  32. package/dist/dashboard/out/providers/setup/codex.txt +1 -1
  33. package/dist/dashboard/out/providers/setup/cursor.html +1 -1
  34. package/dist/dashboard/out/providers/setup/cursor.txt +1 -1
  35. package/dist/dashboard/out/providers.html +1 -1
  36. package/dist/dashboard/out/providers.txt +2 -2
  37. package/dist/dashboard/out/signup.html +2 -2
  38. package/dist/dashboard/out/signup.txt +1 -1
  39. package/package.json +23 -17
  40. package/packages/api-types/package.json +2 -2
  41. package/packages/bridge/dist/spawner.d.ts +2 -0
  42. package/packages/bridge/dist/spawner.js +75 -23
  43. package/packages/bridge/package.json +8 -8
  44. package/packages/cli-tester/README.md +277 -0
  45. package/packages/cli-tester/dist/index.d.ts +21 -0
  46. package/packages/cli-tester/dist/index.js +21 -0
  47. package/packages/cli-tester/dist/utils/credential-check.d.ts +56 -0
  48. package/packages/cli-tester/dist/utils/credential-check.js +230 -0
  49. package/packages/cli-tester/dist/utils/socket-client.d.ts +76 -0
  50. package/packages/cli-tester/dist/utils/socket-client.js +153 -0
  51. package/packages/cli-tester/docker/entrypoint.sh +58 -0
  52. package/packages/cli-tester/package.json +32 -0
  53. package/packages/cli-tester/scripts/clear-auth.sh +101 -0
  54. package/packages/cli-tester/scripts/inject-message.sh +42 -0
  55. package/packages/cli-tester/scripts/start.sh +71 -0
  56. package/packages/cli-tester/scripts/test-cli.sh +56 -0
  57. package/packages/cli-tester/scripts/test-full-spawn.sh +238 -0
  58. package/packages/cli-tester/scripts/test-registration.sh +182 -0
  59. package/packages/cli-tester/scripts/test-setup-flow.sh +202 -0
  60. package/packages/cli-tester/scripts/test-spawn.sh +140 -0
  61. package/packages/cli-tester/scripts/test-with-daemon.sh +247 -0
  62. package/packages/cli-tester/scripts/verify-auth.sh +112 -0
  63. package/packages/cloud/dist/api/cli-pty-runner.js +9 -6
  64. package/packages/cloud/package.json +6 -6
  65. package/packages/config/dist/cli-auth-config.js +75 -0
  66. package/packages/config/package.json +2 -2
  67. package/packages/continuity/package.json +1 -1
  68. package/packages/daemon/dist/cli-auth.js +5 -1
  69. package/packages/daemon/dist/router.js +4 -4
  70. package/packages/daemon/dist/server.js +38 -19
  71. package/packages/daemon/dist/spawn-manager.d.ts +4 -0
  72. package/packages/daemon/dist/spawn-manager.js +2 -0
  73. package/packages/daemon/package.json +12 -12
  74. package/packages/dashboard/dist/server.js +4 -0
  75. package/packages/dashboard/package.json +14 -14
  76. package/packages/dashboard/ui/app/providers/page.tsx +2 -2
  77. package/packages/dashboard/ui/react-components/ProviderConnectionList.tsx +23 -8
  78. package/packages/dashboard/ui/react-components/SpawnModal.tsx +16 -6
  79. package/packages/dashboard/ui/react-components/settings/WorkspaceSettingsPanel.tsx +22 -6
  80. package/packages/dashboard/ui-dist/404.html +1 -1
  81. package/packages/dashboard/ui-dist/_next/static/chunks/320-a6304232cd0ee2ce.js +1 -0
  82. package/packages/dashboard/ui-dist/_next/static/chunks/631-16b905e5920f9b59.js +1 -0
  83. package/packages/dashboard/ui-dist/_next/static/chunks/app/providers/page-ecb16ffd3b36262b.js +1 -0
  84. package/packages/dashboard/ui-dist/_next/static/css/{45361ce86b2847c4.css → 6892f8422896ef7a.css} +1 -1
  85. package/packages/dashboard/ui-dist/app/onboarding.html +1 -1
  86. package/packages/dashboard/ui-dist/app/onboarding.txt +1 -1
  87. package/packages/dashboard/ui-dist/app.html +1 -1
  88. package/packages/dashboard/ui-dist/app.txt +2 -2
  89. package/packages/dashboard/ui-dist/cloud/link.html +1 -1
  90. package/packages/dashboard/ui-dist/cloud/link.txt +1 -1
  91. package/packages/dashboard/ui-dist/complete-profile.html +2 -2
  92. package/packages/dashboard/ui-dist/complete-profile.txt +1 -1
  93. package/packages/dashboard/ui-dist/connect-repos.html +1 -1
  94. package/packages/dashboard/ui-dist/connect-repos.txt +1 -1
  95. package/packages/dashboard/ui-dist/history.html +1 -1
  96. package/packages/dashboard/ui-dist/history.txt +1 -1
  97. package/packages/dashboard/ui-dist/index.html +1 -1
  98. package/packages/dashboard/ui-dist/index.txt +2 -2
  99. package/packages/dashboard/ui-dist/login.html +2 -2
  100. package/packages/dashboard/ui-dist/login.txt +1 -1
  101. package/packages/dashboard/ui-dist/metrics.html +1 -1
  102. package/packages/dashboard/ui-dist/metrics.txt +1 -1
  103. package/packages/dashboard/ui-dist/pricing.html +2 -2
  104. package/packages/dashboard/ui-dist/pricing.txt +1 -1
  105. package/packages/dashboard/ui-dist/providers/setup/claude.html +1 -1
  106. package/packages/dashboard/ui-dist/providers/setup/claude.txt +1 -1
  107. package/packages/dashboard/ui-dist/providers/setup/codex.html +1 -1
  108. package/packages/dashboard/ui-dist/providers/setup/codex.txt +1 -1
  109. package/packages/dashboard/ui-dist/providers/setup/cursor.html +1 -1
  110. package/packages/dashboard/ui-dist/providers/setup/cursor.txt +1 -1
  111. package/packages/dashboard/ui-dist/providers.html +1 -1
  112. package/packages/dashboard/ui-dist/providers.txt +2 -2
  113. package/packages/dashboard/ui-dist/signup.html +2 -2
  114. package/packages/dashboard/ui-dist/signup.txt +1 -1
  115. package/packages/dashboard-server/dist/server.js +4 -0
  116. package/packages/dashboard-server/package.json +12 -12
  117. package/packages/hooks/package.json +4 -4
  118. package/packages/mcp/package.json +2 -2
  119. package/packages/memory/package.json +2 -2
  120. package/packages/policy/package.json +2 -2
  121. package/packages/protocol/package.json +1 -1
  122. package/packages/resiliency/package.json +1 -1
  123. package/packages/sdk/README.md +512 -58
  124. package/packages/sdk/dist/client.d.ts +135 -1
  125. package/packages/sdk/dist/client.js +338 -0
  126. package/packages/sdk/dist/index.d.ts +2 -1
  127. package/packages/sdk/dist/index.js +2 -0
  128. package/packages/sdk/dist/logs.d.ts +61 -0
  129. package/packages/sdk/dist/logs.js +95 -0
  130. package/packages/sdk/dist/protocol/index.d.ts +1 -1
  131. package/packages/sdk/dist/protocol/types.d.ts +186 -1
  132. package/packages/sdk/package.json +3 -3
  133. package/packages/spawner/package.json +2 -2
  134. package/packages/state/package.json +1 -1
  135. package/packages/storage/dist/sqlite-adapter.js +2 -0
  136. package/packages/storage/package.json +2 -2
  137. package/packages/telemetry/package.json +1 -1
  138. package/packages/trajectory/package.json +2 -2
  139. package/packages/user-directory/package.json +2 -2
  140. package/packages/utils/package.json +1 -1
  141. package/packages/wrapper/dist/base-wrapper.js +27 -10
  142. package/packages/wrapper/dist/idle-detector.d.ts +4 -0
  143. package/packages/wrapper/dist/idle-detector.js +21 -8
  144. package/packages/wrapper/dist/relay-pty-orchestrator.d.ts +5 -0
  145. package/packages/wrapper/dist/relay-pty-orchestrator.js +60 -5
  146. package/packages/wrapper/dist/tmux-wrapper.js +16 -0
  147. package/packages/wrapper/package.json +7 -7
  148. package/scripts/hooks/install.sh +16 -0
  149. package/scripts/hooks/pre-commit +60 -0
  150. package/scripts/postinstall.js +41 -1
  151. package/specs/PRIMITIVES_ROADMAP.md +2154 -0
  152. package/dist/dashboard/out/_next/static/chunks/320-402ffc8646b31da1.js +0 -1
  153. package/dist/dashboard/out/_next/static/chunks/631-af51bad94027527a.js +0 -1
  154. package/dist/dashboard/out/_next/static/chunks/app/providers/page-bcf46064ac4474ce.js +0 -1
  155. package/packages/dashboard/ui-dist/_next/static/chunks/320-402ffc8646b31da1.js +0 -1
  156. package/packages/dashboard/ui-dist/_next/static/chunks/631-af51bad94027527a.js +0 -1
  157. package/packages/dashboard/ui-dist/_next/static/chunks/app/providers/page-bcf46064ac4474ce.js +0 -1
  158. /package/dist/dashboard/out/_next/static/{JIjqkuDKNeoSg7KaMMuhx → PwtT8u1tFMW_S1HUv0i5S}/_buildManifest.js +0 -0
  159. /package/dist/dashboard/out/_next/static/{JIjqkuDKNeoSg7KaMMuhx → PwtT8u1tFMW_S1HUv0i5S}/_ssgManifest.js +0 -0
  160. /package/packages/dashboard/ui-dist/_next/static/{JIjqkuDKNeoSg7KaMMuhx → 52xh7eSCZzG97BVf5zzLY}/_buildManifest.js +0 -0
  161. /package/packages/dashboard/ui-dist/_next/static/{JIjqkuDKNeoSg7KaMMuhx → 52xh7eSCZzG97BVf5zzLY}/_ssgManifest.js +0 -0
  162. /package/packages/dashboard/ui-dist/_next/static/{nmkOi7bqeDmLMoWBih8lz → NN1eZ4W4r5XU6mkmJWV2-}/_buildManifest.js +0 -0
  163. /package/packages/dashboard/ui-dist/_next/static/{nmkOi7bqeDmLMoWBih8lz → NN1eZ4W4r5XU6mkmJWV2-}/_ssgManifest.js +0 -0
  164. /package/packages/dashboard/ui-dist/_next/static/{wk_gKRNSPpWE-ZhGL6UMl → PwtT8u1tFMW_S1HUv0i5S}/_buildManifest.js +0 -0
  165. /package/packages/dashboard/ui-dist/_next/static/{wk_gKRNSPpWE-ZhGL6UMl → PwtT8u1tFMW_S1HUv0i5S}/_ssgManifest.js +0 -0
@@ -0,0 +1,140 @@
1
+ #!/bin/bash
2
+ # Test CLI spawn flow - simulates real spawner behavior
3
+ # This is a more realistic test that mimics what AgentSpawner does
4
+ #
5
+ # Usage: ./test-spawn.sh <cli> [--interactive]
6
+ # Example: ./test-spawn.sh cursor
7
+ # ./test-spawn.sh cursor --interactive
8
+ # DEBUG_SPAWN=1 ./test-spawn.sh cursor
9
+
10
+ set -e
11
+
12
+ CLI=${1:-cursor}
13
+ INTERACTIVE=""
14
+ if [ "$2" = "--interactive" ]; then
15
+ INTERACTIVE="1"
16
+ fi
17
+
18
+ # Map CLI name to actual command (cursor installs as 'agent')
19
+ CLI_CMD="$CLI"
20
+ if [ "$CLI" = "cursor" ]; then
21
+ CLI_CMD="agent"
22
+ fi
23
+
24
+ NAME="spawn-test-${CLI}"
25
+ SOCKET="/tmp/relay-pty-${NAME}.sock"
26
+ RELAY_DATA_DIR="/tmp/relay-test-data"
27
+
28
+ # Create test data directories
29
+ mkdir -p "$RELAY_DATA_DIR"
30
+
31
+ # Cleanup function
32
+ cleanup() {
33
+ echo ""
34
+ echo "Cleaning up..."
35
+ rm -f "$SOCKET"
36
+ pkill -f "relay-pty.*${NAME}" 2>/dev/null || true
37
+ }
38
+ trap cleanup EXIT
39
+
40
+ # Remove stale socket if exists
41
+ rm -f "$SOCKET"
42
+
43
+ echo "========================================"
44
+ echo " Spawn Flow Test: $CLI"
45
+ echo "========================================"
46
+ echo ""
47
+ echo "This test simulates what AgentSpawner.spawn() does:"
48
+ echo " 1. Builds command with appropriate flags"
49
+ echo " 2. Starts relay-pty with the CLI"
50
+ echo " 3. Monitors for daemon registration"
51
+ echo ""
52
+ echo "Session name: $NAME"
53
+ echo "Socket path: $SOCKET"
54
+ echo "Data dir: $RELAY_DATA_DIR"
55
+ echo ""
56
+
57
+ # Build CLI arguments exactly like spawner does
58
+ CLI_ARGS=()
59
+
60
+ # Add args based on CLI type
61
+ case $CLI in
62
+ claude)
63
+ # Claude: add --dangerously-skip-permissions in non-interactive mode
64
+ if [ -z "$INTERACTIVE" ]; then
65
+ CLI_ARGS+=(--dangerously-skip-permissions)
66
+ echo "[spawn] Adding --dangerously-skip-permissions (non-interactive mode)"
67
+ fi
68
+ ;;
69
+ cursor)
70
+ # Cursor: add --force in non-interactive mode
71
+ if [ -z "$INTERACTIVE" ]; then
72
+ CLI_ARGS+=(--force)
73
+ echo "[spawn] Adding --force (non-interactive mode)"
74
+ fi
75
+ ;;
76
+ codex)
77
+ # Codex: supports device flow for headless
78
+ if [ -z "$INTERACTIVE" ]; then
79
+ CLI_ARGS+=(login --device-auth)
80
+ echo "[spawn] Adding login --device-auth (non-interactive mode)"
81
+ fi
82
+ ;;
83
+ copilot)
84
+ # Copilot: needs auth login command, device flow for headless
85
+ if [ -z "$INTERACTIVE" ]; then
86
+ CLI_ARGS+=(auth login --device)
87
+ echo "[spawn] Adding auth login --device (non-interactive mode)"
88
+ else
89
+ CLI_ARGS+=(auth login)
90
+ echo "[spawn] Adding auth login (interactive mode)"
91
+ fi
92
+ ;;
93
+ opencode)
94
+ # OpenCode: needs auth login command
95
+ CLI_ARGS+=(auth login)
96
+ echo "[spawn] Adding auth login"
97
+ ;;
98
+ droid)
99
+ # Droid: needs --login flag
100
+ CLI_ARGS+=(--login)
101
+ echo "[spawn] Adding --login"
102
+ ;;
103
+ esac
104
+
105
+ echo ""
106
+ echo "Command: $CLI_CMD ${CLI_ARGS[*]}"
107
+ echo ""
108
+
109
+ # Build relay-pty args
110
+ RELAY_ARGS=(
111
+ --name "$NAME"
112
+ --socket "$SOCKET"
113
+ --idle-timeout 300
114
+ )
115
+
116
+ # Enable JSON output for debugging
117
+ if [ -n "$DEBUG_SPAWN" ] || [ -n "$DEBUG" ]; then
118
+ RELAY_ARGS+=(--json-output)
119
+ echo "[debug] JSON output enabled"
120
+ fi
121
+
122
+ echo "========================================"
123
+ echo " Starting CLI with relay-pty"
124
+ echo "========================================"
125
+ echo ""
126
+ echo "Press Ctrl+C to stop."
127
+ echo ""
128
+ echo "In another terminal, you can:"
129
+ echo " - Check socket status: echo '{\"type\":\"status\"}' | nc -U $SOCKET"
130
+ echo " - Inject message: echo '{\"type\":\"inject\",\"body\":\"test\"}' | nc -U $SOCKET"
131
+ echo " - Monitor registration: watch -n1 'cat $RELAY_DATA_DIR/*.json 2>/dev/null || echo no files'"
132
+ echo ""
133
+
134
+ # Start the CLI with relay-pty
135
+ # In a real spawn, this would be done via AgentSpawner which handles registration waiting
136
+ if [ ${#CLI_ARGS[@]} -gt 0 ]; then
137
+ exec relay-pty "${RELAY_ARGS[@]}" -- "$CLI_CMD" "${CLI_ARGS[@]}"
138
+ else
139
+ exec relay-pty "${RELAY_ARGS[@]}" -- "$CLI_CMD"
140
+ fi
@@ -0,0 +1,247 @@
1
+ #!/bin/bash
2
+ # Full integration test with daemon
3
+ # This starts a local daemon and tests the complete spawn flow
4
+ #
5
+ # Usage: ./test-with-daemon.sh <cli>
6
+ # Example: ./test-with-daemon.sh cursor
7
+ # DEBUG=1 ./test-with-daemon.sh cursor
8
+
9
+ set -e
10
+
11
+ CLI=${1:-cursor}
12
+
13
+ # Map CLI name to actual command
14
+ CLI_CMD="$CLI"
15
+ if [ "$CLI" = "cursor" ]; then
16
+ CLI_CMD="agent"
17
+ fi
18
+
19
+ NAME="daemon-test-${CLI}"
20
+ SOCKET="/tmp/relay-pty-${NAME}.sock"
21
+
22
+ # Daemon configuration
23
+ DAEMON_PORT=${DAEMON_PORT:-3377}
24
+ DAEMON_HOST="127.0.0.1"
25
+ DAEMON_URL="http://${DAEMON_HOST}:${DAEMON_PORT}"
26
+ DATA_DIR="/tmp/relay-daemon-test"
27
+
28
+ # Cleanup function
29
+ cleanup() {
30
+ echo ""
31
+ echo "========================================"
32
+ echo " Cleaning up"
33
+ echo "========================================"
34
+ rm -f "$SOCKET"
35
+ if [ -n "$DAEMON_PID" ]; then
36
+ echo "Stopping daemon (PID: $DAEMON_PID)..."
37
+ kill $DAEMON_PID 2>/dev/null || true
38
+ fi
39
+ if [ -n "$PTY_PID" ]; then
40
+ echo "Stopping relay-pty (PID: $PTY_PID)..."
41
+ kill $PTY_PID 2>/dev/null || true
42
+ fi
43
+ echo "Done."
44
+ }
45
+ trap cleanup EXIT
46
+
47
+ # Create data directory
48
+ mkdir -p "$DATA_DIR"
49
+
50
+ echo "========================================"
51
+ echo " Full Daemon Integration Test: $CLI"
52
+ echo "========================================"
53
+ echo ""
54
+ echo "This test starts a real daemon and tests the complete flow:"
55
+ echo " 1. Start relay-daemon"
56
+ echo " 2. Start relay-pty with CLI"
57
+ echo " 3. Wait for agent registration"
58
+ echo " 4. Monitor the full flow"
59
+ echo ""
60
+ echo "Configuration:"
61
+ echo " CLI: $CLI_CMD"
62
+ echo " Agent name: $NAME"
63
+ echo " Daemon URL: $DAEMON_URL"
64
+ echo " Data dir: $DATA_DIR"
65
+ echo ""
66
+
67
+ # Check if daemon binary is available
68
+ if ! command -v relay-daemon &> /dev/null; then
69
+ echo "WARNING: relay-daemon not found in PATH"
70
+ echo ""
71
+ echo "To build the daemon:"
72
+ echo " cd packages/daemon && npm run build"
73
+ echo ""
74
+ echo "Or run a daemon manually:"
75
+ echo " npm run daemon"
76
+ echo ""
77
+ echo "Then re-run this test."
78
+ exit 1
79
+ fi
80
+
81
+ echo "========================================"
82
+ echo " Phase 1: Starting Daemon"
83
+ echo "========================================"
84
+ echo ""
85
+
86
+ # Check if a daemon is already running
87
+ if curl -s "${DAEMON_URL}/health" > /dev/null 2>&1; then
88
+ echo "Daemon already running at $DAEMON_URL"
89
+ DAEMON_PID=""
90
+ else
91
+ echo "Starting daemon on port $DAEMON_PORT..."
92
+
93
+ # Start daemon in background with test configuration
94
+ RELAY_DATA_DIR="$DATA_DIR" \
95
+ RELAY_PORT="$DAEMON_PORT" \
96
+ DEBUG="${DEBUG:-}" \
97
+ relay-daemon > "$DATA_DIR/daemon.log" 2>&1 &
98
+
99
+ DAEMON_PID=$!
100
+ echo "Daemon started (PID: $DAEMON_PID)"
101
+
102
+ # Wait for daemon to be ready
103
+ echo "Waiting for daemon to be ready..."
104
+ for i in $(seq 1 30); do
105
+ if curl -s "${DAEMON_URL}/health" > /dev/null 2>&1; then
106
+ echo "Daemon is ready!"
107
+ break
108
+ fi
109
+ if [ $i -eq 30 ]; then
110
+ echo "ERROR: Daemon failed to start within 30 seconds"
111
+ echo ""
112
+ echo "Daemon log:"
113
+ cat "$DATA_DIR/daemon.log" | tail -50
114
+ exit 1
115
+ fi
116
+ sleep 1
117
+ done
118
+ fi
119
+
120
+ echo ""
121
+
122
+ echo "========================================"
123
+ echo " Phase 2: Starting CLI with relay-pty"
124
+ echo "========================================"
125
+ echo ""
126
+
127
+ # Build CLI arguments
128
+ CLI_ARGS=()
129
+ case $CLI in
130
+ claude)
131
+ CLI_ARGS+=(--dangerously-skip-permissions)
132
+ ;;
133
+ cursor)
134
+ CLI_ARGS+=(--force)
135
+ ;;
136
+ esac
137
+
138
+ echo "Command: $CLI_CMD ${CLI_ARGS[*]}"
139
+
140
+ # Build relay-pty args
141
+ RELAY_ARGS=(
142
+ --name "$NAME"
143
+ --socket "$SOCKET"
144
+ --idle-timeout 300
145
+ )
146
+
147
+ # Enable verbose output
148
+ if [ -n "$DEBUG" ]; then
149
+ RELAY_ARGS+=(--json-output)
150
+ fi
151
+
152
+ # Set daemon URL environment variable so relay-pty connects to our test daemon
153
+ export RELAY_DAEMON_URL="$DAEMON_URL"
154
+
155
+ echo "Starting relay-pty..."
156
+ if [ ${#CLI_ARGS[@]} -gt 0 ]; then
157
+ relay-pty "${RELAY_ARGS[@]}" -- "$CLI_CMD" "${CLI_ARGS[@]}" 2>&1 &
158
+ else
159
+ relay-pty "${RELAY_ARGS[@]}" -- "$CLI_CMD" 2>&1 &
160
+ fi
161
+
162
+ PTY_PID=$!
163
+ echo "relay-pty started (PID: $PTY_PID)"
164
+ echo ""
165
+
166
+ echo "========================================"
167
+ echo " Phase 3: Monitoring Registration"
168
+ echo "========================================"
169
+ echo ""
170
+
171
+ # Poll for registration via daemon API
172
+ START_TIME=$(date +%s)
173
+ TIMEOUT_SEC=60
174
+
175
+ echo "Polling daemon for agent registration (timeout: ${TIMEOUT_SEC}s)..."
176
+ echo ""
177
+
178
+ while true; do
179
+ CURRENT_TIME=$(date +%s)
180
+ ELAPSED=$((CURRENT_TIME - START_TIME))
181
+
182
+ # Check if PTY process is still running
183
+ if ! kill -0 $PTY_PID 2>/dev/null; then
184
+ echo ""
185
+ echo "[$(date +%T)] ERROR: relay-pty exited after ${ELAPSED}s"
186
+ echo ""
187
+ echo "The CLI crashed or exited before completing registration."
188
+ echo ""
189
+ if [ -f "$DATA_DIR/daemon.log" ]; then
190
+ echo "Daemon log (last 20 lines):"
191
+ tail -20 "$DATA_DIR/daemon.log"
192
+ fi
193
+ exit 1
194
+ fi
195
+
196
+ # Query daemon for connected agents
197
+ AGENTS=$(curl -s "${DAEMON_URL}/api/agents" 2>/dev/null || echo "[]")
198
+
199
+ # Check if our agent is registered
200
+ if echo "$AGENTS" | grep -q "\"$NAME\""; then
201
+ echo ""
202
+ echo "========================================"
203
+ echo " SUCCESS: Agent Registered!"
204
+ echo "========================================"
205
+ echo ""
206
+ echo "Agent '$NAME' successfully registered with daemon after ${ELAPSED}s"
207
+ echo ""
208
+ echo "Connected agents:"
209
+ echo "$AGENTS" | jq . 2>/dev/null || echo "$AGENTS"
210
+ echo ""
211
+ echo "Press Ctrl+C to stop the test, or leave running to interact with the CLI."
212
+
213
+ # Keep running so user can interact
214
+ wait $PTY_PID
215
+ exit 0
216
+ fi
217
+
218
+ echo "[$(date +%T)] +${ELAPSED}s: Waiting for registration... (agents: $(echo "$AGENTS" | grep -o '"' | wc -l | xargs))"
219
+
220
+ # Check timeout
221
+ if [ $ELAPSED -ge $TIMEOUT_SEC ]; then
222
+ echo ""
223
+ echo "========================================"
224
+ echo " TIMEOUT: Registration Failed"
225
+ echo "========================================"
226
+ echo ""
227
+ echo "Agent '$NAME' did not register within ${TIMEOUT_SEC}s"
228
+ echo ""
229
+ echo "This is the same timeout the real spawner would hit."
230
+ echo ""
231
+ echo "Debugging info:"
232
+ echo ""
233
+ echo "1. Connected agents from daemon:"
234
+ echo "$AGENTS" | jq . 2>/dev/null || echo "$AGENTS"
235
+ echo ""
236
+ if [ -f "$DATA_DIR/daemon.log" ]; then
237
+ echo "2. Daemon log (last 30 lines):"
238
+ tail -30 "$DATA_DIR/daemon.log"
239
+ fi
240
+ echo ""
241
+ echo "3. Check if CLI is stuck on a prompt (auth, trust, etc.)"
242
+ echo ""
243
+ exit 1
244
+ fi
245
+
246
+ sleep 2
247
+ done
@@ -0,0 +1,112 @@
1
+ #!/bin/bash
2
+ # Verify CLI credentials exist and show (redacted) contents
3
+ # Usage: ./verify-auth.sh <cli>
4
+ # Example: ./verify-auth.sh claude
5
+
6
+ CLI=${1:-claude}
7
+
8
+ # Map CLI to credential file path
9
+ case $CLI in
10
+ claude)
11
+ CRED_FILE="$HOME/.claude/.credentials.json"
12
+ ;;
13
+ codex)
14
+ CRED_FILE="$HOME/.codex/auth.json"
15
+ ;;
16
+ gemini)
17
+ # Gemini stores in application_default_credentials.json
18
+ CRED_FILE="$HOME/.config/gcloud/application_default_credentials.json"
19
+ ALT_FILE="$HOME/.gemini/credentials.json"
20
+ ;;
21
+ cursor|agent)
22
+ # Cursor CLI installs as 'agent', credentials in ~/.cursor/
23
+ CRED_FILE="$HOME/.cursor/auth.json"
24
+ CLI="cursor" # Normalize name
25
+ ;;
26
+ opencode)
27
+ CRED_FILE="$HOME/.local/share/opencode/auth.json"
28
+ ;;
29
+ droid)
30
+ CRED_FILE="$HOME/.droid/auth.json"
31
+ ;;
32
+ copilot)
33
+ # GitHub Copilot uses gh CLI auth - stored in YAML format
34
+ CRED_FILE="$HOME/.config/gh/hosts.yml"
35
+ ;;
36
+ *)
37
+ echo "Unknown CLI: $CLI"
38
+ echo "Supported: claude, codex, gemini, cursor, opencode, droid, copilot"
39
+ exit 1
40
+ ;;
41
+ esac
42
+
43
+ echo "========================================"
44
+ echo " Checking credentials for: $CLI"
45
+ echo "========================================"
46
+ echo ""
47
+
48
+ # Check primary credential file
49
+ if [ -f "$CRED_FILE" ]; then
50
+ echo "✓ Credentials found: $CRED_FILE"
51
+ echo ""
52
+ echo "Contents (tokens redacted):"
53
+ echo "----------------------------------------"
54
+ # Redact any values that look like tokens (long strings, JWTs, etc.)
55
+ cat "$CRED_FILE" | jq '.' 2>/dev/null | \
56
+ sed -E 's/"([^"]*[Tt]oken[^"]*|[Aa]ccess[^"]*|[Rr]efresh[^"]*|[Ss]ecret[^"]*)": "[^"]{20,}"/"***\1***": "[REDACTED]"/g' || \
57
+ cat "$CRED_FILE" | sed -E 's/"[^"]{40,}"/"[REDACTED]"/g'
58
+ echo "----------------------------------------"
59
+ echo ""
60
+
61
+ # Check for specific fields
62
+ if command -v jq &> /dev/null && [ -f "$CRED_FILE" ]; then
63
+ echo "Token check:"
64
+ if jq -e '.claudeAiOauth.accessToken' "$CRED_FILE" &>/dev/null; then
65
+ echo " ✓ Access token present (Claude format)"
66
+ elif jq -e '.tokens.access_token' "$CRED_FILE" &>/dev/null; then
67
+ echo " ✓ Access token present (Codex format)"
68
+ elif jq -e '.accessToken' "$CRED_FILE" &>/dev/null; then
69
+ echo " ✓ Access token present (generic format)"
70
+ elif jq -e '.access_token' "$CRED_FILE" &>/dev/null; then
71
+ echo " ✓ Access token present (OAuth format)"
72
+ else
73
+ echo " ? Access token format unknown"
74
+ fi
75
+
76
+ if jq -e '.claudeAiOauth.refreshToken' "$CRED_FILE" &>/dev/null || \
77
+ jq -e '.tokens.refresh_token' "$CRED_FILE" &>/dev/null || \
78
+ jq -e '.refreshToken' "$CRED_FILE" &>/dev/null || \
79
+ jq -e '.refresh_token' "$CRED_FILE" &>/dev/null; then
80
+ echo " ✓ Refresh token present"
81
+ else
82
+ echo " ✗ No refresh token found"
83
+ fi
84
+ fi
85
+
86
+ exit 0
87
+ else
88
+ echo "✗ No credentials found at: $CRED_FILE"
89
+
90
+ # Check alternate location for Gemini
91
+ if [ -n "$ALT_FILE" ] && [ -f "$ALT_FILE" ]; then
92
+ echo ""
93
+ echo "✓ Found alternate credentials: $ALT_FILE"
94
+ cat "$ALT_FILE" | jq '.' 2>/dev/null | \
95
+ sed -E 's/"[^"]{40,}"/"[REDACTED]"/g' || \
96
+ cat "$ALT_FILE"
97
+ exit 0
98
+ fi
99
+
100
+ # Show what files exist in the CLI's config directory
101
+ CLI_DIR=$(dirname "$CRED_FILE")
102
+ if [ -d "$CLI_DIR" ]; then
103
+ echo ""
104
+ echo "Files in $CLI_DIR:"
105
+ ls -la "$CLI_DIR" 2>/dev/null || echo " (directory exists but is empty or unreadable)"
106
+ else
107
+ echo ""
108
+ echo "Config directory does not exist: $CLI_DIR"
109
+ fi
110
+
111
+ exit 1
112
+ fi
@@ -114,9 +114,11 @@ export async function runCLIAuthViaPTY(config, options = {}) {
114
114
  }
115
115
  }, delay);
116
116
  }
117
- // Look for auth URL
118
- const cleanText = stripAnsiCodes(text);
119
- const match = cleanText.match(config.urlPattern);
117
+ // Look for auth URL in accumulated output
118
+ // Join lines that look like URL continuations (handles wrapped URLs)
119
+ const cleanAccumulated = stripAnsiCodes(result.output)
120
+ .replace(/\n(?=[a-zA-Z0-9\-_.~:/?#\[\]@!$&'()*+,;=%])/g, '');
121
+ const match = cleanAccumulated.match(config.urlPattern);
120
122
  if (match && match[1] && !result.authUrl) {
121
123
  result.authUrl = match[1];
122
124
  if (result.authUrl) {
@@ -134,9 +136,10 @@ export async function runCLIAuthViaPTY(config, options = {}) {
134
136
  // Also check stderr for output (some CLIs write to stderr)
135
137
  result.output += text;
136
138
  options.onOutput?.(text);
137
- // Check stderr for auth URLs too
138
- const cleanText = stripAnsiCodes(text);
139
- const match = cleanText.match(config.urlPattern);
139
+ // Check stderr for auth URLs too (using accumulated output)
140
+ const cleanAccumulated = stripAnsiCodes(result.output)
141
+ .replace(/\n(?=[a-zA-Z0-9\-_.~:/?#\[\]@!$&'()*+,;=%])/g, '');
142
+ const match = cleanAccumulated.match(config.urlPattern);
140
143
  if (match && match[1] && !result.authUrl) {
141
144
  result.authUrl = match[1];
142
145
  if (result.authUrl) {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-relay/cloud",
3
- "version": "2.0.18",
3
+ "version": "2.0.20",
4
4
  "description": "Cloud API server and services for Agent Relay",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -38,11 +38,11 @@
38
38
  "test:watch": "vitest"
39
39
  },
40
40
  "dependencies": {
41
- "@agent-relay/wrapper": "2.0.18",
42
- "@agent-relay/config": "2.0.18",
43
- "@agent-relay/resiliency": "2.0.18",
44
- "@agent-relay/storage": "2.0.18",
45
- "@agent-relay/protocol": "2.0.18"
41
+ "@agent-relay/wrapper": "2.0.20",
42
+ "@agent-relay/config": "2.0.20",
43
+ "@agent-relay/resiliency": "2.0.20",
44
+ "@agent-relay/storage": "2.0.20",
45
+ "@agent-relay/protocol": "2.0.20"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@types/node": "^22.19.3",
@@ -69,6 +69,16 @@ export const CLI_AUTH_CONFIG = {
69
69
  delay: 300,
70
70
  description: 'Ready to code permission prompt',
71
71
  },
72
+ {
73
+ // Bypass Permissions mode prompt - for cloud workspaces running in sandboxed containers
74
+ // Shows "1. No, exit" (default selected) and "2. Yes, I accept"
75
+ // We need to select option 2 (down arrow) then confirm (enter)
76
+ // This is safe because cloud workspaces are sandboxed containers
77
+ pattern: /bypass\s*permissions\s*mode|will\s*not\s*ask\s*for\s*your\s*approval|sandboxed\s*container/i,
78
+ response: '\x1b[B\r', // Down arrow to select "Yes, I accept", then Enter
79
+ delay: 500, // Longer delay to ensure menu is fully rendered
80
+ description: 'Bypass permissions mode prompt',
81
+ },
72
82
  {
73
83
  // Fallback: Any "press enter" or "enter to confirm/continue" prompt
74
84
  // Keep this LAST so more specific handlers match first
@@ -213,6 +223,15 @@ export const CLI_AUTH_CONFIG = {
213
223
  displayName: 'Cursor',
214
224
  waitTimeout: 30000,
215
225
  prompts: [
226
+ {
227
+ // Initial login prompt - "Press any key to log in..."
228
+ // This is the FIRST prompt shown by Cursor Agent and blocks all progress
229
+ // Must send a keystroke to proceed to the auth URL
230
+ pattern: /press any key to log in/i,
231
+ response: '\r', // Send Enter to proceed
232
+ delay: 500,
233
+ description: 'Initial login prompt',
234
+ },
216
235
  {
217
236
  // Workspace Trust screen - must press 'a' to trust
218
237
  // "Do you want to mark this workspace as trusted?"
@@ -261,6 +280,62 @@ export const CLI_AUTH_CONFIG = {
261
280
  },
262
281
  ],
263
282
  },
283
+ copilot: {
284
+ command: 'copilot',
285
+ args: ['auth', 'login'], // copilot auth login - triggers GitHub OAuth flow
286
+ deviceFlowArgs: ['auth', 'login', '--device'], // Device flow for headless environments
287
+ supportsDeviceFlow: true,
288
+ urlPattern: /(https:\/\/[^\s]+)/,
289
+ // Copilot uses gh CLI's auth - credentials stored via GitHub CLI config
290
+ credentialPath: '~/.config/gh/hosts.yml',
291
+ displayName: 'GitHub Copilot',
292
+ waitTimeout: 30000,
293
+ prompts: [
294
+ {
295
+ // Browser or device code selection
296
+ pattern: /login\s*with\s*a\s*code|one-time\s*code|device\s*code|browser|authenticate/i,
297
+ response: '\r', // Select first option (browser-based auth)
298
+ delay: 200,
299
+ description: 'Auth method selection',
300
+ },
301
+ {
302
+ // Press Enter to open browser
303
+ pattern: /press\s*enter\s*to\s*open|open.*browser|opening\s*browser/i,
304
+ response: '\r',
305
+ delay: 200,
306
+ description: 'Open browser prompt',
307
+ },
308
+ {
309
+ // Login success - press enter to continue
310
+ pattern: /login\s*successful|logged\s*in.*press\s*enter|press\s*enter\s*to\s*continue|authentication\s*complete/i,
311
+ response: '\r',
312
+ delay: 200,
313
+ description: 'Login success prompt',
314
+ },
315
+ {
316
+ // Generic enter prompt (fallback)
317
+ pattern: /press\s*enter|enter\s*to\s*(confirm|continue|proceed)/i,
318
+ response: '\r',
319
+ delay: 300,
320
+ description: 'Generic enter prompt',
321
+ },
322
+ ],
323
+ successPatterns: [/success/i, /authenticated/i, /logged\s*in/i, /you.*(?:are|now).*logged/i, /authentication\s*complete/i],
324
+ errorPatterns: [
325
+ {
326
+ pattern: /oauth\s*error|auth.*failed|authentication\s*error/i,
327
+ message: 'GitHub authentication failed',
328
+ recoverable: true,
329
+ hint: 'Please try logging in again. Make sure you have GitHub Copilot access.',
330
+ },
331
+ {
332
+ pattern: /network\s*error|ENOTFOUND|ECONNREFUSED|timeout/i,
333
+ message: 'Network error during authentication',
334
+ recoverable: true,
335
+ hint: 'Please check your internet connection and try again.',
336
+ },
337
+ ],
338
+ },
264
339
  };
265
340
  /**
266
341
  * Strip ANSI escape codes from text
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-relay/config",
3
- "version": "2.0.18",
3
+ "version": "2.0.20",
4
4
  "description": "Shared configuration schemas and loaders for Agent Relay",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -83,7 +83,7 @@
83
83
  "test:watch": "vitest"
84
84
  },
85
85
  "dependencies": {
86
- "@agent-relay/protocol": "2.0.18",
86
+ "@agent-relay/protocol": "2.0.20",
87
87
  "zod": "^3.23.8",
88
88
  "zod-to-json-schema": "^3.23.1"
89
89
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-relay/continuity",
3
- "version": "2.0.18",
3
+ "version": "2.0.20",
4
4
  "description": "Session continuity manager for Relay (ledgers, handoffs, resume)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",