@agent-relay/cloud 2.0.23 → 6.0.4

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 (301) hide show
  1. package/dist/api-client.d.ts +33 -0
  2. package/dist/api-client.d.ts.map +1 -0
  3. package/dist/api-client.js +123 -0
  4. package/dist/api-client.js.map +1 -0
  5. package/dist/auth.d.ts +13 -0
  6. package/dist/auth.d.ts.map +1 -0
  7. package/dist/auth.js +299 -0
  8. package/dist/auth.js.map +1 -0
  9. package/dist/connect.d.ts +45 -0
  10. package/dist/connect.d.ts.map +1 -0
  11. package/dist/connect.js +166 -0
  12. package/dist/connect.js.map +1 -0
  13. package/dist/index.d.ts +7 -10
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +7 -37
  16. package/dist/index.js.map +1 -1
  17. package/dist/lib/ssh-interactive.d.ts +70 -0
  18. package/dist/lib/ssh-interactive.d.ts.map +1 -0
  19. package/dist/lib/ssh-interactive.js +440 -0
  20. package/dist/lib/ssh-interactive.js.map +1 -0
  21. package/dist/lib/ssh-runtime.d.ts +35 -0
  22. package/dist/lib/ssh-runtime.d.ts.map +1 -0
  23. package/dist/lib/ssh-runtime.js +52 -0
  24. package/dist/lib/ssh-runtime.js.map +1 -0
  25. package/dist/types.d.ts +76 -0
  26. package/dist/types.d.ts.map +1 -0
  27. package/dist/types.js +12 -0
  28. package/dist/types.js.map +1 -0
  29. package/dist/workflows.d.ts +49 -0
  30. package/dist/workflows.d.ts.map +1 -0
  31. package/dist/workflows.js +473 -0
  32. package/dist/workflows.js.map +1 -0
  33. package/package.json +12 -25
  34. package/dist/api/admin.d.ts +0 -8
  35. package/dist/api/admin.d.ts.map +0 -1
  36. package/dist/api/admin.js +0 -225
  37. package/dist/api/admin.js.map +0 -1
  38. package/dist/api/auth.d.ts +0 -20
  39. package/dist/api/auth.d.ts.map +0 -1
  40. package/dist/api/auth.js +0 -138
  41. package/dist/api/auth.js.map +0 -1
  42. package/dist/api/billing.d.ts +0 -7
  43. package/dist/api/billing.d.ts.map +0 -1
  44. package/dist/api/billing.js +0 -564
  45. package/dist/api/billing.js.map +0 -1
  46. package/dist/api/cli-pty-runner.d.ts +0 -53
  47. package/dist/api/cli-pty-runner.d.ts.map +0 -1
  48. package/dist/api/cli-pty-runner.js +0 -175
  49. package/dist/api/cli-pty-runner.js.map +0 -1
  50. package/dist/api/codex-auth-helper.d.ts +0 -21
  51. package/dist/api/codex-auth-helper.d.ts.map +0 -1
  52. package/dist/api/codex-auth-helper.js +0 -327
  53. package/dist/api/codex-auth-helper.js.map +0 -1
  54. package/dist/api/consensus.d.ts +0 -13
  55. package/dist/api/consensus.d.ts.map +0 -1
  56. package/dist/api/consensus.js +0 -261
  57. package/dist/api/consensus.js.map +0 -1
  58. package/dist/api/coordinators.d.ts +0 -8
  59. package/dist/api/coordinators.d.ts.map +0 -1
  60. package/dist/api/coordinators.js +0 -750
  61. package/dist/api/coordinators.js.map +0 -1
  62. package/dist/api/daemons.d.ts +0 -12
  63. package/dist/api/daemons.d.ts.map +0 -1
  64. package/dist/api/daemons.js +0 -535
  65. package/dist/api/daemons.js.map +0 -1
  66. package/dist/api/email-auth.d.ts +0 -11
  67. package/dist/api/email-auth.d.ts.map +0 -1
  68. package/dist/api/email-auth.js +0 -347
  69. package/dist/api/email-auth.js.map +0 -1
  70. package/dist/api/generic-webhooks.d.ts +0 -8
  71. package/dist/api/generic-webhooks.d.ts.map +0 -1
  72. package/dist/api/generic-webhooks.js +0 -129
  73. package/dist/api/generic-webhooks.js.map +0 -1
  74. package/dist/api/git.d.ts +0 -8
  75. package/dist/api/git.d.ts.map +0 -1
  76. package/dist/api/git.js +0 -269
  77. package/dist/api/git.js.map +0 -1
  78. package/dist/api/github-app.d.ts +0 -11
  79. package/dist/api/github-app.d.ts.map +0 -1
  80. package/dist/api/github-app.js +0 -223
  81. package/dist/api/github-app.js.map +0 -1
  82. package/dist/api/middleware/planLimits.d.ts +0 -43
  83. package/dist/api/middleware/planLimits.d.ts.map +0 -1
  84. package/dist/api/middleware/planLimits.js +0 -202
  85. package/dist/api/middleware/planLimits.js.map +0 -1
  86. package/dist/api/monitoring.d.ts +0 -11
  87. package/dist/api/monitoring.d.ts.map +0 -1
  88. package/dist/api/monitoring.js +0 -578
  89. package/dist/api/monitoring.js.map +0 -1
  90. package/dist/api/nango-auth.d.ts +0 -9
  91. package/dist/api/nango-auth.d.ts.map +0 -1
  92. package/dist/api/nango-auth.js +0 -741
  93. package/dist/api/nango-auth.js.map +0 -1
  94. package/dist/api/onboarding.d.ts +0 -15
  95. package/dist/api/onboarding.d.ts.map +0 -1
  96. package/dist/api/onboarding.js +0 -679
  97. package/dist/api/onboarding.js.map +0 -1
  98. package/dist/api/policy.d.ts +0 -8
  99. package/dist/api/policy.d.ts.map +0 -1
  100. package/dist/api/policy.js +0 -229
  101. package/dist/api/policy.js.map +0 -1
  102. package/dist/api/provider-env.d.ts +0 -26
  103. package/dist/api/provider-env.d.ts.map +0 -1
  104. package/dist/api/provider-env.js +0 -141
  105. package/dist/api/provider-env.js.map +0 -1
  106. package/dist/api/providers.d.ts +0 -7
  107. package/dist/api/providers.d.ts.map +0 -1
  108. package/dist/api/providers.js +0 -574
  109. package/dist/api/providers.js.map +0 -1
  110. package/dist/api/repos.d.ts +0 -8
  111. package/dist/api/repos.d.ts.map +0 -1
  112. package/dist/api/repos.js +0 -577
  113. package/dist/api/repos.js.map +0 -1
  114. package/dist/api/sessions.d.ts +0 -11
  115. package/dist/api/sessions.d.ts.map +0 -1
  116. package/dist/api/sessions.js +0 -302
  117. package/dist/api/sessions.js.map +0 -1
  118. package/dist/api/teams.d.ts +0 -7
  119. package/dist/api/teams.d.ts.map +0 -1
  120. package/dist/api/teams.js +0 -281
  121. package/dist/api/teams.js.map +0 -1
  122. package/dist/api/test-helpers.d.ts +0 -10
  123. package/dist/api/test-helpers.d.ts.map +0 -1
  124. package/dist/api/test-helpers.js +0 -745
  125. package/dist/api/test-helpers.js.map +0 -1
  126. package/dist/api/usage.d.ts +0 -7
  127. package/dist/api/usage.d.ts.map +0 -1
  128. package/dist/api/usage.js +0 -111
  129. package/dist/api/usage.js.map +0 -1
  130. package/dist/api/webhooks.d.ts +0 -8
  131. package/dist/api/webhooks.d.ts.map +0 -1
  132. package/dist/api/webhooks.js +0 -645
  133. package/dist/api/webhooks.js.map +0 -1
  134. package/dist/api/workspaces.d.ts +0 -25
  135. package/dist/api/workspaces.d.ts.map +0 -1
  136. package/dist/api/workspaces.js +0 -1799
  137. package/dist/api/workspaces.js.map +0 -1
  138. package/dist/billing/index.d.ts +0 -9
  139. package/dist/billing/index.d.ts.map +0 -1
  140. package/dist/billing/index.js +0 -9
  141. package/dist/billing/index.js.map +0 -1
  142. package/dist/billing/plans.d.ts +0 -39
  143. package/dist/billing/plans.d.ts.map +0 -1
  144. package/dist/billing/plans.js +0 -245
  145. package/dist/billing/plans.js.map +0 -1
  146. package/dist/billing/service.d.ts +0 -80
  147. package/dist/billing/service.d.ts.map +0 -1
  148. package/dist/billing/service.js +0 -388
  149. package/dist/billing/service.js.map +0 -1
  150. package/dist/billing/types.d.ts +0 -141
  151. package/dist/billing/types.d.ts.map +0 -1
  152. package/dist/billing/types.js +0 -7
  153. package/dist/billing/types.js.map +0 -1
  154. package/dist/config.d.ts +0 -5
  155. package/dist/config.d.ts.map +0 -1
  156. package/dist/config.js +0 -5
  157. package/dist/config.js.map +0 -1
  158. package/dist/db/bulk-ingest.d.ts +0 -89
  159. package/dist/db/bulk-ingest.d.ts.map +0 -1
  160. package/dist/db/bulk-ingest.js +0 -268
  161. package/dist/db/bulk-ingest.js.map +0 -1
  162. package/dist/db/drizzle.d.ts +0 -290
  163. package/dist/db/drizzle.d.ts.map +0 -1
  164. package/dist/db/drizzle.js +0 -1422
  165. package/dist/db/drizzle.js.map +0 -1
  166. package/dist/db/index.d.ts +0 -56
  167. package/dist/db/index.d.ts.map +0 -1
  168. package/dist/db/index.js +0 -70
  169. package/dist/db/index.js.map +0 -1
  170. package/dist/db/schema.d.ts +0 -5117
  171. package/dist/db/schema.d.ts.map +0 -1
  172. package/dist/db/schema.js +0 -656
  173. package/dist/db/schema.js.map +0 -1
  174. package/dist/provisioner/index.d.ts +0 -207
  175. package/dist/provisioner/index.d.ts.map +0 -1
  176. package/dist/provisioner/index.js +0 -2118
  177. package/dist/provisioner/index.js.map +0 -1
  178. package/dist/server.d.ts +0 -17
  179. package/dist/server.d.ts.map +0 -1
  180. package/dist/server.js +0 -2055
  181. package/dist/server.js.map +0 -1
  182. package/dist/services/auto-scaler.d.ts +0 -152
  183. package/dist/services/auto-scaler.d.ts.map +0 -1
  184. package/dist/services/auto-scaler.js +0 -439
  185. package/dist/services/auto-scaler.js.map +0 -1
  186. package/dist/services/capacity-manager.d.ts +0 -148
  187. package/dist/services/capacity-manager.d.ts.map +0 -1
  188. package/dist/services/capacity-manager.js +0 -449
  189. package/dist/services/capacity-manager.js.map +0 -1
  190. package/dist/services/ci-agent-spawner.d.ts +0 -49
  191. package/dist/services/ci-agent-spawner.d.ts.map +0 -1
  192. package/dist/services/ci-agent-spawner.js +0 -373
  193. package/dist/services/ci-agent-spawner.js.map +0 -1
  194. package/dist/services/cloud-message-bus.d.ts +0 -28
  195. package/dist/services/cloud-message-bus.d.ts.map +0 -1
  196. package/dist/services/cloud-message-bus.js +0 -19
  197. package/dist/services/cloud-message-bus.js.map +0 -1
  198. package/dist/services/compute-enforcement.d.ts +0 -57
  199. package/dist/services/compute-enforcement.d.ts.map +0 -1
  200. package/dist/services/compute-enforcement.js +0 -175
  201. package/dist/services/compute-enforcement.js.map +0 -1
  202. package/dist/services/coordinator.d.ts +0 -62
  203. package/dist/services/coordinator.d.ts.map +0 -1
  204. package/dist/services/coordinator.js +0 -389
  205. package/dist/services/coordinator.js.map +0 -1
  206. package/dist/services/index.d.ts +0 -17
  207. package/dist/services/index.d.ts.map +0 -1
  208. package/dist/services/index.js +0 -25
  209. package/dist/services/index.js.map +0 -1
  210. package/dist/services/intro-expiration.d.ts +0 -60
  211. package/dist/services/intro-expiration.d.ts.map +0 -1
  212. package/dist/services/intro-expiration.js +0 -252
  213. package/dist/services/intro-expiration.js.map +0 -1
  214. package/dist/services/mention-handler.d.ts +0 -65
  215. package/dist/services/mention-handler.d.ts.map +0 -1
  216. package/dist/services/mention-handler.js +0 -405
  217. package/dist/services/mention-handler.js.map +0 -1
  218. package/dist/services/nango.d.ts +0 -219
  219. package/dist/services/nango.d.ts.map +0 -1
  220. package/dist/services/nango.js +0 -424
  221. package/dist/services/nango.js.map +0 -1
  222. package/dist/services/persistence.d.ts +0 -131
  223. package/dist/services/persistence.d.ts.map +0 -1
  224. package/dist/services/persistence.js +0 -200
  225. package/dist/services/persistence.js.map +0 -1
  226. package/dist/services/planLimits.d.ts +0 -147
  227. package/dist/services/planLimits.d.ts.map +0 -1
  228. package/dist/services/planLimits.js +0 -335
  229. package/dist/services/planLimits.js.map +0 -1
  230. package/dist/services/presence-registry.d.ts +0 -56
  231. package/dist/services/presence-registry.d.ts.map +0 -1
  232. package/dist/services/presence-registry.js +0 -91
  233. package/dist/services/presence-registry.js.map +0 -1
  234. package/dist/services/scaling-orchestrator.d.ts +0 -159
  235. package/dist/services/scaling-orchestrator.d.ts.map +0 -1
  236. package/dist/services/scaling-orchestrator.js +0 -502
  237. package/dist/services/scaling-orchestrator.js.map +0 -1
  238. package/dist/services/scaling-policy.d.ts +0 -121
  239. package/dist/services/scaling-policy.d.ts.map +0 -1
  240. package/dist/services/scaling-policy.js +0 -415
  241. package/dist/services/scaling-policy.js.map +0 -1
  242. package/dist/services/ssh-security.d.ts +0 -31
  243. package/dist/services/ssh-security.d.ts.map +0 -1
  244. package/dist/services/ssh-security.js +0 -63
  245. package/dist/services/ssh-security.js.map +0 -1
  246. package/dist/services/workspace-keepalive.d.ts +0 -76
  247. package/dist/services/workspace-keepalive.d.ts.map +0 -1
  248. package/dist/services/workspace-keepalive.js +0 -234
  249. package/dist/services/workspace-keepalive.js.map +0 -1
  250. package/dist/shims/consensus.d.ts +0 -23
  251. package/dist/shims/consensus.d.ts.map +0 -1
  252. package/dist/shims/consensus.js +0 -5
  253. package/dist/shims/consensus.js.map +0 -1
  254. package/dist/webhooks/index.d.ts +0 -24
  255. package/dist/webhooks/index.d.ts.map +0 -1
  256. package/dist/webhooks/index.js +0 -29
  257. package/dist/webhooks/index.js.map +0 -1
  258. package/dist/webhooks/parsers/github.d.ts +0 -8
  259. package/dist/webhooks/parsers/github.d.ts.map +0 -1
  260. package/dist/webhooks/parsers/github.js +0 -234
  261. package/dist/webhooks/parsers/github.js.map +0 -1
  262. package/dist/webhooks/parsers/index.d.ts +0 -23
  263. package/dist/webhooks/parsers/index.d.ts.map +0 -1
  264. package/dist/webhooks/parsers/index.js +0 -30
  265. package/dist/webhooks/parsers/index.js.map +0 -1
  266. package/dist/webhooks/parsers/linear.d.ts +0 -9
  267. package/dist/webhooks/parsers/linear.d.ts.map +0 -1
  268. package/dist/webhooks/parsers/linear.js +0 -258
  269. package/dist/webhooks/parsers/linear.js.map +0 -1
  270. package/dist/webhooks/parsers/slack.d.ts +0 -9
  271. package/dist/webhooks/parsers/slack.d.ts.map +0 -1
  272. package/dist/webhooks/parsers/slack.js +0 -214
  273. package/dist/webhooks/parsers/slack.js.map +0 -1
  274. package/dist/webhooks/responders/github.d.ts +0 -8
  275. package/dist/webhooks/responders/github.d.ts.map +0 -1
  276. package/dist/webhooks/responders/github.js +0 -73
  277. package/dist/webhooks/responders/github.js.map +0 -1
  278. package/dist/webhooks/responders/index.d.ts +0 -23
  279. package/dist/webhooks/responders/index.d.ts.map +0 -1
  280. package/dist/webhooks/responders/index.js +0 -30
  281. package/dist/webhooks/responders/index.js.map +0 -1
  282. package/dist/webhooks/responders/linear.d.ts +0 -9
  283. package/dist/webhooks/responders/linear.d.ts.map +0 -1
  284. package/dist/webhooks/responders/linear.js +0 -149
  285. package/dist/webhooks/responders/linear.js.map +0 -1
  286. package/dist/webhooks/responders/slack.d.ts +0 -20
  287. package/dist/webhooks/responders/slack.d.ts.map +0 -1
  288. package/dist/webhooks/responders/slack.js +0 -178
  289. package/dist/webhooks/responders/slack.js.map +0 -1
  290. package/dist/webhooks/router.d.ts +0 -25
  291. package/dist/webhooks/router.d.ts.map +0 -1
  292. package/dist/webhooks/router.js +0 -504
  293. package/dist/webhooks/router.js.map +0 -1
  294. package/dist/webhooks/rules-engine.d.ts +0 -24
  295. package/dist/webhooks/rules-engine.d.ts.map +0 -1
  296. package/dist/webhooks/rules-engine.js +0 -287
  297. package/dist/webhooks/rules-engine.js.map +0 -1
  298. package/dist/webhooks/types.d.ts +0 -186
  299. package/dist/webhooks/types.d.ts.map +0 -1
  300. package/dist/webhooks/types.js +0 -8
  301. package/dist/webhooks/types.js.map +0 -1
@@ -1,745 +0,0 @@
1
- /**
2
- * Test Helper API Routes
3
- *
4
- * These endpoints are ONLY available in test/development mode.
5
- * They allow integration tests to create users and daemons without OAuth.
6
- *
7
- * IMPORTANT: These routes are disabled in production (NODE_ENV=production).
8
- */
9
- import { Router } from 'express';
10
- import { randomUUID, createHash, randomBytes } from 'crypto';
11
- import { getDb } from '../db/drizzle.js';
12
- import { users, linkedDaemons, workspaces, repositories } from '../db/schema.js';
13
- import { getProvisioner } from '../provisioner/index.js';
14
- import { db } from '../db/index.js';
15
- import { nangoService } from '../services/nango.js';
16
- export const testHelpersRouter = Router();
17
- // Only enable in test/development mode
18
- const isTestMode = process.env.NODE_ENV !== 'production';
19
- if (!isTestMode) {
20
- console.warn('[test-helpers] Test helper routes are disabled in production');
21
- }
22
- /**
23
- * POST /api/test/create-user
24
- * Creates a test user without OAuth
25
- */
26
- testHelpersRouter.post('/create-user', async (req, res) => {
27
- if (!isTestMode) {
28
- return res.status(403).json({ error: 'Test endpoints disabled in production' });
29
- }
30
- try {
31
- const { email, name } = req.body;
32
- const db = getDb();
33
- const testId = `test-${randomUUID()}`;
34
- // Create user with required GitHub fields
35
- const [user] = await db.insert(users).values({
36
- email: email || `${testId}@test.local`,
37
- githubId: testId,
38
- githubUsername: name || 'test-user',
39
- avatarUrl: null,
40
- }).returning();
41
- // Create session
42
- const sessionId = randomUUID();
43
- req.session.userId = user.id;
44
- // Get session cookie (simplified for testing)
45
- const sessionCookie = `connect.sid=s%3A${sessionId}`;
46
- res.json({
47
- userId: user.id,
48
- email: user.email,
49
- sessionCookie,
50
- });
51
- }
52
- catch (error) {
53
- console.error('Error creating test user:', error);
54
- res.status(500).json({ error: 'Failed to create test user' });
55
- }
56
- });
57
- /**
58
- * POST /api/test/create-daemon
59
- * Creates a test daemon with API key
60
- */
61
- testHelpersRouter.post('/create-daemon', async (req, res) => {
62
- if (!isTestMode) {
63
- return res.status(403).json({ error: 'Test endpoints disabled in production' });
64
- }
65
- try {
66
- const { name, machineId } = req.body;
67
- if (!name) {
68
- return res.status(400).json({ error: 'name is required' });
69
- }
70
- const db = getDb();
71
- // First, ensure we have a test user to associate with the daemon
72
- let [testUser] = await db.select().from(users).limit(1);
73
- if (!testUser) {
74
- // Create a test user if none exists
75
- const testId = `test-system-${randomUUID()}`;
76
- [testUser] = await db.insert(users).values({
77
- email: `${testId}@test.local`,
78
- githubId: testId,
79
- githubUsername: 'test-system-user',
80
- avatarUrl: null,
81
- }).returning();
82
- }
83
- // Generate API key
84
- const apiKey = `ar_live_${randomBytes(32).toString('hex')}`;
85
- const apiKeyHash = createHash('sha256').update(apiKey).digest('hex');
86
- // Create daemon - only include fields that exist in schema
87
- const [daemon] = await db.insert(linkedDaemons).values({
88
- userId: testUser.id,
89
- name,
90
- machineId: machineId || randomUUID(),
91
- apiKeyHash,
92
- status: 'online',
93
- metadata: {
94
- hostname: 'test-host',
95
- platform: 'linux',
96
- version: '1.0.0-test',
97
- },
98
- }).returning();
99
- res.json({
100
- daemonId: daemon.id,
101
- apiKey,
102
- name: daemon.name,
103
- machineId: daemon.machineId,
104
- });
105
- }
106
- catch (error) {
107
- console.error('Error creating test daemon:', error);
108
- res.status(500).json({ error: 'Failed to create test daemon' });
109
- }
110
- });
111
- /**
112
- * POST /api/test/create-workspace
113
- * Creates a test workspace for integration tests with optional linked repository
114
- */
115
- testHelpersRouter.post('/create-workspace', async (req, res) => {
116
- if (!isTestMode) {
117
- return res.status(403).json({ error: 'Test endpoints disabled in production' });
118
- }
119
- try {
120
- const { name, repoFullName, userId: providedUserId } = req.body;
121
- const db = getDb();
122
- // Use provided userId, session userId, or create a test user
123
- let targetUserId = providedUserId || req.session.userId;
124
- if (!targetUserId) {
125
- // Create a test user if none exists
126
- const testId = `test-ws-${randomUUID()}`;
127
- const [newUser] = await db.insert(users).values({
128
- email: `${testId}@test.local`,
129
- githubId: testId,
130
- githubUsername: 'workspace-test-user',
131
- avatarUrl: null,
132
- plan: 'free',
133
- }).returning();
134
- targetUserId = newUser.id;
135
- }
136
- const targetRepoFullName = repoFullName || `test-org/test-repo-${Date.now()}`;
137
- // Create workspace
138
- const [workspace] = await db.insert(workspaces).values({
139
- userId: targetUserId,
140
- name: name || `Test Workspace ${Date.now()}`,
141
- status: 'running',
142
- publicUrl: 'http://localhost:3889',
143
- computeProvider: 'docker',
144
- computeId: `test-${randomUUID().slice(0, 8)}`,
145
- config: {
146
- providers: ['anthropic'],
147
- repositories: [targetRepoFullName],
148
- supervisorEnabled: true,
149
- maxAgents: 10,
150
- },
151
- }).returning();
152
- // Create a linked repository for workspace lookup via repoFullName
153
- const [repo] = await db.insert(repositories).values({
154
- userId: targetUserId,
155
- workspaceId: workspace.id,
156
- githubId: Math.floor(Math.random() * 1000000),
157
- githubFullName: targetRepoFullName,
158
- isPrivate: false,
159
- defaultBranch: 'main',
160
- syncStatus: 'synced',
161
- nangoConnectionId: `mock-${randomUUID().slice(0, 8)}`,
162
- lastSyncedAt: new Date(),
163
- }).returning();
164
- res.json({
165
- workspaceId: workspace.id,
166
- name: workspace.name,
167
- repoFullName: repo.githubFullName,
168
- repoId: repo.id,
169
- userId: targetUserId,
170
- });
171
- }
172
- catch (error) {
173
- console.error('Error creating test workspace:', error);
174
- res.status(500).json({ error: 'Failed to create test workspace' });
175
- }
176
- });
177
- /**
178
- * POST /api/test/create-daemon-with-workspace
179
- * Creates a test daemon linked to a workspace
180
- */
181
- testHelpersRouter.post('/create-daemon-with-workspace', async (req, res) => {
182
- if (!isTestMode) {
183
- return res.status(403).json({ error: 'Test endpoints disabled in production' });
184
- }
185
- try {
186
- const { name, machineId, workspaceId, userId: providedUserId } = req.body;
187
- if (!name) {
188
- return res.status(400).json({ error: 'name is required' });
189
- }
190
- const db = getDb();
191
- // Get or create test user
192
- let targetUserId = providedUserId;
193
- if (!targetUserId) {
194
- const existingUsers = await db.select().from(users).limit(1);
195
- if (existingUsers.length > 0) {
196
- targetUserId = existingUsers[0].id;
197
- }
198
- else {
199
- const testId = `test-daemon-${randomUUID()}`;
200
- const [newUser] = await db.insert(users).values({
201
- email: `${testId}@test.local`,
202
- githubId: testId,
203
- githubUsername: 'daemon-test-user',
204
- avatarUrl: null,
205
- plan: 'free',
206
- }).returning();
207
- targetUserId = newUser.id;
208
- }
209
- }
210
- // Generate API key
211
- const apiKey = `ar_live_${randomBytes(32).toString('hex')}`;
212
- const apiKeyHash = createHash('sha256').update(apiKey).digest('hex');
213
- // Create daemon with optional workspace link
214
- const [daemon] = await db.insert(linkedDaemons).values({
215
- userId: targetUserId,
216
- workspaceId: workspaceId || null,
217
- name,
218
- machineId: machineId || randomUUID(),
219
- apiKeyHash,
220
- status: 'online',
221
- metadata: {
222
- hostname: 'test-host',
223
- platform: 'linux',
224
- version: '1.0.0-test',
225
- },
226
- }).returning();
227
- res.json({
228
- daemonId: daemon.id,
229
- apiKey,
230
- name: daemon.name,
231
- machineId: daemon.machineId,
232
- workspaceId: daemon.workspaceId,
233
- userId: targetUserId,
234
- });
235
- }
236
- catch (error) {
237
- console.error('Error creating test daemon:', error);
238
- res.status(500).json({ error: 'Failed to create test daemon' });
239
- }
240
- });
241
- /**
242
- * DELETE /api/test/cleanup
243
- * Cleans up test data
244
- */
245
- testHelpersRouter.delete('/cleanup', async (req, res) => {
246
- if (!isTestMode) {
247
- return res.status(403).json({ error: 'Test endpoints disabled in production' });
248
- }
249
- try {
250
- const _db = getDb();
251
- // Delete test data (users with test- prefix in githubId)
252
- // Note: This cascades to linked daemons due to FK constraints
253
- res.json({ success: true, message: 'Test data cleaned up' });
254
- }
255
- catch (error) {
256
- console.error('Error cleaning up test data:', error);
257
- res.status(500).json({ error: 'Failed to cleanup test data' });
258
- }
259
- });
260
- /**
261
- * GET /api/test/status
262
- * Returns test mode status
263
- */
264
- testHelpersRouter.get('/status', (req, res) => {
265
- res.json({
266
- testMode: isTestMode,
267
- nodeEnv: process.env.NODE_ENV,
268
- timestamp: new Date().toISOString(),
269
- });
270
- });
271
- /**
272
- * POST /api/test/create-mock-workspace
273
- * Creates a mock workspace pointing to a local dashboard server
274
- *
275
- * Use this to test the cloud flow locally without real provisioning.
276
- * The workspace will have publicUrl pointing to localhost:3889.
277
- */
278
- testHelpersRouter.post('/create-mock-workspace', async (req, res) => {
279
- if (!isTestMode) {
280
- return res.status(403).json({ error: 'Test endpoints disabled in production' });
281
- }
282
- try {
283
- const { name, publicUrl } = req.body;
284
- const userId = req.session.userId;
285
- if (!userId) {
286
- return res.status(401).json({ error: 'Must be logged in. Use /api/test/create-user first or log in via OAuth.' });
287
- }
288
- const db = getDb();
289
- // Create a mock workspace with local publicUrl
290
- const [workspace] = await db.insert(workspaces).values({
291
- userId,
292
- name: name || 'Local Test Workspace',
293
- status: 'running',
294
- publicUrl: publicUrl || 'http://localhost:3889',
295
- computeProvider: 'docker',
296
- computeId: `mock-${randomUUID().slice(0, 8)}`,
297
- config: {
298
- providers: ['anthropic'],
299
- repositories: [],
300
- supervisorEnabled: true,
301
- maxAgents: 10,
302
- },
303
- }).returning();
304
- res.json({
305
- workspaceId: workspace.id,
306
- name: workspace.name,
307
- status: workspace.status,
308
- publicUrl: workspace.publicUrl,
309
- message: 'Mock workspace created. Start agent-relay locally and navigate to /app.',
310
- });
311
- }
312
- catch (error) {
313
- console.error('Error creating mock workspace:', error);
314
- res.status(500).json({ error: 'Failed to create mock workspace' });
315
- }
316
- });
317
- /**
318
- * POST /api/test/create-mock-repo
319
- * Creates a mock repository for the current user
320
- *
321
- * Use this to test the cloud flow without connecting real GitHub repos.
322
- */
323
- testHelpersRouter.post('/create-mock-repo', async (req, res) => {
324
- if (!isTestMode) {
325
- return res.status(403).json({ error: 'Test endpoints disabled in production' });
326
- }
327
- try {
328
- const { fullName, isPrivate } = req.body;
329
- const userId = req.session.userId;
330
- if (!userId) {
331
- return res.status(401).json({ error: 'Must be logged in. Use /api/test/create-user first or log in via OAuth.' });
332
- }
333
- if (!fullName) {
334
- return res.status(400).json({ error: 'fullName is required (e.g., "owner/repo")' });
335
- }
336
- const db = getDb();
337
- // Create a mock repository
338
- const [repo] = await db.insert(repositories).values({
339
- userId,
340
- githubId: Math.floor(Math.random() * 1000000),
341
- githubFullName: fullName,
342
- isPrivate: isPrivate ?? false,
343
- defaultBranch: 'main',
344
- syncStatus: 'synced',
345
- nangoConnectionId: `mock-connection-${randomUUID().slice(0, 8)}`,
346
- lastSyncedAt: new Date(),
347
- }).returning();
348
- res.json({
349
- repoId: repo.id,
350
- fullName: repo.githubFullName,
351
- isPrivate: repo.isPrivate,
352
- message: 'Mock repository created.',
353
- });
354
- }
355
- catch (error) {
356
- console.error('Error creating mock repo:', error);
357
- res.status(500).json({ error: 'Failed to create mock repo' });
358
- }
359
- });
360
- /**
361
- * GET /api/test/auto-login
362
- * Browser-friendly auto-login - visit this URL to login and redirect
363
- * Usage: /api/test/auto-login?redirect=/providers/setup/claude?workspace=xxx
364
- */
365
- testHelpersRouter.get('/auto-login', async (req, res) => {
366
- if (!isTestMode) {
367
- return res.status(403).json({ error: 'Test endpoints disabled in production' });
368
- }
369
- try {
370
- const db = getDb();
371
- const redirect = req.query.redirect || '/app';
372
- // Find or create test user
373
- let user;
374
- const existingUsers = await db.select().from(users).limit(1);
375
- if (existingUsers.length > 0) {
376
- user = existingUsers[0];
377
- }
378
- else {
379
- const testId = `test-${randomUUID()}`;
380
- const [newUser] = await db.insert(users).values({
381
- email: `${testId}@test.local`,
382
- githubId: testId,
383
- githubUsername: 'test-user',
384
- avatarUrl: null,
385
- plan: 'free',
386
- }).returning();
387
- user = newUser;
388
- }
389
- // Set session and CSRF token
390
- req.session.userId = user.id;
391
- req.session.csrfToken = randomUUID();
392
- // Redirect to requested page
393
- res.redirect(redirect);
394
- }
395
- catch (error) {
396
- console.error('Error in auto-login:', error);
397
- res.status(500).json({ error: 'Failed to auto-login' });
398
- }
399
- });
400
- /**
401
- * POST /api/test/login-as
402
- * Quick login for testing - creates session for existing or new test user
403
- */
404
- testHelpersRouter.post('/login-as', async (req, res) => {
405
- if (!isTestMode) {
406
- return res.status(403).json({ error: 'Test endpoints disabled in production' });
407
- }
408
- try {
409
- const { username } = req.body;
410
- const db = getDb();
411
- // Find or create user
412
- let user;
413
- const existingUsers = await db.select().from(users).limit(1);
414
- if (existingUsers.length > 0 && !username) {
415
- user = existingUsers[0];
416
- }
417
- else {
418
- const testId = `test-${randomUUID()}`;
419
- const [newUser] = await db.insert(users).values({
420
- email: `${username || testId}@test.local`,
421
- githubId: testId,
422
- githubUsername: username || 'test-user',
423
- avatarUrl: null,
424
- plan: 'free',
425
- }).returning();
426
- user = newUser;
427
- }
428
- // Set session
429
- req.session.userId = user.id;
430
- res.json({
431
- success: true,
432
- userId: user.id,
433
- username: user.githubUsername,
434
- message: 'Logged in. You can now access /app and other authenticated routes.',
435
- });
436
- }
437
- catch (error) {
438
- console.error('Error in login-as:', error);
439
- res.status(500).json({ error: 'Failed to login' });
440
- }
441
- });
442
- /**
443
- * GET /api/test/setup-local-cloud
444
- * One-shot setup: creates user, mock repo, and mock workspace
445
- *
446
- * After calling this, start agent-relay locally and go to /app
447
- */
448
- testHelpersRouter.post('/setup-local-cloud', async (req, res) => {
449
- if (!isTestMode) {
450
- return res.status(403).json({ error: 'Test endpoints disabled in production' });
451
- }
452
- try {
453
- const { repoName, workspaceName } = req.body;
454
- const db = getDb();
455
- // 1. Create or get test user
456
- const testId = `test-${randomUUID().slice(0, 8)}`;
457
- const [user] = await db.insert(users).values({
458
- email: `${testId}@test.local`,
459
- githubId: testId,
460
- githubUsername: 'local-tester',
461
- avatarUrl: null,
462
- plan: 'free',
463
- }).returning();
464
- // Set session
465
- req.session.userId = user.id;
466
- // 2. Create mock repository
467
- const [repo] = await db.insert(repositories).values({
468
- userId: user.id,
469
- githubId: Math.floor(Math.random() * 1000000),
470
- githubFullName: repoName || 'test-org/test-repo',
471
- isPrivate: false,
472
- defaultBranch: 'main',
473
- syncStatus: 'synced',
474
- nangoConnectionId: `mock-${randomUUID().slice(0, 8)}`,
475
- lastSyncedAt: new Date(),
476
- }).returning();
477
- // 3. Create mock workspace pointing to local dashboard
478
- const [workspace] = await db.insert(workspaces).values({
479
- userId: user.id,
480
- name: workspaceName || 'Local Development',
481
- status: 'running',
482
- publicUrl: 'http://localhost:3889',
483
- computeProvider: 'docker',
484
- computeId: `mock-${randomUUID().slice(0, 8)}`,
485
- config: {
486
- providers: ['anthropic'],
487
- repositories: [repo.githubFullName],
488
- supervisorEnabled: true,
489
- maxAgents: 10,
490
- },
491
- }).returning();
492
- res.json({
493
- success: true,
494
- user: {
495
- id: user.id,
496
- username: user.githubUsername,
497
- },
498
- repo: {
499
- id: repo.id,
500
- fullName: repo.githubFullName,
501
- },
502
- workspace: {
503
- id: workspace.id,
504
- name: workspace.name,
505
- publicUrl: workspace.publicUrl,
506
- },
507
- instructions: [
508
- '1. Start agent-relay daemon: npm run dev (or agent-relay up)',
509
- '2. Go to http://localhost:4567/app',
510
- '3. The app should auto-connect to the local workspace',
511
- '4. The WebSocket will connect to ws://localhost:3889/ws',
512
- ],
513
- });
514
- }
515
- catch (error) {
516
- console.error('Error in setup-local-cloud:', error);
517
- res.status(500).json({ error: 'Failed to setup local cloud' });
518
- }
519
- });
520
- /**
521
- * POST /api/test/provision-real-workspace
522
- * Provision a REAL Docker container using your Nango GitHub App connection.
523
- *
524
- * This tests the full flow including:
525
- * - Fetching GitHub App token from Nango
526
- * - Spinning up a Docker container
527
- * - Cloning your actual repositories
528
- *
529
- * Prerequisites:
530
- * - Must be logged in (via real OAuth or /api/test/login-as)
531
- * - Must have connected repos via /connect-repos (real Nango GitHub App OAuth)
532
- * - Docker must be running locally
533
- * - COMPUTE_PROVIDER must be 'docker' (default for dev)
534
- */
535
- testHelpersRouter.post('/provision-real-workspace', async (req, res) => {
536
- if (!isTestMode) {
537
- return res.status(403).json({ error: 'Test endpoints disabled in production' });
538
- }
539
- const userId = req.session.userId;
540
- if (!userId) {
541
- return res.status(401).json({
542
- error: 'Must be logged in. Use real OAuth or /api/test/login-as first.',
543
- });
544
- }
545
- try {
546
- const { name, repositoryFullName, providers, githubToken } = req.body;
547
- // Get user's connected repositories
548
- const userRepos = await db.repositories.findByUserId(userId);
549
- const reposWithNango = userRepos.filter(r => r.nangoConnectionId);
550
- if (reposWithNango.length === 0) {
551
- return res.status(400).json({
552
- error: 'No repositories with Nango connection found. Complete /connect-repos first with real GitHub OAuth.',
553
- hint: 'Go to http://localhost:4567/connect-repos and connect your GitHub App, or pass githubToken directly',
554
- });
555
- }
556
- // Determine which repo to use
557
- let targetRepo = reposWithNango[0];
558
- if (repositoryFullName) {
559
- const found = reposWithNango.find(r => r.githubFullName === repositoryFullName);
560
- if (!found) {
561
- return res.status(400).json({
562
- error: `Repository ${repositoryFullName} not found or not connected via Nango`,
563
- availableRepos: reposWithNango.map(r => r.githubFullName),
564
- });
565
- }
566
- targetRepo = found;
567
- }
568
- // Use the real provisioner (Docker in dev mode)
569
- const provisioner = getProvisioner();
570
- const result = await provisioner.provision({
571
- userId,
572
- name: name || `Test Workspace - ${targetRepo.githubFullName}`,
573
- providers: providers || ['anthropic'], // Default to anthropic if not specified
574
- repositories: [targetRepo.githubFullName],
575
- supervisorEnabled: true,
576
- maxAgents: 10,
577
- // Allow passing GitHub token directly for local testing
578
- githubToken: githubToken || undefined,
579
- });
580
- if (result.status === 'error') {
581
- return res.status(500).json({
582
- error: 'Provisioning failed',
583
- details: result.error,
584
- });
585
- }
586
- res.json({
587
- success: true,
588
- workspace: {
589
- id: result.workspaceId,
590
- status: result.status,
591
- publicUrl: result.publicUrl,
592
- },
593
- repository: targetRepo.githubFullName,
594
- instructions: [
595
- `1. Workspace is running at ${result.publicUrl}`,
596
- `2. Repository ${targetRepo.githubFullName} should be cloned`,
597
- `3. Go to http://localhost:4567/app to connect`,
598
- `4. Check container: docker logs ar-${result.workspaceId.substring(0, 8)}`,
599
- `5. Verify clone: docker exec ar-${result.workspaceId.substring(0, 8)} ls /workspace/repos`,
600
- ],
601
- });
602
- }
603
- catch (error) {
604
- console.error('Error provisioning real workspace:', error);
605
- res.status(500).json({
606
- error: 'Failed to provision workspace',
607
- details: error instanceof Error ? error.message : 'Unknown error',
608
- });
609
- }
610
- });
611
- /**
612
- * GET /api/test/my-repos
613
- * List current user's connected repositories (for debugging)
614
- */
615
- testHelpersRouter.get('/my-repos', async (req, res) => {
616
- if (!isTestMode) {
617
- return res.status(403).json({ error: 'Test endpoints disabled in production' });
618
- }
619
- const userId = req.session.userId;
620
- if (!userId) {
621
- return res.status(401).json({ error: 'Not logged in' });
622
- }
623
- try {
624
- const repos = await db.repositories.findByUserId(userId);
625
- res.json({
626
- userId,
627
- repositories: repos.map(r => ({
628
- id: r.id,
629
- fullName: r.githubFullName,
630
- isPrivate: r.isPrivate,
631
- hasNangoConnection: !!r.nangoConnectionId,
632
- nangoConnectionId: r.nangoConnectionId, // For debugging
633
- syncStatus: r.syncStatus,
634
- })),
635
- });
636
- }
637
- catch (error) {
638
- console.error('Error fetching repos:', error);
639
- res.status(500).json({ error: 'Failed to fetch repositories' });
640
- }
641
- });
642
- /**
643
- * GET /api/test/my-workspaces
644
- * List current user's workspaces (for debugging)
645
- */
646
- testHelpersRouter.get('/my-workspaces', async (req, res) => {
647
- if (!isTestMode) {
648
- return res.status(403).json({ error: 'Test endpoints disabled in production' });
649
- }
650
- const userId = req.session.userId;
651
- if (!userId) {
652
- return res.status(401).json({ error: 'Not logged in' });
653
- }
654
- try {
655
- const userWorkspaces = await db.workspaces.findByUserId(userId);
656
- res.json({
657
- userId,
658
- workspaces: userWorkspaces.map(w => ({
659
- id: w.id,
660
- name: w.name,
661
- status: w.status,
662
- publicUrl: w.publicUrl,
663
- computeProvider: w.computeProvider,
664
- computeId: w.computeId,
665
- config: w.config,
666
- })),
667
- });
668
- }
669
- catch (error) {
670
- console.error('Error fetching workspaces:', error);
671
- res.status(500).json({ error: 'Failed to fetch workspaces' });
672
- }
673
- });
674
- /**
675
- * GET /api/test/nango-token
676
- * Test fetching GitHub App token from Nango (for debugging)
677
- */
678
- testHelpersRouter.get('/nango-token', async (req, res) => {
679
- if (!isTestMode) {
680
- return res.status(403).json({ error: 'Test endpoints disabled in production' });
681
- }
682
- const userId = req.session.userId;
683
- if (!userId) {
684
- return res.status(401).json({ error: 'Not logged in' });
685
- }
686
- try {
687
- const repos = await db.repositories.findByUserId(userId);
688
- const repoWithConnection = repos.find(r => r.nangoConnectionId);
689
- if (!repoWithConnection?.nangoConnectionId) {
690
- return res.status(400).json({
691
- error: 'No Nango connection found',
692
- repos: repos.map(r => ({ fullName: r.githubFullName, nangoConnectionId: r.nangoConnectionId })),
693
- });
694
- }
695
- console.log('[test] Fetching token for connection:', repoWithConnection.nangoConnectionId);
696
- const token = await nangoService.getGithubAppToken(repoWithConnection.nangoConnectionId);
697
- res.json({
698
- success: true,
699
- connectionId: repoWithConnection.nangoConnectionId,
700
- tokenLength: token.length,
701
- tokenPrefix: token.substring(0, 10) + '...',
702
- });
703
- }
704
- catch (error) {
705
- console.error('[test] Nango token fetch error:', error);
706
- res.status(500).json({
707
- error: 'Failed to fetch token',
708
- details: error instanceof Error ? error.message : 'Unknown error',
709
- });
710
- }
711
- });
712
- /**
713
- * DELETE /api/test/workspace/:id
714
- * Delete/deprovision a workspace (for cleanup)
715
- */
716
- testHelpersRouter.delete('/workspace/:id', async (req, res) => {
717
- if (!isTestMode) {
718
- return res.status(403).json({ error: 'Test endpoints disabled in production' });
719
- }
720
- const userId = req.session.userId;
721
- if (!userId) {
722
- return res.status(401).json({ error: 'Not logged in' });
723
- }
724
- try {
725
- const id = req.params.id;
726
- const workspace = await db.workspaces.findById(id);
727
- if (!workspace) {
728
- return res.status(404).json({ error: 'Workspace not found' });
729
- }
730
- if (workspace.userId !== userId) {
731
- return res.status(403).json({ error: 'Not your workspace' });
732
- }
733
- const provisioner = getProvisioner();
734
- await provisioner.deprovision(id);
735
- res.json({
736
- success: true,
737
- message: `Workspace ${id} deleted`,
738
- });
739
- }
740
- catch (error) {
741
- console.error('Error deleting workspace:', error);
742
- res.status(500).json({ error: 'Failed to delete workspace' });
743
- }
744
- });
745
- //# sourceMappingURL=test-helpers.js.map