agent-relay 2.0.16 → 2.0.18

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 (153) hide show
  1. package/deploy/workspace/entrypoint.sh +35 -19
  2. package/deploy/workspace/git-credential-relay +82 -7
  3. package/dist/dashboard/out/404.html +1 -1
  4. package/dist/dashboard/out/_next/static/chunks/320-402ffc8646b31da1.js +1 -0
  5. package/dist/dashboard/out/_next/static/chunks/83-26d2bde54616ee90.js +1 -0
  6. package/{packages/dashboard/ui-dist/_next/static/chunks/app/app/page-9d6bc8729b429956.js → dist/dashboard/out/_next/static/chunks/app/app/page-366fb7c078d4e9e0.js} +1 -1
  7. package/dist/dashboard/out/_next/static/chunks/app/complete-profile/page-dd64bbdf66b639cd.js +1 -0
  8. package/dist/dashboard/out/_next/static/chunks/app/login/page-435eceb0073be027.js +1 -0
  9. package/dist/dashboard/out/_next/static/chunks/app/{page-487fa38f041815c1.js → page-8119d4246743574e.js} +1 -1
  10. package/dist/dashboard/out/_next/static/chunks/app/signup/page-c7a0a28341365ae0.js +1 -0
  11. package/dist/dashboard/out/_next/static/chunks/{main-5a40a5ae29646e1b.js → main-311c3db74dcfadb7.js} +1 -1
  12. package/dist/dashboard/out/_next/static/css/{605dd4e30c91986f.css → 45361ce86b2847c4.css} +1 -1
  13. package/dist/dashboard/out/app/onboarding.html +1 -1
  14. package/dist/dashboard/out/app/onboarding.txt +1 -1
  15. package/dist/dashboard/out/app.html +1 -1
  16. package/dist/dashboard/out/app.txt +2 -2
  17. package/dist/dashboard/out/cloud/link.html +1 -1
  18. package/dist/dashboard/out/cloud/link.txt +1 -1
  19. package/dist/dashboard/out/complete-profile.html +5 -0
  20. package/dist/dashboard/out/complete-profile.txt +7 -0
  21. package/dist/dashboard/out/connect-repos.html +1 -1
  22. package/dist/dashboard/out/connect-repos.txt +1 -1
  23. package/dist/dashboard/out/history.html +1 -1
  24. package/dist/dashboard/out/history.txt +1 -1
  25. package/dist/dashboard/out/index.html +1 -1
  26. package/dist/dashboard/out/index.txt +2 -2
  27. package/dist/dashboard/out/login.html +2 -2
  28. package/dist/dashboard/out/login.txt +2 -2
  29. package/dist/dashboard/out/metrics.html +1 -1
  30. package/dist/dashboard/out/metrics.txt +1 -1
  31. package/dist/dashboard/out/pricing.html +2 -2
  32. package/dist/dashboard/out/pricing.txt +1 -1
  33. package/dist/dashboard/out/providers/setup/claude.html +1 -1
  34. package/dist/dashboard/out/providers/setup/claude.txt +1 -1
  35. package/dist/dashboard/out/providers/setup/codex.html +1 -1
  36. package/dist/dashboard/out/providers/setup/codex.txt +1 -1
  37. package/dist/dashboard/out/providers/setup/cursor.html +1 -1
  38. package/dist/dashboard/out/providers/setup/cursor.txt +1 -1
  39. package/dist/dashboard/out/providers.html +1 -1
  40. package/dist/dashboard/out/providers.txt +2 -2
  41. package/dist/dashboard/out/signup.html +2 -2
  42. package/dist/dashboard/out/signup.txt +2 -2
  43. package/dist/src/cli/index.js +3 -1
  44. package/package.json +22 -21
  45. package/packages/api-types/package.json +1 -1
  46. package/packages/bridge/package.json +8 -8
  47. package/packages/cloud/dist/api/auth.js +2 -0
  48. package/packages/cloud/dist/api/billing.js +4 -4
  49. package/packages/cloud/dist/api/email-auth.d.ts +11 -0
  50. package/packages/cloud/dist/api/email-auth.js +347 -0
  51. package/packages/cloud/dist/api/nango-auth.js +72 -5
  52. package/packages/cloud/dist/db/drizzle.d.ts +35 -1
  53. package/packages/cloud/dist/db/drizzle.js +136 -0
  54. package/packages/cloud/dist/db/index.d.ts +5 -4
  55. package/packages/cloud/dist/db/index.js +5 -3
  56. package/packages/cloud/dist/db/schema.d.ts +246 -2
  57. package/packages/cloud/dist/db/schema.js +39 -3
  58. package/packages/cloud/dist/provisioner/index.js +5 -1
  59. package/packages/cloud/dist/server.js +134 -24
  60. package/packages/cloud/dist/services/nango.d.ts +18 -0
  61. package/packages/cloud/dist/services/nango.js +32 -0
  62. package/packages/cloud/package.json +6 -6
  63. package/packages/config/package.json +2 -2
  64. package/packages/continuity/package.json +1 -1
  65. package/packages/daemon/package.json +12 -12
  66. package/packages/dashboard/dist/server.js +36 -7
  67. package/packages/dashboard/package.json +13 -13
  68. package/packages/dashboard/ui/app/complete-profile/page.tsx +204 -0
  69. package/packages/dashboard/ui/app/login/page.tsx +182 -38
  70. package/packages/dashboard/ui/app/signup/page.tsx +244 -54
  71. package/packages/dashboard/ui/lib/cloudApi.ts +1 -0
  72. package/packages/dashboard/ui/react-components/App.tsx +1 -1
  73. package/packages/dashboard/ui/react-components/ProviderAuthFlow.tsx +10 -0
  74. package/packages/dashboard/ui/react-components/RepoAccessPanel.tsx +160 -3
  75. package/packages/dashboard/ui-dist/404.html +1 -1
  76. package/packages/dashboard/ui-dist/_next/static/chunks/320-402ffc8646b31da1.js +1 -0
  77. package/packages/dashboard/ui-dist/_next/static/chunks/83-26d2bde54616ee90.js +1 -0
  78. package/{dist/dashboard/out/_next/static/chunks/app/app/page-9d6bc8729b429956.js → packages/dashboard/ui-dist/_next/static/chunks/app/app/page-366fb7c078d4e9e0.js} +1 -1
  79. package/packages/dashboard/ui-dist/_next/static/chunks/app/complete-profile/page-dd64bbdf66b639cd.js +1 -0
  80. package/packages/dashboard/ui-dist/_next/static/chunks/app/login/page-435eceb0073be027.js +1 -0
  81. package/packages/dashboard/ui-dist/_next/static/chunks/app/{page-487fa38f041815c1.js → page-8119d4246743574e.js} +1 -1
  82. package/packages/dashboard/ui-dist/_next/static/chunks/app/signup/page-c7a0a28341365ae0.js +1 -0
  83. package/packages/dashboard/ui-dist/_next/static/chunks/{main-5a40a5ae29646e1b.js → main-311c3db74dcfadb7.js} +1 -1
  84. package/packages/dashboard/ui-dist/_next/static/css/{605dd4e30c91986f.css → 45361ce86b2847c4.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 +5 -0
  92. package/packages/dashboard/ui-dist/complete-profile.txt +7 -0
  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 +2 -2
  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 +2 -2
  115. package/packages/dashboard-server/dist/server.js +36 -7
  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/package.json +2 -2
  124. package/packages/spawner/package.json +1 -1
  125. package/packages/state/package.json +1 -1
  126. package/packages/storage/package.json +2 -2
  127. package/packages/telemetry/package.json +1 -1
  128. package/packages/trajectory/package.json +2 -2
  129. package/packages/user-directory/package.json +2 -2
  130. package/packages/utils/package.json +1 -1
  131. package/packages/wrapper/dist/relay-pty-orchestrator.js +17 -3
  132. package/packages/wrapper/package.json +6 -6
  133. package/relay-snippets/agent-policy-snippet.md +40 -0
  134. package/relay-snippets/agent-relay-protocol.md +101 -0
  135. package/relay-snippets/agent-relay-snippet.md +177 -0
  136. package/SESSION_HANDOFF.md +0 -67
  137. package/dist/dashboard/out/_next/static/chunks/320-23e5ffe6aa7eb934.js +0 -1
  138. package/dist/dashboard/out/_next/static/chunks/83-4f08122d4e7e79a6.js +0 -1
  139. package/dist/dashboard/out/_next/static/chunks/app/login/page-a0ca6f7ca6a100b8.js +0 -1
  140. package/dist/dashboard/out/_next/static/chunks/app/signup/page-1ede2205b58649ca.js +0 -1
  141. package/packages/dashboard/ui-dist/_next/static/chunks/320-23e5ffe6aa7eb934.js +0 -1
  142. package/packages/dashboard/ui-dist/_next/static/chunks/83-4f08122d4e7e79a6.js +0 -1
  143. package/packages/dashboard/ui-dist/_next/static/chunks/app/login/page-a0ca6f7ca6a100b8.js +0 -1
  144. package/packages/dashboard/ui-dist/_next/static/chunks/app/signup/page-1ede2205b58649ca.js +0 -1
  145. package/test-push.txt +0 -1
  146. /package/dist/dashboard/out/_next/static/{itBGQ1M8yMA_hC42DKCqv → JIjqkuDKNeoSg7KaMMuhx}/_buildManifest.js +0 -0
  147. /package/dist/dashboard/out/_next/static/{itBGQ1M8yMA_hC42DKCqv → JIjqkuDKNeoSg7KaMMuhx}/_ssgManifest.js +0 -0
  148. /package/packages/dashboard/ui-dist/_next/static/{ML6Zby1B5OtZvl0Pa1zSZ → JIjqkuDKNeoSg7KaMMuhx}/_buildManifest.js +0 -0
  149. /package/packages/dashboard/ui-dist/_next/static/{ML6Zby1B5OtZvl0Pa1zSZ → JIjqkuDKNeoSg7KaMMuhx}/_ssgManifest.js +0 -0
  150. /package/packages/dashboard/ui-dist/_next/static/{Ni5Di0TB0PDcrvEYBFRKd → nmkOi7bqeDmLMoWBih8lz}/_buildManifest.js +0 -0
  151. /package/packages/dashboard/ui-dist/_next/static/{Ni5Di0TB0PDcrvEYBFRKd → nmkOi7bqeDmLMoWBih8lz}/_ssgManifest.js +0 -0
  152. /package/packages/dashboard/ui-dist/_next/static/{itBGQ1M8yMA_hC42DKCqv → wk_gKRNSPpWE-ZhGL6UMl}/_buildManifest.js +0 -0
  153. /package/packages/dashboard/ui-dist/_next/static/{itBGQ1M8yMA_hC42DKCqv → wk_gKRNSPpWE-ZhGL6UMl}/_ssgManifest.js +0 -0
@@ -1,6 +1,6 @@
1
- <!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="/_next/static/css/605dd4e30c91986f.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/webpack-1cdd8ed57114d5e1.js"/><script src="/_next/static/chunks/fd9d1056-609918ca7b6280bb.js" async=""></script><script src="/_next/static/chunks/117-c8afed19e821a35d.js" async=""></script><script src="/_next/static/chunks/main-app-fdbeb09028f57c9f.js" async=""></script><script src="/_next/static/chunks/282-980c2eb8fff20123.js" async=""></script><script src="/_next/static/chunks/app/signup/page-1ede2205b58649ca.js" async=""></script><title>Agent Relay Dashboard</title><meta name="description" content="Fleet control dashboard for Agent Relay"/><link rel="apple-touch-icon" href="/apple-icon.png?9e7a840704165ca6" type="image/png" sizes="256x256"/><script src="/_next/static/chunks/polyfills-42372ed130431b0a.js" noModule=""></script></head><body><div class="min-h-screen bg-gradient-to-br from-[#0a0a0f] via-[#0d1117] to-[#0a0a0f] flex flex-col items-center justify-center p-4"><div class="fixed inset-0 opacity-10"><div class="absolute inset-0" style="background-image:linear-gradient(rgba(0, 217, 255, 0.1) 1px, transparent 1px),
1
+ <!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="/_next/static/css/45361ce86b2847c4.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/webpack-1cdd8ed57114d5e1.js"/><script src="/_next/static/chunks/fd9d1056-609918ca7b6280bb.js" async=""></script><script src="/_next/static/chunks/117-c8afed19e821a35d.js" async=""></script><script src="/_next/static/chunks/main-app-fdbeb09028f57c9f.js" async=""></script><script src="/_next/static/chunks/282-980c2eb8fff20123.js" async=""></script><script src="/_next/static/chunks/app/signup/page-c7a0a28341365ae0.js" async=""></script><title>Agent Relay Dashboard</title><meta name="description" content="Fleet control dashboard for Agent Relay"/><link rel="apple-touch-icon" href="/apple-icon.png?9e7a840704165ca6" type="image/png" sizes="256x256"/><script src="/_next/static/chunks/polyfills-42372ed130431b0a.js" noModule=""></script></head><body><div class="min-h-screen bg-gradient-to-br from-[#0a0a0f] via-[#0d1117] to-[#0a0a0f] flex flex-col items-center justify-center p-4"><div class="fixed inset-0 opacity-10"><div class="absolute inset-0" style="background-image:linear-gradient(rgba(0, 217, 255, 0.1) 1px, transparent 1px),
2
2
  linear-gradient(90deg, rgba(0, 217, 255, 0.1) 1px, transparent 1px);background-size:50px 50px"></div></div><div class="fixed inset-0 overflow-hidden pointer-events-none"><div class="absolute -top-40 -left-40 w-80 h-80 bg-accent-cyan/20 rounded-full blur-[100px]"></div><div class="absolute -bottom-40 -right-40 w-80 h-80 bg-[#00ffc8]/15 rounded-full blur-[100px]"></div></div><div class="relative z-10 w-full max-w-md"><div class="flex flex-col items-center mb-8"><svg width="56" height="56" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg" class="
3
3
  transition-all duration-300
4
4
  drop-shadow-[0_0_8px_rgba(0,217,255,0.3)]
5
5
 
6
- " aria-label="Agent Relay Logo" role="img"><path d="M30 80 L 50 20 L 70 80" stroke="#00d9ff" stroke-width="5" stroke-linejoin="round" stroke-linecap="round" fill="none"></path><line x1="40" y1="50" x2="60" y2="50" stroke="#00d9ff" stroke-width="5" stroke-linecap="round"></line><path d="M50 20 L 50 80" stroke="#00ffc8" stroke-width="2.5" stroke-linecap="round" opacity="0.7"></path><path d="M50 20 C 80 20 80 50 50 50 L 80 80" stroke="#00ffc8" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" fill="none" opacity="0.7"></path></svg><h1 class="mt-4 text-3xl font-bold text-white">Get Started</h1><p class="mt-2 text-text-muted text-center">Create your account and start orchestrating AI agents</p></div><div class="bg-bg-primary/80 backdrop-blur-sm border border-border-subtle rounded-2xl p-8 shadow-xl"><div><div class="mb-6 space-y-3"><div class="flex items-center gap-3 text-sm text-text-secondary"><div class="w-8 h-8 rounded-lg bg-accent-cyan/10 flex items-center justify-center flex-shrink-0"><svg class="w-4 h-4 text-accent-cyan" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path></svg></div><span>Deploy AI agents in seconds</span></div><div class="flex items-center gap-3 text-sm text-text-secondary"><div class="w-8 h-8 rounded-lg bg-[#00ffc8]/10 flex items-center justify-center flex-shrink-0"><svg class="w-4 h-4 text-[#00ffc8]" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"></path></svg></div><span>Real-time agent collaboration</span></div><div class="flex items-center gap-3 text-sm text-text-secondary"><div class="w-8 h-8 rounded-lg bg-[#0891b2]/10 flex items-center justify-center flex-shrink-0"><svg class="w-4 h-4 text-[#0891b2]" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"></path></svg></div><span>Secure credential management</span></div></div><button type="button" disabled="" class="w-full py-4 px-6 bg-[#24292e] hover:bg-[#2f363d] border border-[#444d56] rounded-xl text-white font-medium flex items-center justify-center gap-3 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"><svg class="w-5 h-5 animate-spin" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"></path></svg><span>Loading...</span></button><p class="mt-6 text-center text-text-muted text-sm">By signing up, you agree to our<!-- --> <a href="/terms" class="text-accent-cyan hover:underline">Terms of Service</a> <!-- -->and<!-- --> <a href="/privacy" class="text-accent-cyan hover:underline">Privacy Policy</a></p></div></div><div class="mt-6 text-center"><p class="text-text-muted">Already have an account?<!-- --> <a href="/login" class="text-accent-cyan hover:underline font-medium">Sign in</a></p></div><div class="mt-4 text-center"><a href="/" class="text-text-muted hover:text-white transition-colors text-sm">Back to home</a></div></div></div><script src="/_next/static/chunks/webpack-1cdd8ed57114d5e1.js" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0]);self.__next_f.push([2,null])</script><script>self.__next_f.push([1,"1:HL[\"/_next/static/css/605dd4e30c91986f.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"2:I[2846,[],\"\"]\n4:I[9107,[],\"ClientPageRoot\"]\n5:I[4665,[\"282\",\"static/chunks/282-980c2eb8fff20123.js\",\"966\",\"static/chunks/app/signup/page-1ede2205b58649ca.js\"],\"default\",1]\n6:I[4707,[],\"\"]\n7:I[6423,[],\"\"]\n9:I[1060,[],\"\"]\na:[]\n"])</script><script>self.__next_f.push([1,"0:[\"$\",\"$L2\",null,{\"buildId\":\"itBGQ1M8yMA_hC42DKCqv\",\"assetPrefix\":\"\",\"urlParts\":[\"\",\"signup\"],\"initialTree\":[\"\",{\"children\":[\"signup\",{\"children\":[\"__PAGE__\",{}]}]},\"$undefined\",\"$undefined\",true],\"initialSeedData\":[\"\",{\"children\":[\"signup\",{\"children\":[\"__PAGE__\",{},[[\"$L3\",[\"$\",\"$L4\",null,{\"props\":{\"params\":{},\"searchParams\":{}},\"Component\":\"$5\"}],null],null],null]},[null,[\"$\",\"$L6\",null,{\"parallelRouterKey\":\"children\",\"segmentPath\":[\"children\",\"signup\",\"children\"],\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L7\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"notFoundStyles\":\"$undefined\"}]],null]},[[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/605dd4e30c91986f.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"children\":[\"$\",\"body\",null,{\"children\":[\"$\",\"$L6\",null,{\"parallelRouterKey\":\"children\",\"segmentPath\":[\"children\"],\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L7\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":\"404\"}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],\"notFoundStyles\":[]}]}]}]],null],null],\"couldBeIntercepted\":false,\"initialHead\":[null,\"$L8\"],\"globalErrorComponent\":\"$9\",\"missingSlots\":\"$Wa\"}]\n"])</script><script>self.__next_f.push([1,"8:[[\"$\",\"meta\",\"0\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}],[\"$\",\"meta\",\"1\",{\"charSet\":\"utf-8\"}],[\"$\",\"title\",\"2\",{\"children\":\"Agent Relay Dashboard\"}],[\"$\",\"meta\",\"3\",{\"name\":\"description\",\"content\":\"Fleet control dashboard for Agent Relay\"}],[\"$\",\"link\",\"4\",{\"rel\":\"apple-touch-icon\",\"href\":\"/apple-icon.png?9e7a840704165ca6\",\"type\":\"image/png\",\"sizes\":\"256x256\"}]]\n3:null\n"])</script></body></html>
6
+ " aria-label="Agent Relay Logo" role="img"><path d="M30 80 L 50 20 L 70 80" stroke="#00d9ff" stroke-width="5" stroke-linejoin="round" stroke-linecap="round" fill="none"></path><line x1="40" y1="50" x2="60" y2="50" stroke="#00d9ff" stroke-width="5" stroke-linecap="round"></line><path d="M50 20 L 50 80" stroke="#00ffc8" stroke-width="2.5" stroke-linecap="round" opacity="0.7"></path><path d="M50 20 C 80 20 80 50 50 50 L 80 80" stroke="#00ffc8" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" fill="none" opacity="0.7"></path></svg><h1 class="mt-4 text-3xl font-bold text-white">Get Started</h1><p class="mt-2 text-text-muted text-center">Create your account and start orchestrating AI agents</p></div><div class="bg-bg-primary/80 backdrop-blur-sm border border-border-subtle rounded-2xl p-8 shadow-xl"><div><div class="flex mb-6 bg-bg-secondary/50 rounded-lg p-1"><button type="button" class="flex-1 py-2 px-4 rounded-md text-sm font-medium transition-colors bg-bg-primary text-white shadow-sm">GitHub</button><button type="button" class="flex-1 py-2 px-4 rounded-md text-sm font-medium transition-colors text-text-muted hover:text-white">Email</button></div><div class="mb-6 space-y-3"><div class="flex items-center gap-3 text-sm text-text-secondary"><div class="w-8 h-8 rounded-lg bg-accent-cyan/10 flex items-center justify-center flex-shrink-0"><svg class="w-4 h-4 text-accent-cyan" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path></svg></div><span>Deploy AI agents in seconds</span></div><div class="flex items-center gap-3 text-sm text-text-secondary"><div class="w-8 h-8 rounded-lg bg-[#00ffc8]/10 flex items-center justify-center flex-shrink-0"><svg class="w-4 h-4 text-[#00ffc8]" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"></path></svg></div><span>Real-time agent collaboration</span></div><div class="flex items-center gap-3 text-sm text-text-secondary"><div class="w-8 h-8 rounded-lg bg-[#0891b2]/10 flex items-center justify-center flex-shrink-0"><svg class="w-4 h-4 text-[#0891b2]" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"></path></svg></div><span>Secure credential management</span></div></div><button type="button" disabled="" class="w-full py-4 px-6 bg-[#24292e] hover:bg-[#2f363d] border border-[#444d56] rounded-xl text-white font-medium flex items-center justify-center gap-3 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"><svg class="w-5 h-5 animate-spin" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"></path></svg><span>Loading...</span></button><p class="mt-6 text-center text-text-muted text-sm">By signing up, you agree to our<!-- --> <a href="/terms" class="text-accent-cyan hover:underline">Terms of Service</a> <!-- -->and<!-- --> <a href="/privacy" class="text-accent-cyan hover:underline">Privacy Policy</a></p></div></div><div class="mt-6 text-center"><p class="text-text-muted">Already have an account?<!-- --> <a href="/login" class="text-accent-cyan hover:underline font-medium">Sign in</a></p></div><div class="mt-4 text-center"><a href="/" class="text-text-muted hover:text-white transition-colors text-sm">Back to home</a></div></div></div><script src="/_next/static/chunks/webpack-1cdd8ed57114d5e1.js" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0]);self.__next_f.push([2,null])</script><script>self.__next_f.push([1,"1:HL[\"/_next/static/css/45361ce86b2847c4.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"2:I[2846,[],\"\"]\n4:I[9107,[],\"ClientPageRoot\"]\n5:I[4665,[\"282\",\"static/chunks/282-980c2eb8fff20123.js\",\"966\",\"static/chunks/app/signup/page-c7a0a28341365ae0.js\"],\"default\",1]\n6:I[4707,[],\"\"]\n7:I[6423,[],\"\"]\n9:I[1060,[],\"\"]\na:[]\n"])</script><script>self.__next_f.push([1,"0:[\"$\",\"$L2\",null,{\"buildId\":\"JIjqkuDKNeoSg7KaMMuhx\",\"assetPrefix\":\"\",\"urlParts\":[\"\",\"signup\"],\"initialTree\":[\"\",{\"children\":[\"signup\",{\"children\":[\"__PAGE__\",{}]}]},\"$undefined\",\"$undefined\",true],\"initialSeedData\":[\"\",{\"children\":[\"signup\",{\"children\":[\"__PAGE__\",{},[[\"$L3\",[\"$\",\"$L4\",null,{\"props\":{\"params\":{},\"searchParams\":{}},\"Component\":\"$5\"}],null],null],null]},[null,[\"$\",\"$L6\",null,{\"parallelRouterKey\":\"children\",\"segmentPath\":[\"children\",\"signup\",\"children\"],\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L7\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"notFoundStyles\":\"$undefined\"}]],null]},[[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/45361ce86b2847c4.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"children\":[\"$\",\"body\",null,{\"children\":[\"$\",\"$L6\",null,{\"parallelRouterKey\":\"children\",\"segmentPath\":[\"children\"],\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L7\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":\"404\"}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],\"notFoundStyles\":[]}]}]}]],null],null],\"couldBeIntercepted\":false,\"initialHead\":[null,\"$L8\"],\"globalErrorComponent\":\"$9\",\"missingSlots\":\"$Wa\"}]\n"])</script><script>self.__next_f.push([1,"8:[[\"$\",\"meta\",\"0\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}],[\"$\",\"meta\",\"1\",{\"charSet\":\"utf-8\"}],[\"$\",\"title\",\"2\",{\"children\":\"Agent Relay Dashboard\"}],[\"$\",\"meta\",\"3\",{\"name\":\"description\",\"content\":\"Fleet control dashboard for Agent Relay\"}],[\"$\",\"link\",\"4\",{\"rel\":\"apple-touch-icon\",\"href\":\"/apple-icon.png?9e7a840704165ca6\",\"type\":\"image/png\",\"sizes\":\"256x256\"}]]\n3:null\n"])</script></body></html>
@@ -1,7 +1,7 @@
1
1
  2:I[9107,[],"ClientPageRoot"]
2
- 3:I[4665,["282","static/chunks/282-980c2eb8fff20123.js","966","static/chunks/app/signup/page-1ede2205b58649ca.js"],"default",1]
2
+ 3:I[4665,["282","static/chunks/282-980c2eb8fff20123.js","966","static/chunks/app/signup/page-c7a0a28341365ae0.js"],"default",1]
3
3
  4:I[4707,[],""]
4
4
  5:I[6423,[],""]
5
- 0:["itBGQ1M8yMA_hC42DKCqv",[[["",{"children":["signup",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",{"children":["signup",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","signup","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/605dd4e30c91986f.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"en","children":["$","body",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]}]],null],null],["$L6",null]]]]
5
+ 0:["JIjqkuDKNeoSg7KaMMuhx",[[["",{"children":["signup",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",{"children":["signup",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","signup","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/45361ce86b2847c4.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"en","children":["$","body",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]}]],null],null],["$L6",null]]]]
6
6
  6:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"Agent Relay Dashboard"}],["$","meta","3",{"name":"description","content":"Fleet control dashboard for Agent Relay"}],["$","link","4",{"rel":"apple-touch-icon","href":"/apple-icon.png?9e7a840704165ca6","type":"image/png","sizes":"256x256"}]]
7
7
  1:null
@@ -156,9 +156,11 @@ program
156
156
  console.error(`Project: ${paths.projectId}`);
157
157
  // Auto-install MCP config if not present (project-local)
158
158
  // Uses .mcp.json in the project root - doesn't modify global settings
159
+ // Feature gated: set RELAY_MCP_AUTO_INSTALL=1 to enable
160
+ const mcpAutoInstallEnabled = process.env.RELAY_MCP_AUTO_INSTALL === '1';
159
161
  const projectMcpConfigPath = path.join(paths.projectRoot, '.mcp.json');
160
162
  const socketPath = path.join(paths.projectRoot, '.agent-relay', 'relay.sock');
161
- if (!fs.existsSync(projectMcpConfigPath)) {
163
+ if (!fs.existsSync(projectMcpConfigPath) && mcpAutoInstallEnabled) {
162
164
  try {
163
165
  const result = installMcpConfig(projectMcpConfigPath, {
164
166
  configKey: 'mcpServers',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-relay",
3
- "version": "2.0.16",
3
+ "version": "2.0.18",
4
4
  "description": "Real-time agent-to-agent communication system",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",
@@ -17,8 +17,8 @@
17
17
  "scripts": {
18
18
  "postinstall": "npm rebuild better-sqlite3 && node scripts/postinstall.js",
19
19
  "build": "npm run clean && npm run build:rust && turbo run build --filter='./packages/*' && tsc && npm run build:dashboard",
20
- "build:sequential": "npm run clean && npm run build:rust && npm run build:protocol && npm run build:config && npm run build:storage && npm run build:state && npm run build:policy && npm run build:trajectory && npm run build:hooks && npm run build:memory && npm run build:utils && npm run build:continuity && npm run build:resiliency && npm run build:user-directory && npm run build:wrapper && npm run build:bridge && npm run build:telemetry && npm run build:cloud && npm run build:daemon && npm run build:sdk && npm run build:dashboard-server && npm run build:dashboard-pkg && npm run build:api-types && npm run build:spawner && npm run build:mcp && tsc && npm run build:dashboard",
21
- "build:workspace": "npm run clean && npm run build:rust && npm run build:protocol && npm run build:config && npm run build:storage && npm run build:state && npm run build:policy && npm run build:trajectory && npm run build:hooks && npm run build:memory && npm run build:utils && npm run build:continuity && npm run build:resiliency && npm run build:user-directory && npm run build:wrapper && npm run build:bridge && npm run build:telemetry && npm run build:cloud && npm run build:daemon && npm run build:sdk && npm run build:dashboard-server && npm run build:dashboard-pkg && npm run build:api-types && npm run build:spawner && npm run build:mcp && tsc",
20
+ "build:sequential": "npm run clean && npm run build:rust && npm run build:protocol && npm run build:config && npm run build:storage && npm run build:state && npm run build:policy && npm run build:trajectory && npm run build:hooks && npm run build:memory && npm run build:utils && npm run build:continuity && npm run build:resiliency && npm run build:user-directory && npm run build:wrapper && npm run build:mcp && npm run build:bridge && npm run build:telemetry && npm run build:cloud && npm run build:daemon && npm run build:sdk && npm run build:dashboard-server && npm run build:dashboard-pkg && npm run build:api-types && npm run build:spawner && tsc && npm run build:dashboard",
21
+ "build:workspace": "npm run clean && npm run build:rust && npm run build:protocol && npm run build:config && npm run build:storage && npm run build:state && npm run build:policy && npm run build:trajectory && npm run build:hooks && npm run build:memory && npm run build:utils && npm run build:continuity && npm run build:resiliency && npm run build:user-directory && npm run build:wrapper && npm run build:mcp && npm run build:bridge && npm run build:telemetry && npm run build:cloud && npm run build:daemon && npm run build:sdk && npm run build:dashboard-server && npm run build:dashboard-pkg && npm run build:api-types && npm run build:spawner && tsc",
22
22
  "build:packages": "turbo run build --filter='./packages/*'",
23
23
  "build:packages:watch": "turbo run build --filter='./packages/*' --watch",
24
24
  "build:mcp": "cd packages/mcp && npm run build",
@@ -44,10 +44,10 @@
44
44
  "build:api-types": "cd packages/api-types && npm run build",
45
45
  "build:spawner": "cd packages/spawner && npm run build",
46
46
  "build:telemetry": "cd packages/telemetry && npm run build",
47
- "build:dashboard": "cd packages/dashboard/ui && npm run build",
47
+ "build:dashboard": "cd packages/dashboard/ui && npm ci && npm run build",
48
48
  "postbuild": "chmod +x dist/src/cli/index.js && mkdir -p dist/dashboard && cp -r packages/dashboard/ui/out dist/dashboard/ && mkdir -p packages/dashboard/ui-dist && cp -r packages/dashboard/ui/out/* packages/dashboard/ui-dist/",
49
49
  "dev:watch": "tsc -w",
50
- "predev": "npm run clean && tsc && chmod +x dist/src/cli/index.js",
50
+ "predev": "npm run clean && npm run build:packages && tsc && chmod +x dist/src/cli/index.js",
51
51
  "dev": "concurrently -n daemon,next -c blue,magenta \"npm run dev:daemon\" \"npm run dev:next\"",
52
52
  "dev:daemon": "node dist/src/cli/index.js up --dashboard --port 3889",
53
53
  "dev:next": "cd packages/dashboard/ui && npm run dev",
@@ -84,7 +84,8 @@
84
84
  "cloud:setup": "./scripts/cloud-setup.sh",
85
85
  "cloud:api": "WORKSPACE_IMAGE=relay-workspace:local WORKSPACE_DEV_MOUNT=true node -r dotenv/config packages/cloud/dist/index.js",
86
86
  "precloud": "./scripts/cloud-setup.sh --skip-data",
87
- "cloud": "concurrently -n api,daemon,dashboard -c cyan,blue,magenta \"npm run cloud:api\" \"npm run dev:daemon\" \"npm run dev:next\""
87
+ "cloud": "concurrently -n api,daemon,dashboard -c cyan,blue,magenta \"npm run cloud:api\" \"npm run dev:daemon\" \"npm run dev:next\"",
88
+ "docs:dev": "cd docs && npm run dev"
88
89
  },
89
90
  "keywords": [
90
91
  "agent",
@@ -107,21 +108,21 @@
107
108
  },
108
109
  "homepage": "https://github.com/AgentWorkforce/relay#readme",
109
110
  "dependencies": {
110
- "@agent-relay/bridge": "2.0.16",
111
- "@agent-relay/config": "2.0.16",
112
- "@agent-relay/continuity": "2.0.16",
113
- "@agent-relay/daemon": "2.0.16",
114
- "@agent-relay/hooks": "2.0.16",
115
- "@agent-relay/mcp": "2.0.16",
116
- "@agent-relay/protocol": "2.0.16",
117
- "@agent-relay/resiliency": "2.0.16",
118
- "@agent-relay/sdk": "2.0.16",
119
- "@agent-relay/storage": "2.0.16",
120
- "@agent-relay/telemetry": "2.0.16",
121
- "@agent-relay/trajectory": "2.0.16",
122
- "@agent-relay/user-directory": "2.0.16",
123
- "@agent-relay/utils": "2.0.16",
124
- "@agent-relay/wrapper": "2.0.16",
111
+ "@agent-relay/bridge": "2.0.18",
112
+ "@agent-relay/config": "2.0.18",
113
+ "@agent-relay/continuity": "2.0.18",
114
+ "@agent-relay/daemon": "2.0.18",
115
+ "@agent-relay/hooks": "2.0.18",
116
+ "@agent-relay/mcp": "2.0.18",
117
+ "@agent-relay/protocol": "2.0.18",
118
+ "@agent-relay/resiliency": "2.0.18",
119
+ "@agent-relay/sdk": "2.0.18",
120
+ "@agent-relay/storage": "2.0.18",
121
+ "@agent-relay/telemetry": "2.0.18",
122
+ "@agent-relay/trajectory": "2.0.18",
123
+ "@agent-relay/user-directory": "2.0.18",
124
+ "@agent-relay/utils": "2.0.18",
125
+ "@agent-relay/wrapper": "2.0.18",
125
126
  "@nangohq/node": "^0.69.20",
126
127
  "@types/jsonwebtoken": "^9.0.10",
127
128
  "agent-trajectories": "^0.2.3",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-relay/api-types",
3
- "version": "2.0.16",
3
+ "version": "2.0.18",
4
4
  "description": "Shared API types and Zod schemas for Agent Relay",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-relay/bridge",
3
- "version": "2.0.16",
3
+ "version": "2.0.18",
4
4
  "description": "Multi-project bridge client utilities for Relay",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -22,13 +22,13 @@
22
22
  "test:watch": "vitest"
23
23
  },
24
24
  "dependencies": {
25
- "@agent-relay/protocol": "2.0.16",
26
- "@agent-relay/config": "2.0.16",
27
- "@agent-relay/utils": "2.0.16",
28
- "@agent-relay/policy": "2.0.16",
29
- "@agent-relay/user-directory": "2.0.16",
30
- "@agent-relay/wrapper": "2.0.16",
31
- "@agent-relay/mcp": "2.0.16"
25
+ "@agent-relay/protocol": "2.0.18",
26
+ "@agent-relay/config": "2.0.18",
27
+ "@agent-relay/utils": "2.0.18",
28
+ "@agent-relay/policy": "2.0.18",
29
+ "@agent-relay/user-directory": "2.0.18",
30
+ "@agent-relay/wrapper": "2.0.18",
31
+ "@agent-relay/mcp": "2.0.18"
32
32
  },
33
33
  "devDependencies": {
34
34
  "@types/node": "^22.19.3",
@@ -55,6 +55,7 @@ authRouter.get('/me', async (req, res) => {
55
55
  res.json({
56
56
  id: user.id,
57
57
  githubUsername: user.githubUsername,
58
+ displayName: user.displayName || user.githubUsername || user.email?.split('@')[0] || null,
58
59
  email: user.email,
59
60
  avatarUrl: user.avatarUrl,
60
61
  plan: user.plan,
@@ -117,6 +118,7 @@ authRouter.get('/session', async (req, res) => {
117
118
  user: {
118
119
  id: user.id,
119
120
  githubUsername: user.githubUsername,
121
+ displayName: user.displayName || user.githubUsername || user.email?.split('@')[0] || null,
120
122
  email: user.email,
121
123
  avatarUrl: user.avatarUrl,
122
124
  plan: user.plan,
@@ -172,7 +172,7 @@ billingRouter.get('/subscription', requireAuth, async (req, res) => {
172
172
  return res.status(404).json({ error: 'User not found' });
173
173
  }
174
174
  // Admin users have special status - show their current plan without Stripe
175
- if (isAdminUser(user.githubUsername)) {
175
+ if (user.githubUsername && isAdminUser(user.githubUsername)) {
176
176
  return res.json({
177
177
  tier: user.plan || 'enterprise',
178
178
  subscription: null,
@@ -192,7 +192,7 @@ billingRouter.get('/subscription', requireAuth, async (req, res) => {
192
192
  const billing = getBillingService();
193
193
  // Get or create Stripe customer
194
194
  const customerId = user.stripeCustomerId ||
195
- await billing.getOrCreateCustomer(user.id, user.email || '', user.githubUsername);
195
+ await billing.getOrCreateCustomer(user.id, user.email || '', user.githubUsername ?? undefined);
196
196
  // Save customer ID to database if newly created
197
197
  if (!user.stripeCustomerId) {
198
198
  await db.users.update(userId, { stripeCustomerId: customerId });
@@ -250,7 +250,7 @@ billingRouter.post('/checkout', requireAuth, async (req, res) => {
250
250
  return res.status(404).json({ error: 'User not found' });
251
251
  }
252
252
  // Admin users get free upgrades - skip Stripe entirely
253
- if (isAdminUser(user.githubUsername)) {
253
+ if (user.githubUsername && isAdminUser(user.githubUsername)) {
254
254
  // Update user plan directly
255
255
  await db.users.update(userId, { plan: tier });
256
256
  console.log(`[billing] Admin user ${user.githubUsername} upgraded to ${tier} (free)`);
@@ -273,7 +273,7 @@ billingRouter.post('/checkout', requireAuth, async (req, res) => {
273
273
  const billing = getBillingService();
274
274
  // Get or create customer
275
275
  const customerId = user.stripeCustomerId ||
276
- await billing.getOrCreateCustomer(user.id, user.email || '', user.githubUsername);
276
+ await billing.getOrCreateCustomer(user.id, user.email || '', user.githubUsername ?? undefined);
277
277
  // Save customer ID to database
278
278
  if (!user.stripeCustomerId) {
279
279
  await db.users.update(userId, { stripeCustomerId: customerId });
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Email Auth API Routes
3
+ *
4
+ * Handles email/password authentication:
5
+ * - Signup with email/password
6
+ * - Login with email/password
7
+ * - Email verification
8
+ * - Password reset (future)
9
+ */
10
+ export declare const emailAuthRouter: import("express-serve-static-core").Router;
11
+ //# sourceMappingURL=email-auth.d.ts.map
@@ -0,0 +1,347 @@
1
+ /**
2
+ * Email Auth API Routes
3
+ *
4
+ * Handles email/password authentication:
5
+ * - Signup with email/password
6
+ * - Login with email/password
7
+ * - Email verification
8
+ * - Password reset (future)
9
+ */
10
+ import { Router } from 'express';
11
+ import { randomBytes, scrypt, timingSafeEqual } from 'node:crypto';
12
+ import { promisify } from 'node:util';
13
+ import { db } from '../db/index.js';
14
+ import { requireAuth } from './auth.js';
15
+ const scryptAsync = promisify(scrypt);
16
+ export const emailAuthRouter = Router();
17
+ // Password hashing configuration
18
+ const SALT_LENGTH = 32;
19
+ const KEY_LENGTH = 64;
20
+ /**
21
+ * Hash a password using scrypt
22
+ */
23
+ async function hashPassword(password) {
24
+ const salt = randomBytes(SALT_LENGTH);
25
+ const derivedKey = await scryptAsync(password, salt, KEY_LENGTH);
26
+ return `${salt.toString('hex')}:${derivedKey.toString('hex')}`;
27
+ }
28
+ /**
29
+ * Verify a password against a hash
30
+ */
31
+ async function verifyPassword(password, storedHash) {
32
+ try {
33
+ const [saltHex, keyHex] = storedHash.split(':');
34
+ if (!saltHex || !keyHex)
35
+ return false;
36
+ const salt = Buffer.from(saltHex, 'hex');
37
+ const storedKey = Buffer.from(keyHex, 'hex');
38
+ const derivedKey = await scryptAsync(password, salt, KEY_LENGTH);
39
+ return timingSafeEqual(storedKey, derivedKey);
40
+ }
41
+ catch {
42
+ return false;
43
+ }
44
+ }
45
+ /**
46
+ * Generate a random verification token
47
+ */
48
+ function generateVerificationToken() {
49
+ return randomBytes(32).toString('hex');
50
+ }
51
+ /**
52
+ * Validate email format
53
+ */
54
+ function isValidEmail(email) {
55
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
56
+ return emailRegex.test(email);
57
+ }
58
+ /**
59
+ * Validate password strength
60
+ */
61
+ function isValidPassword(password) {
62
+ if (password.length < 8) {
63
+ return { valid: false, message: 'Password must be at least 8 characters long' };
64
+ }
65
+ if (password.length > 128) {
66
+ return { valid: false, message: 'Password must be less than 128 characters' };
67
+ }
68
+ return { valid: true };
69
+ }
70
+ /**
71
+ * POST /api/auth/email/signup
72
+ * Create a new account with email/password
73
+ */
74
+ emailAuthRouter.post('/signup', async (req, res) => {
75
+ try {
76
+ const { email, password, displayName } = req.body;
77
+ // Validate input
78
+ if (!email || typeof email !== 'string') {
79
+ return res.status(400).json({ error: 'Email is required' });
80
+ }
81
+ if (!password || typeof password !== 'string') {
82
+ return res.status(400).json({ error: 'Password is required' });
83
+ }
84
+ const normalizedEmail = email.toLowerCase().trim();
85
+ if (!isValidEmail(normalizedEmail)) {
86
+ return res.status(400).json({ error: 'Invalid email format' });
87
+ }
88
+ const passwordValidation = isValidPassword(password);
89
+ if (!passwordValidation.valid) {
90
+ return res.status(400).json({ error: passwordValidation.message });
91
+ }
92
+ // Check if email already exists (in users.email or user_emails table)
93
+ // This enables account reconciliation - if someone signed up via GitHub,
94
+ // their linked emails will be found and they should log in instead
95
+ const existingUser = await db.userEmails.findUserByEmail(normalizedEmail);
96
+ if (existingUser) {
97
+ // If the existing user signed up via GitHub, offer to use that account
98
+ if (existingUser.githubId && !existingUser.passwordHash) {
99
+ return res.status(409).json({
100
+ error: 'This email is associated with a GitHub account. Please log in with GitHub, or set a password on that account.',
101
+ code: 'GITHUB_ACCOUNT_EXISTS',
102
+ });
103
+ }
104
+ return res.status(409).json({ error: 'An account with this email already exists' });
105
+ }
106
+ // Hash password and create user
107
+ const passwordHash = await hashPassword(password);
108
+ const user = await db.users.createEmailUser({
109
+ email: normalizedEmail,
110
+ passwordHash,
111
+ displayName: displayName?.trim() || undefined,
112
+ });
113
+ // Generate verification token
114
+ const verificationToken = generateVerificationToken();
115
+ const verificationExpires = new Date(Date.now() + 24 * 60 * 60 * 1000); // 24 hours
116
+ await db.users.setEmailVerificationToken(user.id, verificationToken, verificationExpires);
117
+ // TODO: Send verification email
118
+ // For now, we'll auto-verify in development or skip email verification
119
+ // In production, you would send an email with a link containing the token
120
+ // Set session
121
+ req.session.userId = user.id;
122
+ res.status(201).json({
123
+ success: true,
124
+ user: {
125
+ id: user.id,
126
+ email: user.email,
127
+ displayName: user.displayName,
128
+ emailVerified: user.emailVerified,
129
+ },
130
+ // Include verification token in development for testing
131
+ ...(process.env.NODE_ENV !== 'production' && { verificationToken }),
132
+ });
133
+ }
134
+ catch (error) {
135
+ console.error('Email signup error:', error);
136
+ res.status(500).json({ error: 'Failed to create account' });
137
+ }
138
+ });
139
+ /**
140
+ * POST /api/auth/email/login
141
+ * Login with email/password
142
+ *
143
+ * Supports account reconciliation: users can log in with any email address
144
+ * linked to their account via GitHub, not just their primary email.
145
+ */
146
+ emailAuthRouter.post('/login', async (req, res) => {
147
+ try {
148
+ const { email, password } = req.body;
149
+ // Validate input
150
+ if (!email || typeof email !== 'string') {
151
+ return res.status(400).json({ error: 'Email is required' });
152
+ }
153
+ if (!password || typeof password !== 'string') {
154
+ return res.status(400).json({ error: 'Password is required' });
155
+ }
156
+ const normalizedEmail = email.toLowerCase().trim();
157
+ // Find user by email - checks both user_emails table (GitHub-linked emails)
158
+ // and users.email (primary email), enabling account reconciliation
159
+ const user = await db.userEmails.findUserByEmail(normalizedEmail);
160
+ if (!user) {
161
+ // Use same message for security (don't reveal if email exists)
162
+ return res.status(401).json({ error: 'Invalid email or password' });
163
+ }
164
+ // Check if user has a password (might be GitHub-only user)
165
+ if (!user.passwordHash) {
166
+ return res.status(401).json({
167
+ error: 'This account uses GitHub login. Please sign in with GitHub, or set a password to enable email login.',
168
+ code: 'GITHUB_ACCOUNT',
169
+ });
170
+ }
171
+ // Verify password
172
+ const isValid = await verifyPassword(password, user.passwordHash);
173
+ if (!isValid) {
174
+ return res.status(401).json({ error: 'Invalid email or password' });
175
+ }
176
+ // Set session
177
+ req.session.userId = user.id;
178
+ res.json({
179
+ success: true,
180
+ user: {
181
+ id: user.id,
182
+ email: user.email,
183
+ displayName: user.displayName,
184
+ githubUsername: user.githubUsername,
185
+ avatarUrl: user.avatarUrl,
186
+ emailVerified: user.emailVerified,
187
+ },
188
+ });
189
+ }
190
+ catch (error) {
191
+ console.error('Email login error:', error);
192
+ res.status(500).json({ error: 'Failed to login' });
193
+ }
194
+ });
195
+ /**
196
+ * POST /api/auth/email/verify
197
+ * Verify email with token
198
+ */
199
+ emailAuthRouter.post('/verify', async (req, res) => {
200
+ try {
201
+ const { token } = req.body;
202
+ if (!token || typeof token !== 'string') {
203
+ return res.status(400).json({ error: 'Verification token is required' });
204
+ }
205
+ // Find user by token
206
+ const user = await db.users.findByEmailVerificationToken(token);
207
+ if (!user) {
208
+ return res.status(400).json({ error: 'Invalid or expired verification token' });
209
+ }
210
+ // Check if token expired
211
+ if (user.emailVerificationExpires && user.emailVerificationExpires < new Date()) {
212
+ return res.status(400).json({ error: 'Verification token has expired' });
213
+ }
214
+ // Verify email
215
+ await db.users.verifyEmail(user.id);
216
+ res.json({
217
+ success: true,
218
+ message: 'Email verified successfully',
219
+ });
220
+ }
221
+ catch (error) {
222
+ console.error('Email verification error:', error);
223
+ res.status(500).json({ error: 'Failed to verify email' });
224
+ }
225
+ });
226
+ /**
227
+ * POST /api/auth/email/resend-verification
228
+ * Resend verification email (requires auth)
229
+ */
230
+ emailAuthRouter.post('/resend-verification', requireAuth, async (req, res) => {
231
+ try {
232
+ const userId = req.session.userId;
233
+ const user = await db.users.findById(userId);
234
+ if (!user) {
235
+ return res.status(404).json({ error: 'User not found' });
236
+ }
237
+ if (user.emailVerified) {
238
+ return res.status(400).json({ error: 'Email is already verified' });
239
+ }
240
+ if (!user.email) {
241
+ return res.status(400).json({ error: 'No email address on this account' });
242
+ }
243
+ // Generate new verification token
244
+ const verificationToken = generateVerificationToken();
245
+ const verificationExpires = new Date(Date.now() + 24 * 60 * 60 * 1000); // 24 hours
246
+ await db.users.setEmailVerificationToken(user.id, verificationToken, verificationExpires);
247
+ // TODO: Send verification email
248
+ // For now, return success and include token in development
249
+ res.json({
250
+ success: true,
251
+ message: 'Verification email sent',
252
+ ...(process.env.NODE_ENV !== 'production' && { verificationToken }),
253
+ });
254
+ }
255
+ catch (error) {
256
+ console.error('Resend verification error:', error);
257
+ res.status(500).json({ error: 'Failed to resend verification email' });
258
+ }
259
+ });
260
+ /**
261
+ * POST /api/auth/set-email
262
+ * Set email for GitHub users who don't have one (requires auth)
263
+ */
264
+ emailAuthRouter.post('/set-email', requireAuth, async (req, res) => {
265
+ try {
266
+ const userId = req.session.userId;
267
+ const { email } = req.body;
268
+ if (!email || typeof email !== 'string') {
269
+ return res.status(400).json({ error: 'Email is required' });
270
+ }
271
+ const normalizedEmail = email.toLowerCase().trim();
272
+ if (!isValidEmail(normalizedEmail)) {
273
+ return res.status(400).json({ error: 'Invalid email format' });
274
+ }
275
+ const user = await db.users.findById(userId);
276
+ if (!user) {
277
+ return res.status(404).json({ error: 'User not found' });
278
+ }
279
+ // Check if user already has an email
280
+ if (user.email) {
281
+ return res.status(400).json({ error: 'Email is already set for this account' });
282
+ }
283
+ // Check if email is already used by another user (including in user_emails table)
284
+ const isLinkedToOther = await db.userEmails.isEmailLinkedToOtherUser(normalizedEmail, userId);
285
+ if (isLinkedToOther) {
286
+ return res.status(409).json({ error: 'This email is already associated with another account' });
287
+ }
288
+ // Also check users.email directly
289
+ const existingUser = await db.users.findByEmail(normalizedEmail);
290
+ if (existingUser && existingUser.id !== userId) {
291
+ return res.status(409).json({ error: 'This email is already associated with another account' });
292
+ }
293
+ // Update user with email
294
+ await db.users.update(userId, { email: normalizedEmail });
295
+ // Generate verification token
296
+ const verificationToken = generateVerificationToken();
297
+ const verificationExpires = new Date(Date.now() + 24 * 60 * 60 * 1000); // 24 hours
298
+ await db.users.setEmailVerificationToken(userId, verificationToken, verificationExpires);
299
+ // TODO: Send verification email
300
+ res.json({
301
+ success: true,
302
+ message: 'Email set successfully',
303
+ email: normalizedEmail,
304
+ ...(process.env.NODE_ENV !== 'production' && { verificationToken }),
305
+ });
306
+ }
307
+ catch (error) {
308
+ console.error('Set email error:', error);
309
+ res.status(500).json({ error: 'Failed to set email' });
310
+ }
311
+ });
312
+ /**
313
+ * POST /api/auth/email/set-password
314
+ * Set password for GitHub users who want to add email login (requires auth)
315
+ */
316
+ emailAuthRouter.post('/set-password', requireAuth, async (req, res) => {
317
+ try {
318
+ const userId = req.session.userId;
319
+ const { password } = req.body;
320
+ if (!password || typeof password !== 'string') {
321
+ return res.status(400).json({ error: 'Password is required' });
322
+ }
323
+ const passwordValidation = isValidPassword(password);
324
+ if (!passwordValidation.valid) {
325
+ return res.status(400).json({ error: passwordValidation.message });
326
+ }
327
+ const user = await db.users.findById(userId);
328
+ if (!user) {
329
+ return res.status(404).json({ error: 'User not found' });
330
+ }
331
+ if (!user.email) {
332
+ return res.status(400).json({ error: 'Please set an email address first' });
333
+ }
334
+ // Hash password and update user
335
+ const passwordHash = await hashPassword(password);
336
+ await db.users.updatePassword(userId, passwordHash);
337
+ res.json({
338
+ success: true,
339
+ message: 'Password set successfully',
340
+ });
341
+ }
342
+ catch (error) {
343
+ console.error('Set password error:', error);
344
+ res.status(500).json({ error: 'Failed to set password' });
345
+ }
346
+ });
347
+ //# sourceMappingURL=email-auth.js.map