agent-relay 1.2.3 → 1.3.1

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 (189) hide show
  1. package/.trajectories/agent-relay-322-324.md +17 -0
  2. package/.trajectories/completed/2026-01/traj_03zupyv1s7b9.json +49 -0
  3. package/.trajectories/completed/2026-01/traj_03zupyv1s7b9.md +31 -0
  4. package/.trajectories/completed/2026-01/traj_0zacdjl1g4ht.json +125 -0
  5. package/.trajectories/completed/2026-01/traj_0zacdjl1g4ht.md +62 -0
  6. package/.trajectories/completed/2026-01/traj_33iuy72sezbk.json +49 -0
  7. package/.trajectories/completed/2026-01/traj_33iuy72sezbk.md +31 -0
  8. package/.trajectories/completed/2026-01/traj_5ammh5qtvklq.json +77 -0
  9. package/.trajectories/completed/2026-01/traj_5ammh5qtvklq.md +42 -0
  10. package/.trajectories/completed/2026-01/traj_6mieijqyvaag.json +77 -0
  11. package/.trajectories/completed/2026-01/traj_6mieijqyvaag.md +42 -0
  12. package/.trajectories/completed/2026-01/traj_78ffm31jn3uk.json +77 -0
  13. package/.trajectories/completed/2026-01/traj_78ffm31jn3uk.md +42 -0
  14. package/.trajectories/completed/2026-01/traj_94gnp3k30goq.json +66 -0
  15. package/.trajectories/completed/2026-01/traj_94gnp3k30goq.md +36 -0
  16. package/.trajectories/completed/2026-01/traj_avqeghu6pz5a.json +40 -0
  17. package/.trajectories/completed/2026-01/traj_avqeghu6pz5a.md +22 -0
  18. package/.trajectories/completed/2026-01/traj_dcsp9s8y01ra.json +121 -0
  19. package/.trajectories/completed/2026-01/traj_dcsp9s8y01ra.md +29 -0
  20. package/.trajectories/completed/2026-01/traj_fhx9irlckht6.json +53 -0
  21. package/.trajectories/completed/2026-01/traj_fhx9irlckht6.md +32 -0
  22. package/.trajectories/completed/2026-01/traj_fqduidx3xbtp.json +101 -0
  23. package/.trajectories/completed/2026-01/traj_fqduidx3xbtp.md +52 -0
  24. package/.trajectories/completed/2026-01/traj_hf81ey93uz6t.json +49 -0
  25. package/.trajectories/completed/2026-01/traj_hf81ey93uz6t.md +31 -0
  26. package/.trajectories/completed/2026-01/traj_hfmki2jr9d4r.json +65 -0
  27. package/.trajectories/completed/2026-01/traj_hfmki2jr9d4r.md +37 -0
  28. package/.trajectories/completed/2026-01/traj_lq450ly148uw.json +49 -0
  29. package/.trajectories/completed/2026-01/traj_lq450ly148uw.md +31 -0
  30. package/.trajectories/completed/2026-01/traj_multi_server_arch.md +101 -0
  31. package/.trajectories/completed/2026-01/traj_psd9ob0j2ru3.json +27 -0
  32. package/.trajectories/completed/2026-01/traj_psd9ob0j2ru3.md +14 -0
  33. package/.trajectories/completed/2026-01/traj_ub8csuv3lcv4.json +53 -0
  34. package/.trajectories/completed/2026-01/traj_ub8csuv3lcv4.md +32 -0
  35. package/.trajectories/completed/2026-01/traj_uc29tlso8i9s.json +186 -0
  36. package/.trajectories/completed/2026-01/traj_uc29tlso8i9s.md +86 -0
  37. package/.trajectories/completed/2026-01/traj_ui9b4tqxoa7j.json +77 -0
  38. package/.trajectories/completed/2026-01/traj_ui9b4tqxoa7j.md +42 -0
  39. package/.trajectories/completed/2026-01/traj_v9dkdoxylyid.json +89 -0
  40. package/.trajectories/completed/2026-01/traj_v9dkdoxylyid.md +47 -0
  41. package/.trajectories/completed/2026-01/traj_xy9vifpqet80.json +65 -0
  42. package/.trajectories/completed/2026-01/traj_xy9vifpqet80.md +37 -0
  43. package/.trajectories/completed/2026-01/traj_y7aiwijyfmmv.json +49 -0
  44. package/.trajectories/completed/2026-01/traj_y7aiwijyfmmv.md +31 -0
  45. package/.trajectories/consolidate-settings-panel.md +24 -0
  46. package/.trajectories/gh-cli-user-token.md +26 -0
  47. package/.trajectories/index.json +155 -1
  48. package/deploy/workspace/codex.config.toml +15 -0
  49. package/deploy/workspace/entrypoint.sh +167 -7
  50. package/deploy/workspace/git-credential-relay +17 -2
  51. package/dist/bridge/spawner.d.ts +7 -0
  52. package/dist/bridge/spawner.js +40 -9
  53. package/dist/bridge/types.d.ts +2 -0
  54. package/dist/cli/index.js +210 -168
  55. package/dist/cloud/api/admin.d.ts +8 -0
  56. package/dist/cloud/api/admin.js +212 -0
  57. package/dist/cloud/api/auth.js +8 -0
  58. package/dist/cloud/api/billing.d.ts +0 -10
  59. package/dist/cloud/api/billing.js +248 -58
  60. package/dist/cloud/api/codex-auth-helper.d.ts +10 -4
  61. package/dist/cloud/api/codex-auth-helper.js +215 -8
  62. package/dist/cloud/api/coordinators.js +402 -0
  63. package/dist/cloud/api/daemons.js +15 -11
  64. package/dist/cloud/api/git.js +104 -17
  65. package/dist/cloud/api/github-app.js +42 -8
  66. package/dist/cloud/api/nango-auth.js +297 -16
  67. package/dist/cloud/api/onboarding.js +97 -33
  68. package/dist/cloud/api/providers.js +12 -16
  69. package/dist/cloud/api/repos.js +200 -124
  70. package/dist/cloud/api/test-helpers.js +40 -0
  71. package/dist/cloud/api/usage.js +13 -0
  72. package/dist/cloud/api/webhooks.js +1 -1
  73. package/dist/cloud/api/workspaces.d.ts +18 -0
  74. package/dist/cloud/api/workspaces.js +945 -15
  75. package/dist/cloud/config.d.ts +8 -0
  76. package/dist/cloud/config.js +15 -0
  77. package/dist/cloud/db/drizzle.d.ts +5 -2
  78. package/dist/cloud/db/drizzle.js +27 -20
  79. package/dist/cloud/db/schema.d.ts +19 -51
  80. package/dist/cloud/db/schema.js +5 -4
  81. package/dist/cloud/index.d.ts +0 -1
  82. package/dist/cloud/index.js +0 -1
  83. package/dist/cloud/provisioner/index.d.ts +93 -1
  84. package/dist/cloud/provisioner/index.js +608 -63
  85. package/dist/cloud/server.js +156 -16
  86. package/dist/cloud/services/compute-enforcement.d.ts +57 -0
  87. package/dist/cloud/services/compute-enforcement.js +175 -0
  88. package/dist/cloud/services/index.d.ts +2 -0
  89. package/dist/cloud/services/index.js +4 -0
  90. package/dist/cloud/services/intro-expiration.d.ts +55 -0
  91. package/dist/cloud/services/intro-expiration.js +211 -0
  92. package/dist/cloud/services/nango.d.ts +14 -0
  93. package/dist/cloud/services/nango.js +74 -14
  94. package/dist/cloud/services/ssh-security.d.ts +31 -0
  95. package/dist/cloud/services/ssh-security.js +63 -0
  96. package/dist/continuity/manager.d.ts +5 -0
  97. package/dist/continuity/manager.js +56 -2
  98. package/dist/daemon/api.d.ts +2 -0
  99. package/dist/daemon/api.js +214 -5
  100. package/dist/daemon/cli-auth.d.ts +13 -1
  101. package/dist/daemon/cli-auth.js +166 -47
  102. package/dist/daemon/connection.d.ts +7 -1
  103. package/dist/daemon/connection.js +15 -0
  104. package/dist/daemon/orchestrator.d.ts +2 -0
  105. package/dist/daemon/orchestrator.js +26 -0
  106. package/dist/daemon/repo-manager.d.ts +116 -0
  107. package/dist/daemon/repo-manager.js +384 -0
  108. package/dist/daemon/router.d.ts +60 -1
  109. package/dist/daemon/router.js +281 -20
  110. package/dist/daemon/user-directory.d.ts +111 -0
  111. package/dist/daemon/user-directory.js +233 -0
  112. package/dist/dashboard/out/404.html +1 -1
  113. package/dist/dashboard/out/_next/static/chunks/532-bace199897eeab37.js +9 -0
  114. package/dist/dashboard/out/_next/static/chunks/766-b54f0853794b78c3.js +1 -0
  115. package/dist/dashboard/out/_next/static/chunks/83-b51836037078006c.js +1 -0
  116. package/dist/dashboard/out/_next/static/chunks/891-6cd50de1224f70bb.js +1 -0
  117. package/dist/dashboard/out/_next/static/chunks/899-fc02ed79e3de4302.js +1 -0
  118. package/dist/dashboard/out/_next/static/chunks/app/app/onboarding/{page-3fdfa60e53f2810d.js → page-8553743baca53a00.js} +1 -1
  119. package/dist/dashboard/out/_next/static/chunks/app/app/page-c617745b81344f4f.js +1 -0
  120. package/dist/dashboard/out/_next/static/chunks/app/metrics/page-f829604fb75a831a.js +1 -0
  121. package/dist/dashboard/out/_next/static/chunks/app/{page-77e9c65420a06cfb.js → page-dc786c183425c2ac.js} +1 -1
  122. package/dist/dashboard/out/_next/static/chunks/app/providers/page-84322991d7244499.js +1 -0
  123. package/dist/dashboard/out/_next/static/chunks/app/providers/setup/[provider]/page-05606941a8e2be83.js +1 -0
  124. package/dist/dashboard/out/_next/static/chunks/{main-ed4e1fb6f29c34cf.js → main-2ee6beb2ae96d210.js} +1 -1
  125. package/dist/dashboard/out/_next/static/css/48a8fbe3e659080e.css +1 -0
  126. package/dist/dashboard/out/_next/static/css/fe4b28883eeff359.css +1 -0
  127. package/dist/dashboard/out/_next/static/sDcbGRTYLcpPvyTs_rsNb/_ssgManifest.js +1 -0
  128. package/dist/dashboard/out/app/onboarding.html +1 -1
  129. package/dist/dashboard/out/app/onboarding.txt +3 -3
  130. package/dist/dashboard/out/app.html +1 -1
  131. package/dist/dashboard/out/app.txt +3 -3
  132. package/dist/dashboard/out/apple-icon.png +0 -0
  133. package/dist/dashboard/out/connect-repos.html +1 -1
  134. package/dist/dashboard/out/connect-repos.txt +2 -2
  135. package/dist/dashboard/out/history.html +1 -1
  136. package/dist/dashboard/out/history.txt +2 -2
  137. package/dist/dashboard/out/index.html +1 -1
  138. package/dist/dashboard/out/index.txt +3 -3
  139. package/dist/dashboard/out/login.html +2 -2
  140. package/dist/dashboard/out/login.txt +2 -2
  141. package/dist/dashboard/out/metrics.html +1 -1
  142. package/dist/dashboard/out/metrics.txt +3 -3
  143. package/dist/dashboard/out/pricing.html +2 -2
  144. package/dist/dashboard/out/pricing.txt +3 -3
  145. package/dist/dashboard/out/providers/setup/claude.html +1 -0
  146. package/dist/dashboard/out/providers/setup/claude.txt +8 -0
  147. package/dist/dashboard/out/providers/setup/codex.html +1 -0
  148. package/dist/dashboard/out/providers/setup/codex.txt +8 -0
  149. package/dist/dashboard/out/providers.html +1 -1
  150. package/dist/dashboard/out/providers.txt +3 -3
  151. package/dist/dashboard/out/signup.html +2 -2
  152. package/dist/dashboard/out/signup.txt +2 -2
  153. package/dist/dashboard-server/server.js +316 -12
  154. package/dist/dashboard-server/user-bridge.d.ts +103 -0
  155. package/dist/dashboard-server/user-bridge.js +189 -0
  156. package/dist/protocol/channels.d.ts +205 -0
  157. package/dist/protocol/channels.js +154 -0
  158. package/dist/protocol/types.d.ts +13 -1
  159. package/dist/resiliency/provider-context.js +2 -0
  160. package/dist/shared/cli-auth-config.d.ts +19 -0
  161. package/dist/shared/cli-auth-config.js +58 -2
  162. package/dist/utils/agent-config.js +1 -1
  163. package/dist/wrapper/auth-detection.d.ts +49 -0
  164. package/dist/wrapper/auth-detection.js +192 -0
  165. package/dist/wrapper/base-wrapper.d.ts +153 -0
  166. package/dist/wrapper/base-wrapper.js +393 -0
  167. package/dist/wrapper/client.d.ts +7 -1
  168. package/dist/wrapper/client.js +3 -0
  169. package/dist/wrapper/index.d.ts +1 -0
  170. package/dist/wrapper/index.js +4 -3
  171. package/dist/wrapper/pty-wrapper.d.ts +62 -84
  172. package/dist/wrapper/pty-wrapper.js +154 -180
  173. package/dist/wrapper/tmux-wrapper.d.ts +41 -66
  174. package/dist/wrapper/tmux-wrapper.js +90 -134
  175. package/package.json +4 -2
  176. package/scripts/postinstall.js +11 -155
  177. package/scripts/test-interactive-terminal.sh +248 -0
  178. package/dist/cloud/vault/index.d.ts +0 -76
  179. package/dist/cloud/vault/index.js +0 -219
  180. package/dist/dashboard/out/_next/static/chunks/699-3b1cd6618a45d259.js +0 -1
  181. package/dist/dashboard/out/_next/static/chunks/724-2dae7627550ab88f.js +0 -9
  182. package/dist/dashboard/out/_next/static/chunks/766-1f2dd8cb7f766b0b.js +0 -1
  183. package/dist/dashboard/out/_next/static/chunks/app/app/page-e6381e5a6e1fbcfd.js +0 -1
  184. package/dist/dashboard/out/_next/static/chunks/app/metrics/page-67a3e98d9a43a6ed.js +0 -1
  185. package/dist/dashboard/out/_next/static/chunks/app/providers/page-e88bc117ef7671c3.js +0 -1
  186. package/dist/dashboard/out/_next/static/css/29852f26181969a0.css +0 -1
  187. package/dist/dashboard/out/_next/static/css/7c3ae9e8617d42a5.css +0 -1
  188. package/dist/dashboard/out/_next/static/wPgKJtcOmTFLpUncDg16A/_ssgManifest.js +0 -1
  189. /package/dist/dashboard/out/_next/static/{wPgKJtcOmTFLpUncDg16A → sDcbGRTYLcpPvyTs_rsNb}/_buildManifest.js +0 -0
@@ -3,18 +3,14 @@
3
3
  * Postinstall Script for agent-relay
4
4
  *
5
5
  * This script runs after npm install to:
6
- * 1. Rebuild native modules (better-sqlite3)
7
- * 2. Install tmux binary if not available on the system
8
- *
9
- * The tmux binary is installed within the package itself (bin/tmux),
10
- * making it portable and not requiring global installation.
6
+ * 1. Install dashboard dependencies
7
+ * 2. Patch agent-trajectories CLI
8
+ * 3. Check for tmux availability
11
9
  */
12
10
 
13
11
  import { execSync } from 'node:child_process';
14
- import os from 'node:os';
15
12
  import path from 'node:path';
16
13
  import fs from 'node:fs';
17
- import https from 'node:https';
18
14
  import { fileURLToPath } from 'node:url';
19
15
 
20
16
  const __filename = fileURLToPath(import.meta.url);
@@ -25,18 +21,12 @@ function getPackageRoot() {
25
21
  return path.resolve(__dirname, '..');
26
22
  }
27
23
 
28
- /** Installation directory (within the package) */
29
- function getInstallDir() {
30
- return path.join(getPackageRoot(), 'bin');
31
- }
32
-
33
24
  // Colors for console output
34
25
  const colors = {
35
26
  reset: '\x1b[0m',
36
27
  green: '\x1b[32m',
37
28
  yellow: '\x1b[33m',
38
29
  blue: '\x1b[34m',
39
- red: '\x1b[31m',
40
30
  };
41
31
 
42
32
  function info(msg) {
@@ -51,10 +41,6 @@ function warn(msg) {
51
41
  console.log(`${colors.yellow}[warn]${colors.reset} ${msg}`);
52
42
  }
53
43
 
54
- function error(msg) {
55
- console.log(`${colors.red}[error]${colors.reset} ${msg}`);
56
- }
57
-
58
44
  /**
59
45
  * Check if tmux is available on the system
60
46
  */
@@ -67,137 +53,6 @@ function hasSystemTmux() {
67
53
  }
68
54
  }
69
55
 
70
- /**
71
- * Get platform identifier for tmux-builds
72
- */
73
- function getPlatformId() {
74
- const platform = os.platform();
75
- const arch = os.arch();
76
-
77
- if (platform === 'darwin') {
78
- return arch === 'arm64' ? 'macos-arm64' : 'macos-x86_64';
79
- } else if (platform === 'linux') {
80
- return arch === 'arm64' ? 'linux-arm64' : 'linux-x86_64';
81
- }
82
-
83
- return null;
84
- }
85
-
86
- /**
87
- * Download file with redirect support
88
- */
89
- function downloadFile(url, destPath) {
90
- return new Promise((resolve, reject) => {
91
- const file = fs.createWriteStream(destPath);
92
-
93
- const request = (currentUrl, redirectCount = 0) => {
94
- if (redirectCount > 5) {
95
- reject(new Error('Too many redirects'));
96
- return;
97
- }
98
-
99
- const urlObj = new URL(currentUrl);
100
- const options = {
101
- hostname: urlObj.hostname,
102
- path: urlObj.pathname + urlObj.search,
103
- headers: {
104
- 'User-Agent': 'agent-relay-installer',
105
- },
106
- };
107
-
108
- https
109
- .get(options, (response) => {
110
- if (response.statusCode === 302 || response.statusCode === 301) {
111
- const location = response.headers.location;
112
- if (location) {
113
- request(location, redirectCount + 1);
114
- return;
115
- }
116
- }
117
-
118
- if (response.statusCode !== 200) {
119
- reject(new Error(`HTTP ${response.statusCode}`));
120
- return;
121
- }
122
-
123
- response.pipe(file);
124
- file.on('finish', () => {
125
- file.close();
126
- resolve();
127
- });
128
- })
129
- .on('error', reject);
130
- };
131
-
132
- request(url);
133
- });
134
- }
135
-
136
- /**
137
- * Install tmux binary
138
- */
139
- async function installTmux() {
140
- const TMUX_VERSION = '3.6a';
141
- const INSTALL_DIR = getInstallDir();
142
- const tmuxPath = path.join(INSTALL_DIR, 'tmux');
143
-
144
- // Check if already installed
145
- if (fs.existsSync(tmuxPath)) {
146
- info('Bundled tmux already installed');
147
- return true;
148
- }
149
-
150
- const platformId = getPlatformId();
151
- if (!platformId) {
152
- const platform = os.platform();
153
- warn(`Unsupported platform: ${platform} ${os.arch()}`);
154
- if (platform === 'win32') {
155
- warn('tmux requires WSL (Windows Subsystem for Linux)');
156
- warn('Install WSL first, then run: sudo apt install tmux');
157
- } else {
158
- warn('Please install tmux manually: https://github.com/tmux/tmux/wiki/Installing');
159
- }
160
- return false;
161
- }
162
-
163
- info(`Installing tmux ${TMUX_VERSION} for ${platformId}...`);
164
-
165
- const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'agent-relay-tmux-'));
166
- const archiveName = `tmux-${TMUX_VERSION}-${platformId}.tar.gz`;
167
- const archivePath = path.join(tmpDir, archiveName);
168
- const downloadUrl = `https://github.com/tmux/tmux-builds/releases/download/v${TMUX_VERSION}/${archiveName}`;
169
-
170
- try {
171
- info('Downloading tmux binary...');
172
- await downloadFile(downloadUrl, archivePath);
173
-
174
- info('Extracting...');
175
- execSync(`tar -xzf "${archivePath}" -C "${tmpDir}"`, { stdio: 'pipe' });
176
-
177
- const extractedTmux = path.join(tmpDir, 'tmux');
178
- if (!fs.existsSync(extractedTmux)) {
179
- throw new Error('tmux binary not found in archive');
180
- }
181
-
182
- fs.mkdirSync(INSTALL_DIR, { recursive: true });
183
- fs.copyFileSync(extractedTmux, tmuxPath);
184
- fs.chmodSync(tmuxPath, 0o755);
185
-
186
- success(`Installed tmux to ${tmuxPath}`);
187
- return true;
188
- } catch (err) {
189
- error(`Failed to install tmux: ${err.message}`);
190
- warn('Please install tmux manually, then reinstall: npm install agent-relay');
191
- return false;
192
- } finally {
193
- try {
194
- fs.rmSync(tmpDir, { recursive: true, force: true });
195
- } catch {
196
- // Ignore
197
- }
198
- }
199
- }
200
-
201
56
  /**
202
57
  * Install dashboard dependencies
203
58
  */
@@ -220,7 +75,7 @@ function installDashboardDeps() {
220
75
  execSync('npm install', { cwd: dashboardDir, stdio: 'inherit' });
221
76
  success('Dashboard dependencies installed');
222
77
  } catch (err) {
223
- error(`Failed to install dashboard dependencies: ${err.message}`);
78
+ warn(`Failed to install dashboard dependencies: ${err.message}`);
224
79
  }
225
80
  }
226
81
 
@@ -291,9 +146,8 @@ async function main() {
291
146
  // Always install dashboard dependencies (needed for build)
292
147
  installDashboardDeps();
293
148
 
294
- // Skip tmux install in CI environments where tmux isn't needed
149
+ // Skip tmux check in CI environments
295
150
  if (process.env.CI === 'true') {
296
- info('Skipping tmux install in CI environment');
297
151
  return;
298
152
  }
299
153
 
@@ -303,12 +157,14 @@ async function main() {
303
157
  return;
304
158
  }
305
159
 
306
- // Try to install bundled tmux
307
- await installTmux();
160
+ // Recommend user installs tmux manually
161
+ warn('tmux not found on system');
162
+ info('To use tmux mode, install tmux:');
163
+ info(' macOS: brew install tmux');
164
+ info(' Ubuntu: sudo apt install tmux');
165
+ info(' Or use PTY mode via the dashboard (no tmux required)');
308
166
  }
309
167
 
310
168
  main().catch((err) => {
311
- // Don't fail the install if tmux installation fails
312
- // User can still install tmux manually
313
169
  warn(`Postinstall warning: ${err.message}`);
314
170
  });
@@ -0,0 +1,248 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # Test Interactive Terminal Flow
4
+ #
5
+ # This script sets up a Docker environment to test the interactive terminal
6
+ # WITHOUT requiring GitHub OAuth.
7
+ #
8
+ # Usage:
9
+ # ./scripts/test-interactive-terminal.sh [command]
10
+ #
11
+ # Commands:
12
+ # start - Build, start, and auto-setup test user/workspace
13
+ # stop - Stop all containers
14
+ # logs - Show logs
15
+ # rebuild - Rebuild images with code changes
16
+ # clean - Stop and remove all data
17
+ # setup - Just run the test setup (if containers already running)
18
+ #
19
+
20
+ set -euo pipefail
21
+
22
+ COMPOSE_FILE="docker-compose.dev.yml"
23
+ PROJECT_NAME="agent-relay-dev"
24
+ CLOUD_URL="http://localhost:4567"
25
+
26
+ log() {
27
+ echo -e "\033[1;36m[test-terminal]\033[0m $*"
28
+ }
29
+
30
+ err() {
31
+ echo -e "\033[1;31m[test-terminal]\033[0m $*" >&2
32
+ }
33
+
34
+ success() {
35
+ echo -e "\033[1;32m[test-terminal]\033[0m $*"
36
+ }
37
+
38
+ check_docker() {
39
+ if ! docker info >/dev/null 2>&1; then
40
+ err "Docker is not running. Please start Docker and try again."
41
+ exit 1
42
+ fi
43
+ }
44
+
45
+ wait_for_cloud() {
46
+ log "Waiting for cloud service..."
47
+ for i in {1..30}; do
48
+ if curl -sf "$CLOUD_URL/health" >/dev/null 2>&1; then
49
+ return 0
50
+ fi
51
+ sleep 2
52
+ done
53
+ return 1
54
+ }
55
+
56
+ wait_for_workspace() {
57
+ log "Waiting for workspace service..."
58
+ for i in {1..20}; do
59
+ if curl -sf "http://localhost:3888/health" >/dev/null 2>&1; then
60
+ return 0
61
+ fi
62
+ sleep 2
63
+ done
64
+ return 1
65
+ }
66
+
67
+ # Setup test user and workspace (no OAuth needed!)
68
+ setup_test_environment() {
69
+ log "Setting up test environment (no OAuth required)..."
70
+
71
+ # Create a cookie jar for session
72
+ COOKIE_JAR=$(mktemp)
73
+ trap "rm -f $COOKIE_JAR" EXIT
74
+
75
+ # Step 1: Login as test user
76
+ log "Creating test user and logging in..."
77
+ LOGIN_RESULT=$(curl -sf -X POST "$CLOUD_URL/api/test/login-as" \
78
+ -H "Content-Type: application/json" \
79
+ -d '{"username": "terminal-tester"}' \
80
+ -c "$COOKIE_JAR" 2>&1) || {
81
+ err "Failed to login. Is the cloud service running?"
82
+ err "Response: $LOGIN_RESULT"
83
+ return 1
84
+ }
85
+
86
+ USER_ID=$(echo "$LOGIN_RESULT" | jq -r '.userId // empty')
87
+ if [[ -z "$USER_ID" ]]; then
88
+ err "Failed to get user ID from login response"
89
+ err "Response: $LOGIN_RESULT"
90
+ return 1
91
+ fi
92
+ log "Logged in as user: $USER_ID"
93
+
94
+ # Step 2: Create mock workspace pointing to the Docker workspace
95
+ log "Creating test workspace..."
96
+ WORKSPACE_RESULT=$(curl -sf -X POST "$CLOUD_URL/api/test/create-mock-workspace" \
97
+ -H "Content-Type: application/json" \
98
+ -d '{"name": "Terminal Test Workspace", "publicUrl": "http://workspace:3888"}' \
99
+ -b "$COOKIE_JAR" 2>&1) || {
100
+ err "Failed to create workspace"
101
+ err "Response: $WORKSPACE_RESULT"
102
+ return 1
103
+ }
104
+
105
+ WORKSPACE_ID=$(echo "$WORKSPACE_RESULT" | jq -r '.workspaceId // empty')
106
+ if [[ -z "$WORKSPACE_ID" ]]; then
107
+ err "Failed to get workspace ID"
108
+ err "Response: $WORKSPACE_RESULT"
109
+ return 1
110
+ fi
111
+
112
+ success "Test environment ready!"
113
+ echo ""
114
+ log "=============================================="
115
+ log " Interactive Terminal Test Environment"
116
+ log "=============================================="
117
+ echo ""
118
+ log "Workspace ID: $WORKSPACE_ID"
119
+ echo ""
120
+ log "Test the interactive terminal (auto-login included):"
121
+ echo ""
122
+ echo " Claude: $CLOUD_URL/api/test/auto-login?redirect=/providers/setup/claude?workspace=$WORKSPACE_ID"
123
+ echo ""
124
+ echo " Codex: $CLOUD_URL/api/test/auto-login?redirect=/providers/setup/codex?workspace=$WORKSPACE_ID"
125
+ echo ""
126
+ log "Or access the dashboard:"
127
+ echo ""
128
+ echo " $CLOUD_URL/api/test/auto-login?redirect=/app"
129
+ echo ""
130
+ log "The terminal will show the CLI starting up."
131
+ log "Type directly to interact with prompts."
132
+ log "Auth URLs will trigger a popup modal."
133
+ echo ""
134
+ log "Commands:"
135
+ log " $0 logs - View service logs"
136
+ log " $0 rebuild - Rebuild after code changes"
137
+ log " $0 stop - Stop services"
138
+ log " $0 clean - Remove all data"
139
+ echo ""
140
+ }
141
+
142
+ start_services() {
143
+ check_docker
144
+
145
+ log "Building images with latest code..."
146
+ docker compose -f "$COMPOSE_FILE" build cloud workspace
147
+
148
+ log "Starting services (including workspace)..."
149
+ docker compose -f "$COMPOSE_FILE" --profile workspace up -d
150
+
151
+ if ! wait_for_cloud; then
152
+ err "Cloud service failed to start. Check logs with: $0 logs"
153
+ exit 1
154
+ fi
155
+
156
+ if ! wait_for_workspace; then
157
+ err "Workspace service failed to start. Check logs with: $0 logs"
158
+ exit 1
159
+ fi
160
+
161
+ # Auto-setup test environment
162
+ sleep 2
163
+ setup_test_environment
164
+ }
165
+
166
+ rebuild_services() {
167
+ check_docker
168
+ log "Rebuilding images..."
169
+ docker compose -f "$COMPOSE_FILE" build cloud workspace --no-cache
170
+ log "Restarting services..."
171
+ docker compose -f "$COMPOSE_FILE" --profile workspace up -d
172
+
173
+ if ! wait_for_cloud; then
174
+ err "Cloud service failed to start after rebuild"
175
+ exit 1
176
+ fi
177
+
178
+ if ! wait_for_workspace; then
179
+ err "Workspace service failed to start after rebuild"
180
+ exit 1
181
+ fi
182
+
183
+ sleep 2
184
+ setup_test_environment
185
+ }
186
+
187
+ stop_services() {
188
+ check_docker
189
+ log "Stopping services..."
190
+ docker compose -f "$COMPOSE_FILE" --profile workspace down
191
+ log "Services stopped."
192
+ }
193
+
194
+ show_logs() {
195
+ check_docker
196
+ docker compose -f "$COMPOSE_FILE" --profile workspace logs -f
197
+ }
198
+
199
+ clean_all() {
200
+ check_docker
201
+ log "Stopping services and removing volumes..."
202
+ docker compose -f "$COMPOSE_FILE" --profile workspace down -v
203
+ log "Cleaned up."
204
+ }
205
+
206
+ # Main
207
+ cd "$(dirname "$0")/.."
208
+
209
+ case "${1:-start}" in
210
+ start)
211
+ start_services
212
+ ;;
213
+ stop)
214
+ stop_services
215
+ ;;
216
+ logs)
217
+ show_logs
218
+ ;;
219
+ rebuild)
220
+ rebuild_services
221
+ ;;
222
+ clean)
223
+ clean_all
224
+ ;;
225
+ setup)
226
+ # Just run setup (containers must be running)
227
+ if ! curl -sf "$CLOUD_URL/health" >/dev/null 2>&1; then
228
+ err "Cloud service not running. Use '$0 start' first."
229
+ exit 1
230
+ fi
231
+ setup_test_environment
232
+ ;;
233
+ help|--help|-h)
234
+ echo "Usage: $0 {start|stop|logs|rebuild|clean|setup|help}"
235
+ echo ""
236
+ echo "Commands:"
237
+ echo " start - Build, start, and auto-setup test environment"
238
+ echo " stop - Stop all containers"
239
+ echo " logs - Show service logs"
240
+ echo " rebuild - Rebuild images and restart"
241
+ echo " clean - Stop and remove all data"
242
+ echo " setup - Re-run test setup (if already running)"
243
+ ;;
244
+ *)
245
+ echo "Usage: $0 {start|stop|logs|rebuild|clean|setup|help}"
246
+ exit 1
247
+ ;;
248
+ esac
@@ -1,76 +0,0 @@
1
- /**
2
- * Agent Relay Cloud - Credential Vault
3
- *
4
- * Secure storage for OAuth tokens with AES-256-GCM encryption.
5
- */
6
- export interface StoredCredential {
7
- userId: string;
8
- provider: string;
9
- accessToken: string;
10
- refreshToken?: string;
11
- tokenExpiresAt?: Date;
12
- scopes?: string[];
13
- providerAccountId?: string;
14
- providerAccountEmail?: string;
15
- }
16
- export interface DecryptedCredential {
17
- accessToken: string;
18
- refreshToken?: string;
19
- tokenExpiresAt?: Date;
20
- scopes?: string[];
21
- providerAccountId?: string;
22
- providerAccountEmail?: string;
23
- }
24
- export declare class CredentialVault {
25
- private masterKey;
26
- constructor();
27
- /**
28
- * Encrypt a string value
29
- */
30
- private encrypt;
31
- /**
32
- * Decrypt a string value
33
- */
34
- private decrypt;
35
- /**
36
- * Store encrypted credential
37
- */
38
- storeCredential(credential: StoredCredential): Promise<void>;
39
- /**
40
- * Retrieve and decrypt credential
41
- */
42
- getCredential(userId: string, provider: string): Promise<DecryptedCredential | null>;
43
- /**
44
- * Get all credentials for a user (decrypted)
45
- */
46
- getUserCredentials(userId: string): Promise<Map<string, DecryptedCredential>>;
47
- /**
48
- * Update tokens (e.g., after refresh)
49
- */
50
- updateTokens(userId: string, provider: string, accessToken: string, refreshToken?: string, expiresAt?: Date): Promise<void>;
51
- /**
52
- * Delete credential
53
- */
54
- deleteCredential(userId: string, provider: string): Promise<void>;
55
- /**
56
- * Check if credential needs refresh (within 5 minutes of expiry)
57
- */
58
- needsRefresh(userId: string, provider: string): Promise<boolean>;
59
- /**
60
- * Refresh OAuth token for a provider
61
- */
62
- refreshToken(userId: string, provider: string): Promise<boolean>;
63
- }
64
- export declare function getVault(): CredentialVault;
65
- export declare const vault: {
66
- readonly instance: CredentialVault;
67
- storeCredential: (cred: StoredCredential) => Promise<void>;
68
- getCredential: (userId: string, provider: string) => Promise<DecryptedCredential | null>;
69
- getUserCredentials: (userId: string) => Promise<Map<string, DecryptedCredential>>;
70
- updateTokens: (userId: string, provider: string, accessToken: string, refreshToken?: string, expiresAt?: Date) => Promise<void>;
71
- deleteCredential: (userId: string, provider: string) => Promise<void>;
72
- needsRefresh: (userId: string, provider: string) => Promise<boolean>;
73
- refreshToken: (userId: string, provider: string) => Promise<boolean>;
74
- };
75
- export declare function generateMasterKey(): string;
76
- //# sourceMappingURL=index.d.ts.map