agent-relay 2.0.4 → 2.0.5
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.
- package/dist/dashboard/out/404.html +1 -1
- package/dist/dashboard/out/app/onboarding.html +1 -1
- package/dist/dashboard/out/app/onboarding.txt +1 -1
- package/dist/dashboard/out/app.html +1 -1
- package/dist/dashboard/out/app.txt +1 -1
- package/dist/dashboard/out/cloud/link.html +1 -1
- package/dist/dashboard/out/cloud/link.txt +1 -1
- package/dist/dashboard/out/connect-repos.html +1 -1
- package/dist/dashboard/out/connect-repos.txt +1 -1
- package/dist/dashboard/out/history.html +1 -1
- package/dist/dashboard/out/history.txt +1 -1
- package/dist/dashboard/out/index.html +1 -1
- package/dist/dashboard/out/index.txt +1 -1
- package/dist/dashboard/out/login.html +1 -1
- package/dist/dashboard/out/login.txt +1 -1
- package/dist/dashboard/out/metrics.html +1 -1
- package/dist/dashboard/out/metrics.txt +1 -1
- package/dist/dashboard/out/pricing.html +1 -1
- package/dist/dashboard/out/pricing.txt +1 -1
- package/dist/dashboard/out/providers/setup/claude.html +1 -1
- package/dist/dashboard/out/providers/setup/claude.txt +1 -1
- package/dist/dashboard/out/providers/setup/codex.html +1 -1
- package/dist/dashboard/out/providers/setup/codex.txt +1 -1
- package/dist/dashboard/out/providers/setup/cursor.html +1 -1
- package/dist/dashboard/out/providers/setup/cursor.txt +1 -1
- package/dist/dashboard/out/providers.html +1 -1
- package/dist/dashboard/out/providers.txt +1 -1
- package/dist/dashboard/out/signup.html +1 -1
- package/dist/dashboard/out/signup.txt +1 -1
- package/dist/src/cli/index.js +61 -3
- package/package.json +14 -12
- package/packages/api-types/package.json +1 -1
- package/packages/bridge/package.json +7 -7
- package/packages/cloud/package.json +6 -6
- package/packages/config/package.json +2 -2
- package/packages/continuity/package.json +1 -1
- package/packages/daemon/dist/router.d.ts +2 -1
- package/packages/daemon/dist/router.js +142 -52
- package/packages/daemon/dist/server.d.ts +3 -0
- package/packages/daemon/dist/server.js +31 -1
- package/packages/daemon/dist/spawn-manager.d.ts +5 -0
- package/packages/daemon/dist/spawn-manager.js +39 -0
- package/packages/daemon/package.json +12 -11
- package/packages/dashboard/package.json +12 -12
- package/packages/dashboard/ui-dist/404.html +1 -1
- package/packages/dashboard/ui-dist/app/onboarding.html +1 -1
- package/packages/dashboard/ui-dist/app/onboarding.txt +1 -1
- package/packages/dashboard/ui-dist/app.html +1 -1
- package/packages/dashboard/ui-dist/app.txt +1 -1
- package/packages/dashboard/ui-dist/cloud/link.html +1 -1
- package/packages/dashboard/ui-dist/cloud/link.txt +1 -1
- package/packages/dashboard/ui-dist/connect-repos.html +1 -1
- package/packages/dashboard/ui-dist/connect-repos.txt +1 -1
- package/packages/dashboard/ui-dist/history.html +1 -1
- package/packages/dashboard/ui-dist/history.txt +1 -1
- package/packages/dashboard/ui-dist/index.html +1 -1
- package/packages/dashboard/ui-dist/index.txt +1 -1
- package/packages/dashboard/ui-dist/login.html +1 -1
- package/packages/dashboard/ui-dist/login.txt +1 -1
- package/packages/dashboard/ui-dist/metrics.html +1 -1
- package/packages/dashboard/ui-dist/metrics.txt +1 -1
- package/packages/dashboard/ui-dist/pricing.html +1 -1
- package/packages/dashboard/ui-dist/pricing.txt +1 -1
- package/packages/dashboard/ui-dist/providers/setup/claude.html +1 -1
- package/packages/dashboard/ui-dist/providers/setup/claude.txt +1 -1
- package/packages/dashboard/ui-dist/providers/setup/codex.html +1 -1
- package/packages/dashboard/ui-dist/providers/setup/codex.txt +1 -1
- package/packages/dashboard/ui-dist/providers/setup/cursor.html +1 -1
- package/packages/dashboard/ui-dist/providers/setup/cursor.txt +1 -1
- package/packages/dashboard/ui-dist/providers.html +1 -1
- package/packages/dashboard/ui-dist/providers.txt +1 -1
- package/packages/dashboard/ui-dist/signup.html +1 -1
- package/packages/dashboard/ui-dist/signup.txt +1 -1
- package/packages/dashboard-server/dist/user-bridge.d.ts +7 -3
- package/packages/dashboard-server/dist/user-bridge.js +48 -30
- package/packages/dashboard-server/package.json +12 -12
- package/packages/hooks/package.json +4 -4
- package/packages/mcp/README.md +19 -135
- package/packages/mcp/dist/client.js +67 -27
- package/packages/mcp/dist/cloud.js +1 -18
- package/packages/mcp/package.json +2 -1
- package/packages/memory/package.json +2 -2
- package/packages/policy/package.json +2 -2
- package/packages/protocol/package.json +1 -1
- package/packages/resiliency/package.json +1 -1
- package/packages/sdk/README.md +43 -160
- package/packages/sdk/dist/client.d.ts +3 -99
- package/packages/sdk/dist/client.js +6 -113
- package/packages/sdk/dist/index.d.ts +0 -1
- package/packages/sdk/dist/index.js +0 -2
- package/packages/sdk/dist/standalone.js +0 -1
- package/packages/sdk/package.json +2 -2
- package/packages/spawner/package.json +1 -1
- package/packages/state/package.json +1 -1
- package/packages/storage/package.json +2 -2
- package/packages/telemetry/dist/client.d.ts +19 -0
- package/packages/telemetry/dist/client.js +125 -0
- package/packages/telemetry/dist/config.d.ts +29 -0
- package/packages/telemetry/dist/config.js +88 -0
- package/packages/telemetry/dist/events.d.ts +106 -0
- package/packages/telemetry/dist/events.js +10 -0
- package/packages/telemetry/dist/index.d.ts +8 -0
- package/packages/telemetry/dist/index.js +7 -0
- package/packages/telemetry/dist/machine-id.d.ts +12 -0
- package/packages/telemetry/dist/machine-id.js +58 -0
- package/packages/telemetry/dist/posthog-config.d.ts +16 -0
- package/packages/telemetry/dist/posthog-config.js +33 -0
- package/packages/telemetry/package.json +41 -0
- package/packages/trajectory/package.json +2 -2
- package/packages/user-directory/package.json +2 -2
- package/packages/utils/package.json +1 -1
- package/packages/wrapper/dist/relay-pty-orchestrator.js +1 -1
- package/packages/wrapper/package.json +6 -6
- package/packages/sdk/dist/discovery.d.ts +0 -29
- package/packages/sdk/dist/discovery.js +0 -126
- /package/dist/dashboard/out/_next/static/{72btMIJ64BCAB4UgVkpaq → xtLmZI8Coh2009JpfvOBw}/_buildManifest.js +0 -0
- /package/dist/dashboard/out/_next/static/{72btMIJ64BCAB4UgVkpaq → xtLmZI8Coh2009JpfvOBw}/_ssgManifest.js +0 -0
- /package/packages/dashboard/ui-dist/_next/static/{0AsOfRemPXJmtynCKT-rx → QWdjV9SGDgz-GkriZP7Ao}/_buildManifest.js +0 -0
- /package/packages/dashboard/ui-dist/_next/static/{0AsOfRemPXJmtynCKT-rx → QWdjV9SGDgz-GkriZP7Ao}/_ssgManifest.js +0 -0
- /package/packages/dashboard/ui-dist/_next/static/{72btMIJ64BCAB4UgVkpaq → SySrsm8xdGaeJLrZ2RNuf}/_buildManifest.js +0 -0
- /package/packages/dashboard/ui-dist/_next/static/{72btMIJ64BCAB4UgVkpaq → SySrsm8xdGaeJLrZ2RNuf}/_ssgManifest.js +0 -0
- /package/packages/dashboard/ui-dist/_next/static/{clUN2n0bz9HCjKI0qlOxU → xtLmZI8Coh2009JpfvOBw}/_buildManifest.js +0 -0
- /package/packages/dashboard/ui-dist/_next/static/{clUN2n0bz9HCjKI0qlOxU → xtLmZI8Coh2009JpfvOBw}/_ssgManifest.js +0 -0
|
@@ -3,4 +3,4 @@
|
|
|
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/99c2552394077586.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-18a4665665f6be11.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\":\"
|
|
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/99c2552394077586.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-18a4665665f6be11.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\":\"xtLmZI8Coh2009JpfvOBw\",\"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/99c2552394077586.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>
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
3:I[4665,["282","static/chunks/282-980c2eb8fff20123.js","966","static/chunks/app/signup/page-18a4665665f6be11.js"],"default",1]
|
|
3
3
|
4:I[4707,[],""]
|
|
4
4
|
5:I[6423,[],""]
|
|
5
|
-
0:["
|
|
5
|
+
0:["xtLmZI8Coh2009JpfvOBw",[[["",{"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/99c2552394077586.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
|
package/dist/src/cli/index.js
CHANGED
|
@@ -20,6 +20,7 @@ import { RelayPtyOrchestrator, getTmuxPath } from '@agent-relay/wrapper';
|
|
|
20
20
|
import { AgentSpawner, readWorkersMetadata, getWorkerLogsDir, selectShadowCli } from '@agent-relay/bridge';
|
|
21
21
|
import { generateAgentName, checkForUpdatesInBackground, checkForUpdates } from '@agent-relay/utils';
|
|
22
22
|
import { getShadowForAgent } from '@agent-relay/config';
|
|
23
|
+
import { initTelemetry, track, enableTelemetry, disableTelemetry, getStatus, isDisabledByEnv, } from '@agent-relay/telemetry';
|
|
23
24
|
import fs from 'node:fs';
|
|
24
25
|
import path from 'node:path';
|
|
25
26
|
import { promisify } from 'node:util';
|
|
@@ -49,12 +50,24 @@ const VERSION = packageJson.version;
|
|
|
49
50
|
const execAsync = promisify(exec);
|
|
50
51
|
// Check for updates in background (non-blocking)
|
|
51
52
|
// Only show notification for interactive commands, not when wrapping agents or running update
|
|
52
|
-
const interactiveCommands = ['up', 'down', 'status', 'agents', 'who', 'version', '--version', '-V', '--help', '-h', 'create-agent', 'claude', 'codex'];
|
|
53
|
+
const interactiveCommands = ['up', 'down', 'status', 'agents', 'who', 'version', '--version', '-V', '--help', '-h', 'create-agent', 'claude', 'codex', 'telemetry'];
|
|
53
54
|
const shouldCheckUpdates = process.argv.length > 2 &&
|
|
54
55
|
interactiveCommands.includes(process.argv[2]);
|
|
55
56
|
if (shouldCheckUpdates) {
|
|
56
57
|
checkForUpdatesInBackground(VERSION);
|
|
57
58
|
}
|
|
59
|
+
// Initialize telemetry for interactive commands (shows first-run notice)
|
|
60
|
+
const shouldInitTelemetry = process.argv.length > 2 &&
|
|
61
|
+
interactiveCommands.includes(process.argv[2]) &&
|
|
62
|
+
process.argv[2] !== 'telemetry'; // Don't show notice for telemetry command itself
|
|
63
|
+
if (shouldInitTelemetry) {
|
|
64
|
+
initTelemetry({ showNotice: true });
|
|
65
|
+
// Track CLI command usage
|
|
66
|
+
const commandName = process.argv[2];
|
|
67
|
+
if (commandName && !commandName.startsWith('-')) {
|
|
68
|
+
track('cli_command_run', { command_name: commandName });
|
|
69
|
+
}
|
|
70
|
+
}
|
|
58
71
|
const program = new Command();
|
|
59
72
|
function pidFilePathForSocket(socketPath) {
|
|
60
73
|
return `${socketPath}.pid`;
|
|
@@ -335,8 +348,11 @@ program
|
|
|
335
348
|
pidFilePath,
|
|
336
349
|
storagePath: dbPath,
|
|
337
350
|
teamDir: paths.teamDir,
|
|
338
|
-
//
|
|
339
|
-
|
|
351
|
+
// Enable protocol-based spawning via SPAWN/RELEASE messages
|
|
352
|
+
spawnManager: {
|
|
353
|
+
projectRoot: paths.projectRoot,
|
|
354
|
+
socketPath,
|
|
355
|
+
},
|
|
340
356
|
});
|
|
341
357
|
// Create spawner for auto-spawn (will be initialized after dashboard starts)
|
|
342
358
|
let spawner = null;
|
|
@@ -3048,6 +3064,48 @@ program
|
|
|
3048
3064
|
.option('--skip-daemon', 'Skip daemon startup')
|
|
3049
3065
|
.option('--skip-mcp', 'Skip MCP installation')
|
|
3050
3066
|
.action(runInit);
|
|
3067
|
+
// telemetry - Manage anonymous telemetry
|
|
3068
|
+
program
|
|
3069
|
+
.command('telemetry')
|
|
3070
|
+
.description('Manage anonymous telemetry (enable/disable/status)')
|
|
3071
|
+
.argument('[action]', 'Action: enable, disable, or status (default: status)')
|
|
3072
|
+
.action((action) => {
|
|
3073
|
+
if (action === 'enable') {
|
|
3074
|
+
if (isDisabledByEnv()) {
|
|
3075
|
+
console.log('Cannot enable: AGENT_RELAY_TELEMETRY_DISABLED is set');
|
|
3076
|
+
console.log('Remove the environment variable to enable telemetry.');
|
|
3077
|
+
return;
|
|
3078
|
+
}
|
|
3079
|
+
enableTelemetry();
|
|
3080
|
+
console.log('Telemetry enabled');
|
|
3081
|
+
console.log('Anonymous usage data will be collected to improve Agent Relay.');
|
|
3082
|
+
}
|
|
3083
|
+
else if (action === 'disable') {
|
|
3084
|
+
disableTelemetry();
|
|
3085
|
+
console.log('Telemetry disabled');
|
|
3086
|
+
console.log('No usage data will be collected.');
|
|
3087
|
+
}
|
|
3088
|
+
else {
|
|
3089
|
+
// Default: show status
|
|
3090
|
+
const status = getStatus();
|
|
3091
|
+
console.log('Telemetry Status');
|
|
3092
|
+
console.log('================');
|
|
3093
|
+
console.log(`Enabled: ${status.enabled ? 'Yes' : 'No'}`);
|
|
3094
|
+
if (status.disabledByEnv) {
|
|
3095
|
+
console.log('(Disabled via AGENT_RELAY_TELEMETRY_DISABLED environment variable)');
|
|
3096
|
+
}
|
|
3097
|
+
console.log(`Anonymous ID: ${status.anonymousId}`);
|
|
3098
|
+
if (status.notifiedAt) {
|
|
3099
|
+
console.log(`First run notice shown: ${new Date(status.notifiedAt).toLocaleString()}`);
|
|
3100
|
+
}
|
|
3101
|
+
console.log('');
|
|
3102
|
+
console.log('Commands:');
|
|
3103
|
+
console.log(' agent-relay telemetry enable - Opt in to telemetry');
|
|
3104
|
+
console.log(' agent-relay telemetry disable - Opt out of telemetry');
|
|
3105
|
+
console.log('');
|
|
3106
|
+
console.log('Learn more: https://agent-relay.com/telemetry');
|
|
3107
|
+
}
|
|
3108
|
+
});
|
|
3051
3109
|
// mcp - MCP server management
|
|
3052
3110
|
program
|
|
3053
3111
|
.command('mcp')
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-relay",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.5",
|
|
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 && turbo run build --filter='./packages/*' && tsc && npm run build:dashboard",
|
|
20
|
-
"build:sequential": "npm run clean && 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: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: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: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: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: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",
|
|
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",
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
"build:sdk": "cd packages/sdk && npm run build",
|
|
44
44
|
"build:api-types": "cd packages/api-types && npm run build",
|
|
45
45
|
"build:spawner": "cd packages/spawner && npm run build",
|
|
46
|
+
"build:telemetry": "cd packages/telemetry && npm run build",
|
|
46
47
|
"build:dashboard": "cd src/dashboard && npm run build",
|
|
47
48
|
"postbuild": "chmod +x dist/src/cli/index.js && mkdir -p dist/dashboard && cp -r src/dashboard/out dist/dashboard/ && mkdir -p packages/dashboard/ui-dist && cp -r src/dashboard/out/* packages/dashboard/ui-dist/",
|
|
48
49
|
"dev:watch": "tsc -w",
|
|
@@ -106,15 +107,16 @@
|
|
|
106
107
|
},
|
|
107
108
|
"homepage": "https://github.com/AgentWorkforce/relay#readme",
|
|
108
109
|
"dependencies": {
|
|
109
|
-
"@agent-relay/sdk": "2.0.
|
|
110
|
-
"@agent-relay/config": "2.0.
|
|
111
|
-
"@agent-relay/protocol": "2.0.
|
|
112
|
-
"@agent-relay/storage": "2.0.
|
|
113
|
-
"@agent-relay/continuity": "2.0.
|
|
114
|
-
"@agent-relay/trajectory": "2.0.
|
|
115
|
-
"@agent-relay/hooks": "2.0.
|
|
116
|
-
"@agent-relay/resiliency": "2.0.
|
|
117
|
-
"@agent-relay/user-directory": "2.0.
|
|
110
|
+
"@agent-relay/sdk": "2.0.5",
|
|
111
|
+
"@agent-relay/config": "2.0.5",
|
|
112
|
+
"@agent-relay/protocol": "2.0.5",
|
|
113
|
+
"@agent-relay/storage": "2.0.5",
|
|
114
|
+
"@agent-relay/continuity": "2.0.5",
|
|
115
|
+
"@agent-relay/trajectory": "2.0.5",
|
|
116
|
+
"@agent-relay/hooks": "2.0.5",
|
|
117
|
+
"@agent-relay/resiliency": "2.0.5",
|
|
118
|
+
"@agent-relay/user-directory": "2.0.5",
|
|
119
|
+
"@agent-relay/telemetry": "2.0.5",
|
|
118
120
|
"@nangohq/node": "^0.69.20",
|
|
119
121
|
"@types/jsonwebtoken": "^9.0.10",
|
|
120
122
|
"agent-trajectories": "^0.2.3",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-relay/bridge",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.5",
|
|
4
4
|
"description": "Multi-project bridge client utilities for Relay",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -22,12 +22,12 @@
|
|
|
22
22
|
"test:watch": "vitest"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@agent-relay/protocol": "2.0.
|
|
26
|
-
"@agent-relay/config": "2.0.
|
|
27
|
-
"@agent-relay/utils": "2.0.
|
|
28
|
-
"@agent-relay/policy": "2.0.
|
|
29
|
-
"@agent-relay/user-directory": "2.0.
|
|
30
|
-
"@agent-relay/wrapper": "2.0.
|
|
25
|
+
"@agent-relay/protocol": "2.0.5",
|
|
26
|
+
"@agent-relay/config": "2.0.5",
|
|
27
|
+
"@agent-relay/utils": "2.0.5",
|
|
28
|
+
"@agent-relay/policy": "2.0.5",
|
|
29
|
+
"@agent-relay/user-directory": "2.0.5",
|
|
30
|
+
"@agent-relay/wrapper": "2.0.5"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@types/node": "^22.19.3",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-relay/cloud",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.5",
|
|
4
4
|
"description": "Cloud API server and services for Agent Relay",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -38,11 +38,11 @@
|
|
|
38
38
|
"test:watch": "vitest"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@agent-relay/wrapper": "2.0.
|
|
42
|
-
"@agent-relay/config": "2.0.
|
|
43
|
-
"@agent-relay/resiliency": "2.0.
|
|
44
|
-
"@agent-relay/storage": "2.0.
|
|
45
|
-
"@agent-relay/protocol": "2.0.
|
|
41
|
+
"@agent-relay/wrapper": "2.0.5",
|
|
42
|
+
"@agent-relay/config": "2.0.5",
|
|
43
|
+
"@agent-relay/resiliency": "2.0.5",
|
|
44
|
+
"@agent-relay/storage": "2.0.5",
|
|
45
|
+
"@agent-relay/protocol": "2.0.5"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@types/node": "^22.19.3",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-relay/config",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.5",
|
|
4
4
|
"description": "Shared configuration schemas and loaders for Agent Relay",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
"test:watch": "vitest"
|
|
84
84
|
},
|
|
85
85
|
"dependencies": {
|
|
86
|
-
"@agent-relay/protocol": "2.0.
|
|
86
|
+
"@agent-relay/protocol": "2.0.5",
|
|
87
87
|
"zod": "^3.23.8",
|
|
88
88
|
"zod-to-json-schema": "^3.23.1"
|
|
89
89
|
},
|
|
@@ -57,7 +57,7 @@ export declare class Router {
|
|
|
57
57
|
private primaryByShadow;
|
|
58
58
|
/** Channel membership: channel -> Set of member names */
|
|
59
59
|
private channels;
|
|
60
|
-
/** User entities (human users, not agents) */
|
|
60
|
+
/** User entities (human users, not agents) - supports multiple connections per user (multi-tab) */
|
|
61
61
|
private users;
|
|
62
62
|
/** Reverse lookup: member name -> Set of channels they're in */
|
|
63
63
|
private memberChannels;
|
|
@@ -331,6 +331,7 @@ export declare class Router {
|
|
|
331
331
|
/**
|
|
332
332
|
* Get a connection by name (checks both agents and users).
|
|
333
333
|
* Uses case-insensitive lookup to handle mismatched casing.
|
|
334
|
+
* For users with multiple connections, returns the first connection.
|
|
334
335
|
*/
|
|
335
336
|
private getConnectionByName;
|
|
336
337
|
/**
|
|
@@ -24,7 +24,7 @@ export class Router {
|
|
|
24
24
|
primaryByShadow = new Map();
|
|
25
25
|
/** Channel membership: channel -> Set of member names */
|
|
26
26
|
channels = new Map();
|
|
27
|
-
/** User entities (human users, not agents) */
|
|
27
|
+
/** User entities (human users, not agents) - supports multiple connections per user (multi-tab) */
|
|
28
28
|
users = new Map();
|
|
29
29
|
/** Reverse lookup: member name -> Set of channels they're in */
|
|
30
30
|
memberChannels = new Map();
|
|
@@ -158,14 +158,13 @@ export class Router {
|
|
|
158
158
|
if (connection.agentName) {
|
|
159
159
|
const isUser = connection.entityType === 'user';
|
|
160
160
|
if (isUser) {
|
|
161
|
-
//
|
|
162
|
-
|
|
163
|
-
if (
|
|
164
|
-
|
|
165
|
-
this.connections.delete(existingUser.id);
|
|
161
|
+
// Users can have multiple connections (e.g., multiple browser tabs)
|
|
162
|
+
// Track ALL connections per user so messages reach all tabs
|
|
163
|
+
if (!this.users.has(connection.agentName)) {
|
|
164
|
+
this.users.set(connection.agentName, new Set());
|
|
166
165
|
}
|
|
167
|
-
this.users.
|
|
168
|
-
routerLog.info(`User registered: ${connection.agentName}`);
|
|
166
|
+
this.users.get(connection.agentName).add(connection);
|
|
167
|
+
routerLog.info(`User registered: ${connection.agentName} (${this.users.get(connection.agentName).size} connections)`);
|
|
169
168
|
}
|
|
170
169
|
else {
|
|
171
170
|
// Handle existing agent connection with same name (disconnect old)
|
|
@@ -202,10 +201,17 @@ export class Router {
|
|
|
202
201
|
const isUser = connection.entityType === 'user';
|
|
203
202
|
let wasCurrentConnection = false;
|
|
204
203
|
if (isUser) {
|
|
205
|
-
const
|
|
206
|
-
if (
|
|
207
|
-
|
|
208
|
-
|
|
204
|
+
const userConnections = this.users.get(connection.agentName);
|
|
205
|
+
if (userConnections) {
|
|
206
|
+
userConnections.delete(connection);
|
|
207
|
+
if (userConnections.size === 0) {
|
|
208
|
+
this.users.delete(connection.agentName);
|
|
209
|
+
wasCurrentConnection = true;
|
|
210
|
+
routerLog.info(`User fully unregistered: ${connection.agentName} (all connections closed)`);
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
routerLog.debug(`User connection closed: ${connection.agentName} (${userConnections.size} connections remaining)`);
|
|
214
|
+
}
|
|
209
215
|
}
|
|
210
216
|
}
|
|
211
217
|
else {
|
|
@@ -496,10 +502,12 @@ export class Router {
|
|
|
496
502
|
* This prevents silent message drops during brief disconnections or spawn timing issues.
|
|
497
503
|
*/
|
|
498
504
|
sendDirect(from, to, envelope) {
|
|
499
|
-
|
|
500
|
-
const
|
|
501
|
-
|
|
502
|
-
|
|
505
|
+
// Check for agent first, then user connections
|
|
506
|
+
const agentTarget = this.agents.get(to);
|
|
507
|
+
const userConnections = this.users.get(to);
|
|
508
|
+
const hasTarget = agentTarget || (userConnections && userConnections.size > 0);
|
|
509
|
+
// If target not found locally, check remote
|
|
510
|
+
if (!hasTarget) {
|
|
503
511
|
const remoteAgent = this.crossMachineHandler?.isRemoteAgent(to);
|
|
504
512
|
if (remoteAgent) {
|
|
505
513
|
routerLog.info(`Routing to remote agent: ${to}`, { daemonName: remoteAgent.daemonName });
|
|
@@ -533,6 +541,33 @@ export class Router {
|
|
|
533
541
|
routerLog.warn(`Target "${to}" not found and unknown`, { availableAgents: Array.from(this.agents.keys()), spawningAgents: Array.from(this.spawningAgents.keys()) });
|
|
534
542
|
return false;
|
|
535
543
|
}
|
|
544
|
+
// For user targets, send to ALL connections (multi-tab support)
|
|
545
|
+
if (userConnections && userConnections.size > 0) {
|
|
546
|
+
let anySent = false;
|
|
547
|
+
for (const userConn of userConnections) {
|
|
548
|
+
const deliver = this.createDeliverEnvelope(from, to, envelope, userConn);
|
|
549
|
+
const sent = userConn.send(deliver);
|
|
550
|
+
if (sent)
|
|
551
|
+
anySent = true;
|
|
552
|
+
routerLog.debug(`Delivered ${from} -> ${to} (user connection ${userConn.id})`, {
|
|
553
|
+
success: sent,
|
|
554
|
+
preview: envelope.payload.body?.substring(0, 40),
|
|
555
|
+
});
|
|
556
|
+
// Persist only once (for the first connection)
|
|
557
|
+
if (userConn === [...userConnections][0]) {
|
|
558
|
+
this.persistDeliverEnvelope(deliver);
|
|
559
|
+
}
|
|
560
|
+
if (sent) {
|
|
561
|
+
this.trackDelivery(userConn, deliver);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
if (anySent) {
|
|
565
|
+
this.registry?.recordReceive(to);
|
|
566
|
+
}
|
|
567
|
+
return anySent;
|
|
568
|
+
}
|
|
569
|
+
// For agent targets, send to single connection
|
|
570
|
+
const target = agentTarget;
|
|
536
571
|
const deliver = this.createDeliverEnvelope(from, to, envelope, target);
|
|
537
572
|
const sent = target.send(deliver);
|
|
538
573
|
routerLog.debug(`Delivered ${from} -> ${to}`, { success: sent, preview: envelope.payload.body?.substring(0, 40) });
|
|
@@ -540,10 +575,7 @@ export class Router {
|
|
|
540
575
|
if (sent) {
|
|
541
576
|
this.trackDelivery(target, deliver);
|
|
542
577
|
this.registry?.recordReceive(to);
|
|
543
|
-
|
|
544
|
-
if (!isUserTarget) {
|
|
545
|
-
this.setProcessing(to, deliver.id);
|
|
546
|
-
}
|
|
578
|
+
this.setProcessing(to, deliver.id);
|
|
547
579
|
}
|
|
548
580
|
return sent;
|
|
549
581
|
}
|
|
@@ -606,19 +638,33 @@ export class Router {
|
|
|
606
638
|
for (const recipientName of recipients) {
|
|
607
639
|
if (recipientName === from)
|
|
608
640
|
continue; // Don't send to self
|
|
609
|
-
// Check
|
|
610
|
-
const
|
|
611
|
-
if (
|
|
612
|
-
const
|
|
613
|
-
const
|
|
614
|
-
const sent = target.send(deliver);
|
|
641
|
+
// Check agents first
|
|
642
|
+
const agentTarget = this.agents.get(recipientName);
|
|
643
|
+
if (agentTarget) {
|
|
644
|
+
const deliver = this.createDeliverEnvelope(from, recipientName, envelope, agentTarget);
|
|
645
|
+
const sent = agentTarget.send(deliver);
|
|
615
646
|
this.persistDeliverEnvelope(deliver, true); // Mark as broadcast
|
|
616
647
|
if (sent) {
|
|
617
|
-
this.trackDelivery(
|
|
648
|
+
this.trackDelivery(agentTarget, deliver);
|
|
618
649
|
this.registry?.recordReceive(recipientName);
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
650
|
+
this.setProcessing(recipientName, deliver.id);
|
|
651
|
+
}
|
|
652
|
+
continue;
|
|
653
|
+
}
|
|
654
|
+
// Check user connections (send to all connections for multi-tab)
|
|
655
|
+
const userConnections = this.users.get(recipientName);
|
|
656
|
+
if (userConnections && userConnections.size > 0) {
|
|
657
|
+
let persisted = false;
|
|
658
|
+
for (const userConn of userConnections) {
|
|
659
|
+
const deliver = this.createDeliverEnvelope(from, recipientName, envelope, userConn);
|
|
660
|
+
const sent = userConn.send(deliver);
|
|
661
|
+
if (!persisted) {
|
|
662
|
+
this.persistDeliverEnvelope(deliver, true); // Mark as broadcast, persist once
|
|
663
|
+
persisted = true;
|
|
664
|
+
}
|
|
665
|
+
if (sent) {
|
|
666
|
+
this.trackDelivery(userConn, deliver);
|
|
667
|
+
this.registry?.recordReceive(recipientName);
|
|
622
668
|
}
|
|
623
669
|
}
|
|
624
670
|
}
|
|
@@ -629,16 +675,24 @@ export class Router {
|
|
|
629
675
|
* Used for system notifications that only humans should see.
|
|
630
676
|
*/
|
|
631
677
|
broadcastToUsers(from, envelope) {
|
|
632
|
-
for (const [userName,
|
|
678
|
+
for (const [userName, userConnections] of this.users) {
|
|
633
679
|
if (userName === from)
|
|
634
680
|
continue; // Don't send to self
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
this.
|
|
640
|
-
|
|
641
|
-
|
|
681
|
+
if (userConnections.size === 0)
|
|
682
|
+
continue;
|
|
683
|
+
let persisted = false;
|
|
684
|
+
for (const userConn of userConnections) {
|
|
685
|
+
const deliver = this.createDeliverEnvelope(from, userName, envelope, userConn);
|
|
686
|
+
const sent = userConn.send(deliver);
|
|
687
|
+
if (!persisted) {
|
|
688
|
+
this.persistDeliverEnvelope(deliver, true); // Mark as broadcast, persist once
|
|
689
|
+
persisted = true;
|
|
690
|
+
}
|
|
691
|
+
if (sent) {
|
|
692
|
+
this.trackDelivery(userConn, deliver);
|
|
693
|
+
this.registry?.recordReceive(userName);
|
|
694
|
+
routerLog.debug(`Broadcast to user ${userName} (connection ${userConn.id})`);
|
|
695
|
+
}
|
|
642
696
|
}
|
|
643
697
|
}
|
|
644
698
|
}
|
|
@@ -1104,8 +1158,9 @@ export class Router {
|
|
|
1104
1158
|
if (this.namesMatch(memberName, senderName)) {
|
|
1105
1159
|
continue;
|
|
1106
1160
|
}
|
|
1107
|
-
|
|
1108
|
-
|
|
1161
|
+
// Check for agent connection first
|
|
1162
|
+
const agentConn = this.agents.get(memberName);
|
|
1163
|
+
if (agentConn) {
|
|
1109
1164
|
const deliverEnvelope = {
|
|
1110
1165
|
v: PROTOCOL_VERSION,
|
|
1111
1166
|
type: 'CHANNEL_MESSAGE',
|
|
@@ -1114,20 +1169,48 @@ export class Router {
|
|
|
1114
1169
|
from: senderName,
|
|
1115
1170
|
payload: envelope.payload,
|
|
1116
1171
|
};
|
|
1117
|
-
const sent =
|
|
1172
|
+
const sent = agentConn.send(deliverEnvelope);
|
|
1118
1173
|
if (sent) {
|
|
1119
1174
|
deliveredCount++;
|
|
1120
|
-
routerLog.info(`Delivered to ${memberName} (
|
|
1175
|
+
routerLog.info(`Delivered to ${memberName} (agent)`);
|
|
1121
1176
|
}
|
|
1122
1177
|
else {
|
|
1123
1178
|
routerLog.warn(`Failed to send to ${memberName}`);
|
|
1124
1179
|
undeliveredMembers.push(memberName);
|
|
1125
1180
|
}
|
|
1181
|
+
continue;
|
|
1126
1182
|
}
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1183
|
+
// Check for user connections (send to ALL for multi-tab support)
|
|
1184
|
+
const userConnections = this.users.get(memberName);
|
|
1185
|
+
if (userConnections && userConnections.size > 0) {
|
|
1186
|
+
let anyDelivered = false;
|
|
1187
|
+
for (const userConn of userConnections) {
|
|
1188
|
+
const deliverEnvelope = {
|
|
1189
|
+
v: PROTOCOL_VERSION,
|
|
1190
|
+
type: 'CHANNEL_MESSAGE',
|
|
1191
|
+
id: generateId(),
|
|
1192
|
+
ts: Date.now(),
|
|
1193
|
+
from: senderName,
|
|
1194
|
+
payload: envelope.payload,
|
|
1195
|
+
};
|
|
1196
|
+
const sent = userConn.send(deliverEnvelope);
|
|
1197
|
+
if (sent) {
|
|
1198
|
+
anyDelivered = true;
|
|
1199
|
+
routerLog.info(`Delivered to ${memberName} (user connection ${userConn.id})`);
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
if (anyDelivered) {
|
|
1203
|
+
deliveredCount++;
|
|
1204
|
+
}
|
|
1205
|
+
else {
|
|
1206
|
+
routerLog.warn(`Failed to send to any connection for user ${memberName}`);
|
|
1207
|
+
undeliveredMembers.push(memberName);
|
|
1208
|
+
}
|
|
1209
|
+
continue;
|
|
1130
1210
|
}
|
|
1211
|
+
// Member not connected
|
|
1212
|
+
routerLog.warn(`Member ${memberName} is registered in channel but NOT connected to daemon - message not delivered`);
|
|
1213
|
+
undeliveredMembers.push(memberName);
|
|
1131
1214
|
}
|
|
1132
1215
|
// Persist channel message
|
|
1133
1216
|
this.persistChannelMessage(envelope, senderName);
|
|
@@ -1246,21 +1329,28 @@ export class Router {
|
|
|
1246
1329
|
/**
|
|
1247
1330
|
* Get a connection by name (checks both agents and users).
|
|
1248
1331
|
* Uses case-insensitive lookup to handle mismatched casing.
|
|
1332
|
+
* For users with multiple connections, returns the first connection.
|
|
1249
1333
|
*/
|
|
1250
1334
|
getConnectionByName(name) {
|
|
1251
|
-
// Try exact match first
|
|
1252
|
-
const
|
|
1253
|
-
if (
|
|
1254
|
-
return
|
|
1335
|
+
// Try exact match for agent first
|
|
1336
|
+
const agentExact = this.agents.get(name);
|
|
1337
|
+
if (agentExact)
|
|
1338
|
+
return agentExact;
|
|
1339
|
+
// Try exact match for user (get first connection from set)
|
|
1340
|
+
const userConnections = this.users.get(name);
|
|
1341
|
+
if (userConnections && userConnections.size > 0) {
|
|
1342
|
+
return [...userConnections][0];
|
|
1343
|
+
}
|
|
1255
1344
|
// Fall back to case-insensitive search
|
|
1256
1345
|
const lowerName = name.toLowerCase();
|
|
1257
1346
|
for (const [key, conn] of this.agents) {
|
|
1258
1347
|
if (key.toLowerCase() === lowerName)
|
|
1259
1348
|
return conn;
|
|
1260
1349
|
}
|
|
1261
|
-
for (const [key,
|
|
1262
|
-
if (key.toLowerCase() === lowerName)
|
|
1263
|
-
return
|
|
1350
|
+
for (const [key, conns] of this.users) {
|
|
1351
|
+
if (key.toLowerCase() === lowerName && conns.size > 0) {
|
|
1352
|
+
return [...conns][0];
|
|
1353
|
+
}
|
|
1264
1354
|
}
|
|
1265
1355
|
return undefined;
|
|
1266
1356
|
}
|