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,277 @@
1
+ # @agent-relay/cli-tester
2
+
3
+ Manual interactive testing environment for CLI authentication flows.
4
+
5
+ ## Purpose
6
+
7
+ This package provides a Docker-based environment for testing CLI authentication with real OAuth providers. It's designed for:
8
+
9
+ - **Debugging auth issues** - Isolate problems with specific CLIs (e.g., "Cursor doesn't work")
10
+ - **Testing auth flows** - Verify OAuth flows work end-to-end
11
+ - **Message injection** - Test relay-pty message delivery
12
+ - **Credential verification** - Check that credentials are saved correctly
13
+
14
+ ## Quick Start
15
+
16
+ From the relay repo root:
17
+
18
+ ```bash
19
+ # Start the test environment (drops into container shell)
20
+ npm run cli-tester:start
21
+
22
+ # Start with clean credentials (removes any cached auth)
23
+ npm run cli-tester:start:clean
24
+
25
+ # Start with daemon for full integration testing
26
+ npm run cli-tester:start:daemon
27
+ ```
28
+
29
+ ## Inside the Container
30
+
31
+ ### Test a CLI
32
+
33
+ ```bash
34
+ # Test Claude CLI with relay-pty
35
+ ./scripts/test-cli.sh claude
36
+
37
+ # Test Codex with device auth
38
+ ./scripts/test-cli.sh codex --device-auth
39
+
40
+ # Test with debug output
41
+ DEBUG=1 ./scripts/test-cli.sh cursor
42
+ ```
43
+
44
+ ### Verify Credentials
45
+
46
+ ```bash
47
+ # Check if credentials exist (after authenticating)
48
+ ./scripts/verify-auth.sh claude
49
+ ./scripts/verify-auth.sh codex
50
+ ./scripts/verify-auth.sh gemini
51
+ ```
52
+
53
+ ### Inject Messages
54
+
55
+ In a second terminal (while CLI is running):
56
+
57
+ ```bash
58
+ # Send a message via relay-pty socket
59
+ ./scripts/inject-message.sh test-claude "What is 2+2?"
60
+ ```
61
+
62
+ ### Clear Credentials
63
+
64
+ ```bash
65
+ # Clear credentials for fresh testing
66
+ ./scripts/clear-auth.sh claude
67
+ ./scripts/clear-auth.sh all # Clear all CLIs
68
+ ```
69
+
70
+ ## Advanced: Testing Spawn Flow
71
+
72
+ The simple `test-cli.sh` tests the CLI in isolation. For debugging issues where the CLI works in isolation but fails when spawned via the application (e.g., registration timeout), use these advanced tests:
73
+
74
+ ### Test Spawn Behavior
75
+
76
+ Simulates what `AgentSpawner.spawn()` does, including CLI-specific flags:
77
+
78
+ ```bash
79
+ # Test with same flags as spawner (--force for cursor, --dangerously-skip-permissions for claude)
80
+ ./scripts/test-spawn.sh cursor
81
+
82
+ # Test in interactive mode (without auto-accept flags)
83
+ ./scripts/test-spawn.sh cursor --interactive
84
+
85
+ # With verbose debug output
86
+ DEBUG_SPAWN=1 ./scripts/test-spawn.sh cursor
87
+ ```
88
+
89
+ ### Test Registration Flow
90
+
91
+ Monitors the registration files that the spawner polls. This is the step that times out:
92
+
93
+ ```bash
94
+ # Watch registration with 60 second timeout
95
+ ./scripts/test-registration.sh cursor 60
96
+
97
+ # With debug output
98
+ DEBUG_SPAWN=1 ./scripts/test-registration.sh cursor
99
+ ```
100
+
101
+ ### Full Daemon Integration Test
102
+
103
+ Starts a real daemon and tests the complete flow:
104
+
105
+ ```bash
106
+ # Full end-to-end test with daemon
107
+ ./scripts/test-with-daemon.sh cursor
108
+
109
+ # With debug output
110
+ DEBUG=1 ./scripts/test-with-daemon.sh cursor
111
+ ```
112
+
113
+ **Note:** Requires the daemon to be built: `cd packages/daemon && npm run build`
114
+
115
+ ## Debugging a Broken CLI
116
+
117
+ When a CLI isn't working, use this workflow:
118
+
119
+ ```bash
120
+ # 1. Start fresh
121
+ npm run cli-tester:start:clean
122
+
123
+ # 2. Test the problematic CLI
124
+ ./scripts/test-cli.sh cursor
125
+
126
+ # 3. Observe the output for:
127
+ # - Auth URLs being printed
128
+ # - Error messages
129
+ # - Prompt patterns
130
+
131
+ # 4. Check credentials
132
+ ./scripts/verify-auth.sh cursor
133
+ ls -la ~/.cursor/
134
+
135
+ # 5. Compare with a working CLI
136
+ ./scripts/test-cli.sh claude
137
+ ```
138
+
139
+ ## Debugging Registration Timeout
140
+
141
+ If a CLI works in isolation but times out when spawned ("Agent registration timeout"), the issue is in the daemon registration flow.
142
+
143
+ ### Quick Test (Run This First)
144
+
145
+ ```bash
146
+ # Test the EXACT setup flow - this is what TerminalProviderSetup.tsx does
147
+ DEBUG=1 ./scripts/test-full-spawn.sh cursor true
148
+ ```
149
+
150
+ This simulates:
151
+ - `interactive: true` (no --force flag, like setup terminal)
152
+ - 30 second registration timeout
153
+ - Verbose logging of what's happening
154
+
155
+ ### Understanding the Flow
156
+
157
+ **Normal spawn (non-interactive):**
158
+ ```bash
159
+ ./scripts/test-full-spawn.sh cursor # Has --force flag
160
+ ```
161
+
162
+ **Setup terminal (interactive):**
163
+ ```bash
164
+ ./scripts/test-full-spawn.sh cursor true # NO --force flag
165
+ ```
166
+
167
+ The key difference is `interactive: true` **skips auto-accept flags**. Setup terminals expect the user to respond to prompts in the browser terminal.
168
+
169
+ ### What the Tests Show
170
+
171
+ 1. **test-full-spawn.sh** - Simulates spawner's 30s registration timeout
172
+ - Shows poll count (like spawner logs)
173
+ - Shows socket status
174
+ - Captures CLI output to log file
175
+ - Tells you exactly where things fail
176
+
177
+ 2. **test-setup-flow.sh** - Identical to what TerminalProviderSetup.tsx does
178
+ - Uses `__setup__cursor-xxx` naming
179
+ - No CLI flags (interactive mode)
180
+
181
+ ### Debugging Steps
182
+
183
+ ```bash
184
+ # 1. Test in isolation (verify CLI starts)
185
+ ./scripts/test-cli.sh cursor
186
+
187
+ # 2. Test NON-INTERACTIVE spawn (with --force)
188
+ DEBUG=1 ./scripts/test-full-spawn.sh cursor
189
+
190
+ # 3. Test INTERACTIVE spawn (setup terminal flow)
191
+ DEBUG=1 ./scripts/test-full-spawn.sh cursor true
192
+
193
+ # 4. Watch the log file in another terminal
194
+ tail -f /tmp/relay-spawn-*.log
195
+ ```
196
+
197
+ ### Common Causes
198
+
199
+ | Symptom | Cause | Fix |
200
+ |---------|-------|-----|
201
+ | CLI exits immediately | Not installed or crash | Check `which agent` |
202
+ | Socket never created | CLI stuck on early prompt | Check log for prompts |
203
+ | 30s timeout | CLI waiting for user input | Respond to prompts (trust, etc.) |
204
+ | 30s timeout | No daemon to register with | Run with daemon profile |
205
+
206
+ ### The Registration Flow
207
+
208
+ The spawner waits for TWO conditions:
209
+ 1. Agent in `connected-agents.json` (daemon updates this when CLI connects)
210
+ 2. Agent in `agents.json` (relay-pty hook updates this)
211
+
212
+ Without a running daemon, both files are empty → timeout.
213
+
214
+ ## Available CLIs
215
+
216
+ The container includes these pre-installed CLIs:
217
+
218
+ | CLI | Command | Auth Command | Credential Path |
219
+ |-----|---------|--------------|-----------------|
220
+ | Claude | `claude` | (auto) | `~/.claude/.credentials.json` |
221
+ | Codex | `codex` | `login` | `~/.codex/auth.json` |
222
+ | Gemini | `gemini` | (auto) | `~/.gemini/credentials.json` |
223
+ | Cursor | `agent` | (auto) | `~/.cursor/auth.json` |
224
+ | OpenCode | `opencode` | `auth login` | `~/.local/share/opencode/auth.json` |
225
+ | Droid | `droid` | `--login` | `~/.droid/auth.json` |
226
+ | Copilot | `copilot` | `auth login` | `~/.config/gh/hosts.yml` |
227
+
228
+ **Note:** Cursor CLI installs as `agent`, not `cursor`. The test scripts handle this mapping automatically.
229
+
230
+ ## How It Works
231
+
232
+ 1. **relay-pty** wraps the CLI and provides:
233
+ - Unix socket for message injection
234
+ - Output parsing for relay commands
235
+ - Idle detection for message timing
236
+
237
+ 2. **Docker volumes** persist credentials between runs so you don't have to re-authenticate each time.
238
+
239
+ 3. **Shell scripts** provide simple commands for common operations.
240
+
241
+ ## TypeScript API
242
+
243
+ For programmatic use:
244
+
245
+ ```typescript
246
+ import { RelayPtyClient, checkCredentials } from '@agent-relay/cli-tester';
247
+
248
+ // Check credentials
249
+ const result = checkCredentials('claude');
250
+ console.log(result.exists, result.valid, result.hasAccessToken);
251
+
252
+ // Inject messages via socket
253
+ const client = new RelayPtyClient('/tmp/relay-pty-test-claude.sock');
254
+ await client.connect();
255
+ await client.inject({ from: 'Test', body: 'Hello' });
256
+ ```
257
+
258
+ ## File Structure
259
+
260
+ ```
261
+ packages/cli-tester/
262
+ ├── docker/
263
+ │ ├── Dockerfile # Test environment image
264
+ │ └── docker-compose.yml # Container configuration
265
+ ├── scripts/
266
+ │ ├── start.sh # Start container
267
+ │ ├── test-cli.sh # Test a CLI with relay-pty
268
+ │ ├── verify-auth.sh # Check credentials
269
+ │ ├── inject-message.sh # Send message via socket
270
+ │ └── clear-auth.sh # Clear credentials
271
+ ├── src/
272
+ │ └── utils/
273
+ │ ├── socket-client.ts # relay-pty socket communication
274
+ │ └── credential-check.ts # Credential file utilities
275
+ └── tests/
276
+ └── credential-check.test.ts
277
+ ```
@@ -0,0 +1,21 @@
1
+ /**
2
+ * CLI Auth Tester - Manual interactive testing for CLI authentication flows
3
+ *
4
+ * This package provides utilities for testing CLI authentication in a Docker container.
5
+ * Primary use case is debugging auth issues with various CLI tools (Claude, Codex, Gemini, etc.)
6
+ *
7
+ * @example
8
+ * ```bash
9
+ * # Start the test environment
10
+ * npm run cli-tester:start
11
+ *
12
+ * # Inside container, test a CLI
13
+ * ./scripts/test-cli.sh claude
14
+ *
15
+ * # Verify credentials
16
+ * ./scripts/verify-auth.sh claude
17
+ * ```
18
+ */
19
+ export { RelayPtyClient, createClient, getSocketPath, type InjectRequest, type InjectResponse, type StatusRequest, type StatusResponse, type RelayPtyResponse, } from './utils/socket-client.js';
20
+ export { checkCredentials, clearCredentials, checkAllCredentials, clearAllCredentials, getCredentialPath, getConfigPaths, type CLIType, type CredentialCheck, } from './utils/credential-check.js';
21
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,21 @@
1
+ /**
2
+ * CLI Auth Tester - Manual interactive testing for CLI authentication flows
3
+ *
4
+ * This package provides utilities for testing CLI authentication in a Docker container.
5
+ * Primary use case is debugging auth issues with various CLI tools (Claude, Codex, Gemini, etc.)
6
+ *
7
+ * @example
8
+ * ```bash
9
+ * # Start the test environment
10
+ * npm run cli-tester:start
11
+ *
12
+ * # Inside container, test a CLI
13
+ * ./scripts/test-cli.sh claude
14
+ *
15
+ * # Verify credentials
16
+ * ./scripts/verify-auth.sh claude
17
+ * ```
18
+ */
19
+ export { RelayPtyClient, createClient, getSocketPath, } from './utils/socket-client.js';
20
+ export { checkCredentials, clearCredentials, checkAllCredentials, clearAllCredentials, getCredentialPath, getConfigPaths, } from './utils/credential-check.js';
21
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Credential checking utilities for CLI authentication testing
3
+ * Verifies and parses credential files for various CLI tools
4
+ */
5
+ export type CLIType = 'claude' | 'codex' | 'gemini' | 'cursor' | 'opencode' | 'droid';
6
+ export interface CredentialCheck {
7
+ /** CLI type being checked */
8
+ cli: CLIType;
9
+ /** Whether the credential file exists */
10
+ exists: boolean;
11
+ /** Whether the credentials appear valid (have required fields) */
12
+ valid: boolean;
13
+ /** Whether an access token is present */
14
+ hasAccessToken: boolean;
15
+ /** Whether a refresh token is present */
16
+ hasRefreshToken: boolean;
17
+ /** Token expiration date if available */
18
+ expiresAt?: Date;
19
+ /** Path to the credential file */
20
+ filePath: string;
21
+ /** Raw credential data (tokens redacted) */
22
+ data?: Record<string, unknown>;
23
+ /** Error message if check failed */
24
+ error?: string;
25
+ }
26
+ /**
27
+ * Get the credential file path for a CLI
28
+ */
29
+ export declare function getCredentialPath(cli: CLIType): string;
30
+ /**
31
+ * Get all config paths for a CLI (for clearing)
32
+ */
33
+ export declare function getConfigPaths(cli: CLIType): string[];
34
+ /**
35
+ * Check credentials for a specific CLI
36
+ */
37
+ export declare function checkCredentials(cli: CLIType): CredentialCheck;
38
+ /**
39
+ * Clear credentials for a specific CLI
40
+ */
41
+ export declare function clearCredentials(cli: CLIType): {
42
+ cleared: string[];
43
+ errors: string[];
44
+ };
45
+ /**
46
+ * Clear all CLI credentials
47
+ */
48
+ export declare function clearAllCredentials(): Record<CLIType, {
49
+ cleared: string[];
50
+ errors: string[];
51
+ }>;
52
+ /**
53
+ * Check all CLI credentials
54
+ */
55
+ export declare function checkAllCredentials(): Record<CLIType, CredentialCheck>;
56
+ //# sourceMappingURL=credential-check.d.ts.map
@@ -0,0 +1,230 @@
1
+ /**
2
+ * Credential checking utilities for CLI authentication testing
3
+ * Verifies and parses credential files for various CLI tools
4
+ */
5
+ import { readFileSync, existsSync, unlinkSync } from 'node:fs';
6
+ import { homedir } from 'node:os';
7
+ import { join } from 'node:path';
8
+ /**
9
+ * Get the credential file path for a CLI
10
+ */
11
+ export function getCredentialPath(cli) {
12
+ const home = homedir();
13
+ switch (cli) {
14
+ case 'claude':
15
+ return join(home, '.claude', '.credentials.json');
16
+ case 'codex':
17
+ return join(home, '.codex', 'auth.json');
18
+ case 'gemini':
19
+ return join(home, '.config', 'gcloud', 'application_default_credentials.json');
20
+ case 'cursor':
21
+ return join(home, '.cursor', 'auth.json');
22
+ case 'opencode':
23
+ return join(home, '.local', 'share', 'opencode', 'auth.json');
24
+ case 'droid':
25
+ return join(home, '.droid', 'auth.json');
26
+ default:
27
+ throw new Error(`Unknown CLI type: ${cli}`);
28
+ }
29
+ }
30
+ /**
31
+ * Get all config paths for a CLI (for clearing)
32
+ */
33
+ export function getConfigPaths(cli) {
34
+ const home = homedir();
35
+ switch (cli) {
36
+ case 'claude':
37
+ return [
38
+ join(home, '.claude', '.credentials.json'),
39
+ join(home, '.claude', 'settings.json'),
40
+ join(home, '.claude', 'settings.local.json'),
41
+ ];
42
+ case 'codex':
43
+ return [
44
+ join(home, '.codex', 'auth.json'),
45
+ join(home, '.codex', 'config.json'),
46
+ join(home, '.codex', 'config.toml'),
47
+ ];
48
+ case 'gemini':
49
+ return [
50
+ join(home, '.config', 'gcloud', 'application_default_credentials.json'),
51
+ join(home, '.gemini', 'credentials.json'),
52
+ join(home, '.gemini', 'settings.json'),
53
+ ];
54
+ case 'cursor':
55
+ return [
56
+ join(home, '.cursor', 'auth.json'),
57
+ join(home, '.cursor', 'settings.json'),
58
+ ];
59
+ case 'opencode':
60
+ return [join(home, '.local', 'share', 'opencode', 'auth.json')];
61
+ case 'droid':
62
+ return [join(home, '.droid', 'auth.json')];
63
+ default:
64
+ throw new Error(`Unknown CLI type: ${cli}`);
65
+ }
66
+ }
67
+ /**
68
+ * Extract token info from credential data based on CLI type
69
+ */
70
+ function extractTokenInfo(cli, data) {
71
+ let hasAccessToken = false;
72
+ let hasRefreshToken = false;
73
+ let expiresAt;
74
+ switch (cli) {
75
+ case 'claude': {
76
+ // Claude format: { claudeAiOauth: { accessToken, refreshToken, expiresAt } }
77
+ const oauth = data.claudeAiOauth;
78
+ if (oauth) {
79
+ hasAccessToken = typeof oauth.accessToken === 'string' && oauth.accessToken.length > 0;
80
+ hasRefreshToken = typeof oauth.refreshToken === 'string' && oauth.refreshToken.length > 0;
81
+ if (typeof oauth.expiresAt === 'number') {
82
+ expiresAt = new Date(oauth.expiresAt);
83
+ }
84
+ }
85
+ break;
86
+ }
87
+ case 'codex': {
88
+ // Codex format: { tokens: { access_token, refresh_token, expires_at } }
89
+ const tokens = data.tokens;
90
+ if (tokens) {
91
+ hasAccessToken =
92
+ typeof tokens.access_token === 'string' && tokens.access_token.length > 0;
93
+ hasRefreshToken =
94
+ typeof tokens.refresh_token === 'string' && tokens.refresh_token.length > 0;
95
+ if (typeof tokens.expires_at === 'number') {
96
+ expiresAt = new Date(tokens.expires_at * 1000); // Unix timestamp
97
+ }
98
+ }
99
+ break;
100
+ }
101
+ case 'gemini': {
102
+ // Google OAuth format: { access_token, refresh_token, expiry_date }
103
+ hasAccessToken =
104
+ typeof data.access_token === 'string' && data.access_token.length > 0;
105
+ hasRefreshToken =
106
+ typeof data.refresh_token === 'string' && data.refresh_token.length > 0;
107
+ if (typeof data.expiry_date === 'number') {
108
+ expiresAt = new Date(data.expiry_date);
109
+ }
110
+ break;
111
+ }
112
+ case 'cursor':
113
+ case 'opencode':
114
+ case 'droid': {
115
+ // Generic format: { accessToken, refreshToken } or { access_token, refresh_token }
116
+ hasAccessToken =
117
+ (typeof data.accessToken === 'string' && data.accessToken.length > 0) ||
118
+ (typeof data.access_token === 'string' && data.access_token.length > 0);
119
+ hasRefreshToken =
120
+ (typeof data.refreshToken === 'string' && data.refreshToken.length > 0) ||
121
+ (typeof data.refresh_token === 'string' && data.refresh_token.length > 0);
122
+ break;
123
+ }
124
+ }
125
+ return { hasAccessToken, hasRefreshToken, expiresAt };
126
+ }
127
+ /**
128
+ * Redact sensitive values in credential data
129
+ */
130
+ function redactData(data) {
131
+ const redacted = {};
132
+ for (const [key, value] of Object.entries(data)) {
133
+ if (typeof value === 'string') {
134
+ // Redact anything that looks like a token
135
+ if (key.toLowerCase().includes('token') ||
136
+ key.toLowerCase().includes('secret') ||
137
+ key.toLowerCase().includes('key') ||
138
+ value.length > 40) {
139
+ redacted[key] = '[REDACTED]';
140
+ }
141
+ else {
142
+ redacted[key] = value;
143
+ }
144
+ }
145
+ else if (typeof value === 'object' && value !== null) {
146
+ redacted[key] = redactData(value);
147
+ }
148
+ else {
149
+ redacted[key] = value;
150
+ }
151
+ }
152
+ return redacted;
153
+ }
154
+ /**
155
+ * Check credentials for a specific CLI
156
+ */
157
+ export function checkCredentials(cli) {
158
+ const filePath = getCredentialPath(cli);
159
+ const result = {
160
+ cli,
161
+ exists: false,
162
+ valid: false,
163
+ hasAccessToken: false,
164
+ hasRefreshToken: false,
165
+ filePath,
166
+ };
167
+ if (!existsSync(filePath)) {
168
+ return result;
169
+ }
170
+ result.exists = true;
171
+ try {
172
+ const content = readFileSync(filePath, 'utf-8');
173
+ const data = JSON.parse(content);
174
+ const tokenInfo = extractTokenInfo(cli, data);
175
+ result.hasAccessToken = tokenInfo.hasAccessToken;
176
+ result.hasRefreshToken = tokenInfo.hasRefreshToken;
177
+ result.expiresAt = tokenInfo.expiresAt;
178
+ // Valid if at least access token is present
179
+ result.valid = result.hasAccessToken;
180
+ // Include redacted data for debugging
181
+ result.data = redactData(data);
182
+ }
183
+ catch (err) {
184
+ result.error = err instanceof Error ? err.message : 'Unknown error';
185
+ }
186
+ return result;
187
+ }
188
+ /**
189
+ * Clear credentials for a specific CLI
190
+ */
191
+ export function clearCredentials(cli) {
192
+ const paths = getConfigPaths(cli);
193
+ const cleared = [];
194
+ const errors = [];
195
+ for (const path of paths) {
196
+ if (existsSync(path)) {
197
+ try {
198
+ unlinkSync(path);
199
+ cleared.push(path);
200
+ }
201
+ catch (err) {
202
+ errors.push(`Failed to remove ${path}: ${err instanceof Error ? err.message : 'Unknown error'}`);
203
+ }
204
+ }
205
+ }
206
+ return { cleared, errors };
207
+ }
208
+ /**
209
+ * Clear all CLI credentials
210
+ */
211
+ export function clearAllCredentials() {
212
+ const clis = ['claude', 'codex', 'gemini', 'cursor', 'opencode', 'droid'];
213
+ const results = {};
214
+ for (const cli of clis) {
215
+ results[cli] = clearCredentials(cli);
216
+ }
217
+ return results;
218
+ }
219
+ /**
220
+ * Check all CLI credentials
221
+ */
222
+ export function checkAllCredentials() {
223
+ const clis = ['claude', 'codex', 'gemini', 'cursor', 'opencode', 'droid'];
224
+ const results = {};
225
+ for (const cli of clis) {
226
+ results[cli] = checkCredentials(cli);
227
+ }
228
+ return results;
229
+ }
230
+ //# sourceMappingURL=credential-check.js.map
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Socket client for communicating with relay-pty Unix socket
3
+ * Used for programmatic message injection and status queries
4
+ */
5
+ export interface InjectRequest {
6
+ type: 'inject';
7
+ id: string;
8
+ from: string;
9
+ body: string;
10
+ priority?: number;
11
+ }
12
+ export interface StatusRequest {
13
+ type: 'status';
14
+ }
15
+ export interface InjectResponse {
16
+ type: 'inject_result';
17
+ id: string;
18
+ status: 'queued' | 'injecting' | 'delivered' | 'failed';
19
+ timestamp: number;
20
+ error?: string;
21
+ }
22
+ export interface StatusResponse {
23
+ type: 'status';
24
+ agent_idle: boolean;
25
+ queue_length: number;
26
+ cursor_position: {
27
+ row: number;
28
+ col: number;
29
+ } | null;
30
+ last_output_ms: number;
31
+ }
32
+ export type RelayPtyResponse = InjectResponse | StatusResponse;
33
+ export declare class RelayPtyClient {
34
+ private socket;
35
+ private socketPath;
36
+ private responseBuffer;
37
+ constructor(socketPath: string);
38
+ /**
39
+ * Connect to the relay-pty socket
40
+ */
41
+ connect(): Promise<void>;
42
+ /**
43
+ * Send a request and wait for response
44
+ */
45
+ private sendRequest;
46
+ /**
47
+ * Inject a message into the CLI
48
+ */
49
+ inject(message: {
50
+ from: string;
51
+ body: string;
52
+ priority?: number;
53
+ }): Promise<InjectResponse>;
54
+ /**
55
+ * Get current status of the CLI session
56
+ */
57
+ getStatus(): Promise<StatusResponse>;
58
+ /**
59
+ * Wait for a specific message to be delivered
60
+ * Returns when the message reaches 'delivered' or 'failed' status
61
+ */
62
+ waitForDelivered(messageId: string, timeoutMs?: number): Promise<InjectResponse>;
63
+ /**
64
+ * Close the connection
65
+ */
66
+ close(): void;
67
+ }
68
+ /**
69
+ * Helper to create a connected client
70
+ */
71
+ export declare function createClient(socketPath: string): Promise<RelayPtyClient>;
72
+ /**
73
+ * Get socket path for a named session
74
+ */
75
+ export declare function getSocketPath(sessionName: string): string;
76
+ //# sourceMappingURL=socket-client.d.ts.map