@turmind/halo 2.0.5 → 2.0.6

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.
@@ -1 +1 @@
1
- <!DOCTYPE html><!--F7kFetjUGIXr5T6aTQAtP--><html lang="en" class="dark"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" href="/_next/static/media/e4af272ccee01ff0-s.p.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="stylesheet" href="/_next/static/css/7b736202f0b1dbfd.css" data-precedence="next"/><link rel="stylesheet" href="/_next/static/css/2e6b00182ac44ae1.css" data-precedence="next"/><link rel="stylesheet" href="/_next/static/css/659eccb5db697b76.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/webpack-74f577c1b094f942.js"/><script src="/_next/static/chunks/1b86ba38-c29611e086b2ce25.js" async=""></script><script src="/_next/static/chunks/698-19872069fed27164.js" async=""></script><script src="/_next/static/chunks/main-app-340a5b58ed229c4d.js" async=""></script><script src="/_next/static/chunks/989-5c90f88e8111b360.js" async=""></script><script src="/_next/static/chunks/app/layout-ea161287d934ba96.js" async=""></script><script src="/_next/static/chunks/1d2d5650-d8d130c85727fdbb.js" async=""></script><script src="/_next/static/chunks/241-75bac3bb8e7aca1b.js" async=""></script><script src="/_next/static/chunks/app/page-cb05cd98d8f9042a.js" async=""></script><meta name="next-size-adjust" content=""/><title>Halo - Multi-Agent Workspace</title><meta name="description" content="Multi-agent collaboration workspace for complex project delivery"/><link rel="icon" href="/favicon.ico" type="image/x-icon" sizes="16x16"/><link rel="icon" href="/icon.svg?3a6863548daca964" type="image/svg+xml" sizes="any"/><script>try{var t=localStorage.getItem('halo_theme');if(t==='light'||t==='midnight'||t==='warm')document.documentElement.dataset.theme=t}catch(e){}</script><script src="/_next/static/chunks/polyfills-42372ed130431b0a.js" noModule=""></script></head><body class="__variable_d8ebd1 font-sans antialiased"><div hidden=""><!--$--><!--/$--></div><div class="flex h-screen w-screen items-center justify-center bg-[var(--background)]"><div class="text-sm text-[var(--muted-foreground)]">Loading...</div></div><!--$--><!--/$--><script src="/_next/static/chunks/webpack-74f577c1b094f942.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[58321,[\"989\",\"static/chunks/989-5c90f88e8111b360.js\",\"177\",\"static/chunks/app/layout-ea161287d934ba96.js\"],\"ThemeProvider\"]\n3:I[24554,[\"989\",\"static/chunks/989-5c90f88e8111b360.js\",\"177\",\"static/chunks/app/layout-ea161287d934ba96.js\"],\"AppI18nProvider\"]\n4:I[63693,[],\"\"]\n5:I[74713,[],\"\"]\n6:I[5444,[],\"ClientPageRoot\"]\n7:I[48891,[\"560\",\"static/chunks/1d2d5650-d8d130c85727fdbb.js\",\"241\",\"static/chunks/241-75bac3bb8e7aca1b.js\",\"989\",\"static/chunks/989-5c90f88e8111b360.js\",\"974\",\"static/chunks/app/page-cb05cd98d8f9042a.js\"],\"default\"]\na:I[23632,[],\"OutletBoundary\"]\nc:I[86889,[],\"AsyncMetadataOutlet\"]\ne:I[23632,[],\"ViewportBoundary\"]\n10:I[23632,[],\"MetadataBoundary\"]\n11:\"$Sreact.suspense\"\n13:I[1935,[],\"\"]\n:HL[\"/_next/static/media/e4af272ccee01ff0-s.p.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n:HL[\"/_next/static/css/7b736202f0b1dbfd.css\",\"style\"]\n:HL[\"/_next/static/css/2e6b00182ac44ae1.css\",\"style\"]\n:HL[\"/_next/static/css/659eccb5db697b76.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"b\":\"F7kFetjUGIXr5T6aTQAtP\",\"p\":\"\",\"c\":[\"\",\"\"],\"i\":false,\"f\":[[[\"\",{\"children\":[\"__PAGE__\",{}]},\"$undefined\",\"$undefined\",true],[\"\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/7b736202f0b1dbfd.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}],[\"$\",\"link\",\"1\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/2e6b00182ac44ae1.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"className\":\"dark\",\"suppressHydrationWarning\":true,\"children\":[[\"$\",\"head\",null,{\"children\":[\"$\",\"script\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"try{var t=localStorage.getItem('halo_theme');if(t==='light'||t==='midnight'||t==='warm')document.documentElement.dataset.theme=t}catch(e){}\"}}]}],[\"$\",\"body\",null,{\"className\":\"__variable_d8ebd1 font-sans antialiased\",\"children\":[\"$\",\"$L2\",null,{\"children\":[\"$\",\"$L3\",null,{\"children\":[\"$\",\"$L4\",null,{\"parallelRouterKey\":\"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.\"}]}]]}]}]],[]],\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]}]}]}]]}]]}],{\"children\":[\"__PAGE__\",[\"$\",\"$1\",\"c\",{\"children\":[[\"$\",\"$L6\",null,{\"Component\":\"$7\",\"searchParams\":{},\"params\":{},\"promises\":[\"$@8\",\"$@9\"]}],[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/659eccb5db697b76.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]],[\"$\",\"$La\",null,{\"children\":[\"$Lb\",[\"$\",\"$Lc\",null,{\"promise\":\"$@d\"}]]}]]}],{},null,false]},null,false],[\"$\",\"$1\",\"h\",{\"children\":[null,[[\"$\",\"$Le\",null,{\"children\":\"$Lf\"}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]],[\"$\",\"$L10\",null,{\"children\":[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$11\",null,{\"fallback\":null,\"children\":\"$L12\"}]}]}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$13\",[]],\"s\":false,\"S\":true}\n"])</script><script>self.__next_f.push([1,"8:{}\n9:\"$0:f:0:1:2:children:1:props:children:0:props:params\"\n"])</script><script>self.__next_f.push([1,"f:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\nb:null\n"])</script><script>self.__next_f.push([1,"14:I[88809,[],\"IconMark\"]\nd:{\"metadata\":[[\"$\",\"title\",\"0\",{\"children\":\"Halo - Multi-Agent Workspace\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"Multi-agent collaboration workspace for complex project delivery\"}],[\"$\",\"link\",\"2\",{\"rel\":\"icon\",\"href\":\"/favicon.ico\",\"type\":\"image/x-icon\",\"sizes\":\"16x16\"}],[\"$\",\"link\",\"3\",{\"rel\":\"icon\",\"href\":\"/icon.svg?3a6863548daca964\",\"type\":\"image/svg+xml\",\"sizes\":\"any\"}],[\"$\",\"$L14\",\"4\",{}]],\"error\":null,\"digest\":\"$undefined\"}\n"])</script><script>self.__next_f.push([1,"12:\"$d:metadata\"\n"])</script></body></html>
1
+ <!DOCTYPE html><!--l5P7Pjp_jJ_CFv3zMF4cK--><html lang="en" class="dark"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" href="/_next/static/media/e4af272ccee01ff0-s.p.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="stylesheet" href="/_next/static/css/7b736202f0b1dbfd.css" data-precedence="next"/><link rel="stylesheet" href="/_next/static/css/2e6b00182ac44ae1.css" data-precedence="next"/><link rel="stylesheet" href="/_next/static/css/659eccb5db697b76.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/webpack-74f577c1b094f942.js"/><script src="/_next/static/chunks/1b86ba38-c29611e086b2ce25.js" async=""></script><script src="/_next/static/chunks/698-19872069fed27164.js" async=""></script><script src="/_next/static/chunks/main-app-340a5b58ed229c4d.js" async=""></script><script src="/_next/static/chunks/989-5c90f88e8111b360.js" async=""></script><script src="/_next/static/chunks/app/layout-ea161287d934ba96.js" async=""></script><script src="/_next/static/chunks/1d2d5650-d8d130c85727fdbb.js" async=""></script><script src="/_next/static/chunks/241-75bac3bb8e7aca1b.js" async=""></script><script src="/_next/static/chunks/app/page-2e03b23bcc38e934.js" async=""></script><meta name="next-size-adjust" content=""/><title>Halo - Multi-Agent Workspace</title><meta name="description" content="Multi-agent collaboration workspace for complex project delivery"/><link rel="icon" href="/favicon.ico" type="image/x-icon" sizes="16x16"/><link rel="icon" href="/icon.svg?3a6863548daca964" type="image/svg+xml" sizes="any"/><script>try{var t=localStorage.getItem('halo_theme');if(t==='light'||t==='midnight'||t==='warm')document.documentElement.dataset.theme=t}catch(e){}</script><script src="/_next/static/chunks/polyfills-42372ed130431b0a.js" noModule=""></script></head><body class="__variable_d8ebd1 font-sans antialiased"><div hidden=""><!--$--><!--/$--></div><div class="flex h-screen w-screen items-center justify-center bg-[var(--background)]"><div class="text-sm text-[var(--muted-foreground)]">Loading...</div></div><!--$--><!--/$--><script src="/_next/static/chunks/webpack-74f577c1b094f942.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[58321,[\"989\",\"static/chunks/989-5c90f88e8111b360.js\",\"177\",\"static/chunks/app/layout-ea161287d934ba96.js\"],\"ThemeProvider\"]\n3:I[24554,[\"989\",\"static/chunks/989-5c90f88e8111b360.js\",\"177\",\"static/chunks/app/layout-ea161287d934ba96.js\"],\"AppI18nProvider\"]\n4:I[63693,[],\"\"]\n5:I[74713,[],\"\"]\n6:I[5444,[],\"ClientPageRoot\"]\n7:I[48891,[\"560\",\"static/chunks/1d2d5650-d8d130c85727fdbb.js\",\"241\",\"static/chunks/241-75bac3bb8e7aca1b.js\",\"989\",\"static/chunks/989-5c90f88e8111b360.js\",\"974\",\"static/chunks/app/page-2e03b23bcc38e934.js\"],\"default\"]\na:I[23632,[],\"OutletBoundary\"]\nc:I[86889,[],\"AsyncMetadataOutlet\"]\ne:I[23632,[],\"ViewportBoundary\"]\n10:I[23632,[],\"MetadataBoundary\"]\n11:\"$Sreact.suspense\"\n13:I[1935,[],\"\"]\n:HL[\"/_next/static/media/e4af272ccee01ff0-s.p.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n:HL[\"/_next/static/css/7b736202f0b1dbfd.css\",\"style\"]\n:HL[\"/_next/static/css/2e6b00182ac44ae1.css\",\"style\"]\n:HL[\"/_next/static/css/659eccb5db697b76.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"b\":\"l5P7Pjp-jJ_CFv3zMF4cK\",\"p\":\"\",\"c\":[\"\",\"\"],\"i\":false,\"f\":[[[\"\",{\"children\":[\"__PAGE__\",{}]},\"$undefined\",\"$undefined\",true],[\"\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/7b736202f0b1dbfd.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}],[\"$\",\"link\",\"1\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/2e6b00182ac44ae1.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"className\":\"dark\",\"suppressHydrationWarning\":true,\"children\":[[\"$\",\"head\",null,{\"children\":[\"$\",\"script\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"try{var t=localStorage.getItem('halo_theme');if(t==='light'||t==='midnight'||t==='warm')document.documentElement.dataset.theme=t}catch(e){}\"}}]}],[\"$\",\"body\",null,{\"className\":\"__variable_d8ebd1 font-sans antialiased\",\"children\":[\"$\",\"$L2\",null,{\"children\":[\"$\",\"$L3\",null,{\"children\":[\"$\",\"$L4\",null,{\"parallelRouterKey\":\"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.\"}]}]]}]}]],[]],\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]}]}]}]]}]]}],{\"children\":[\"__PAGE__\",[\"$\",\"$1\",\"c\",{\"children\":[[\"$\",\"$L6\",null,{\"Component\":\"$7\",\"searchParams\":{},\"params\":{},\"promises\":[\"$@8\",\"$@9\"]}],[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/659eccb5db697b76.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]],[\"$\",\"$La\",null,{\"children\":[\"$Lb\",[\"$\",\"$Lc\",null,{\"promise\":\"$@d\"}]]}]]}],{},null,false]},null,false],[\"$\",\"$1\",\"h\",{\"children\":[null,[[\"$\",\"$Le\",null,{\"children\":\"$Lf\"}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]],[\"$\",\"$L10\",null,{\"children\":[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$11\",null,{\"fallback\":null,\"children\":\"$L12\"}]}]}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$13\",[]],\"s\":false,\"S\":true}\n"])</script><script>self.__next_f.push([1,"8:{}\n9:\"$0:f:0:1:2:children:1:props:children:0:props:params\"\n"])</script><script>self.__next_f.push([1,"f:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\nb:null\n"])</script><script>self.__next_f.push([1,"14:I[88809,[],\"IconMark\"]\nd:{\"metadata\":[[\"$\",\"title\",\"0\",{\"children\":\"Halo - Multi-Agent Workspace\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"Multi-agent collaboration workspace for complex project delivery\"}],[\"$\",\"link\",\"2\",{\"rel\":\"icon\",\"href\":\"/favicon.ico\",\"type\":\"image/x-icon\",\"sizes\":\"16x16\"}],[\"$\",\"link\",\"3\",{\"rel\":\"icon\",\"href\":\"/icon.svg?3a6863548daca964\",\"type\":\"image/svg+xml\",\"sizes\":\"any\"}],[\"$\",\"$L14\",\"4\",{}]],\"error\":null,\"digest\":\"$undefined\"}\n"])</script><script>self.__next_f.push([1,"12:\"$d:metadata\"\n"])</script></body></html>
@@ -4,7 +4,7 @@
4
4
  4:I[63693,[],""]
5
5
  5:I[74713,[],""]
6
6
  6:I[5444,[],"ClientPageRoot"]
7
- 7:I[48891,["560","static/chunks/1d2d5650-d8d130c85727fdbb.js","241","static/chunks/241-75bac3bb8e7aca1b.js","989","static/chunks/989-5c90f88e8111b360.js","974","static/chunks/app/page-cb05cd98d8f9042a.js"],"default"]
7
+ 7:I[48891,["560","static/chunks/1d2d5650-d8d130c85727fdbb.js","241","static/chunks/241-75bac3bb8e7aca1b.js","989","static/chunks/989-5c90f88e8111b360.js","974","static/chunks/app/page-2e03b23bcc38e934.js"],"default"]
8
8
  a:I[23632,[],"OutletBoundary"]
9
9
  c:I[86889,[],"AsyncMetadataOutlet"]
10
10
  e:I[23632,[],"ViewportBoundary"]
@@ -15,7 +15,7 @@ e:I[23632,[],"ViewportBoundary"]
15
15
  :HL["/_next/static/css/7b736202f0b1dbfd.css","style"]
16
16
  :HL["/_next/static/css/2e6b00182ac44ae1.css","style"]
17
17
  :HL["/_next/static/css/659eccb5db697b76.css","style"]
18
- 0:{"P":null,"b":"F7kFetjUGIXr5T6aTQAtP","p":"","c":["",""],"i":false,"f":[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/7b736202f0b1dbfd.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/_next/static/css/2e6b00182ac44ae1.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","className":"dark","suppressHydrationWarning":true,"children":[["$","head",null,{"children":["$","script",null,{"dangerouslySetInnerHTML":{"__html":"try{var t=localStorage.getItem('halo_theme');if(t==='light'||t==='midnight'||t==='warm')document.documentElement.dataset.theme=t}catch(e){}"}}]}],["$","body",null,{"className":"__variable_d8ebd1 font-sans antialiased","children":["$","$L2",null,{"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"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."}]}]]}]}]],[]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}]}]]}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$L6",null,{"Component":"$7","searchParams":{},"params":{},"promises":["$@8","$@9"]}],[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/659eccb5db697b76.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","$La",null,{"children":["$Lb",["$","$Lc",null,{"promise":"$@d"}]]}]]}],{},null,false]},null,false],["$","$1","h",{"children":[null,[["$","$Le",null,{"children":"$Lf"}],["$","meta",null,{"name":"next-size-adjust","content":""}]],["$","$L10",null,{"children":["$","div",null,{"hidden":true,"children":["$","$11",null,{"fallback":null,"children":"$L12"}]}]}]]}],false]],"m":"$undefined","G":["$13",[]],"s":false,"S":true}
18
+ 0:{"P":null,"b":"l5P7Pjp-jJ_CFv3zMF4cK","p":"","c":["",""],"i":false,"f":[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/7b736202f0b1dbfd.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","link","1",{"rel":"stylesheet","href":"/_next/static/css/2e6b00182ac44ae1.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","className":"dark","suppressHydrationWarning":true,"children":[["$","head",null,{"children":["$","script",null,{"dangerouslySetInnerHTML":{"__html":"try{var t=localStorage.getItem('halo_theme');if(t==='light'||t==='midnight'||t==='warm')document.documentElement.dataset.theme=t}catch(e){}"}}]}],["$","body",null,{"className":"__variable_d8ebd1 font-sans antialiased","children":["$","$L2",null,{"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"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."}]}]]}]}]],[]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}]}]]}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$L6",null,{"Component":"$7","searchParams":{},"params":{},"promises":["$@8","$@9"]}],[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/659eccb5db697b76.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","$La",null,{"children":["$Lb",["$","$Lc",null,{"promise":"$@d"}]]}]]}],{},null,false]},null,false],["$","$1","h",{"children":[null,[["$","$Le",null,{"children":"$Lf"}],["$","meta",null,{"name":"next-size-adjust","content":""}]],["$","$L10",null,{"children":["$","div",null,{"hidden":true,"children":["$","$11",null,{"fallback":null,"children":"$L12"}]}]}]]}],false]],"m":"$undefined","G":["$13",[]],"s":false,"S":true}
19
19
  8:{}
20
20
  9:"$0:f:0:1:2:children:1:props:children:0:props:params"
21
21
  f:[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]
@@ -210,7 +210,7 @@ A viewer extension (emulator, model viewer) otherwise sees only its own file or
210
210
 
211
211
  - **`fs` with `scope`** (`extension-host-logic.ts` `onFsFrame`): `workspace` → the same `/files/*` read routes with a workspace-relative path; `system` → admin-cookie routes by absolute path: `read` → `GET /fs/raw` (streamed bytes), `stat` → `GET /fs/stat`, `list` → `GET /fs/browse?files=1` (name + type per entry). Validation happens before any request: `isSystemPath` (POSIX `/…` or `C:/…`, forward slashes, no NUL, no empty / `.` / `..` segment); unknown scope or op, a missing capability, or `write` / `append` → `fs-result{denied}`; a bad path → `invalid-path`.
212
212
  - **`pick`**: opens `FilePicker` (`shared/components/file-picker.tsx`) — a whole-machine browser with Workspace and Home shortcuts, a path box, a breadcrumb and the `accept` filter (directories always show; keyboard: arrows / Enter / Backspace for up / Esc cancels, the capture listener swallowing Esc before maximize sees it). One picker at a time, tied to the iframe attempt that asked; a reply for a since-remounted iframe is dropped. If the viewer is in its own fullscreen the host first drops back one level, so the picker isn't covered. On pick, the host `stat`s both the file and the workspace and compares **realpaths**, so a symlinked workspace or ROM dir lands on the right side: inside → workspace-relative `path`, else the absolute one. Closing it answers `cancelled`.
213
- - **Hidden-path guard** (`routes/files.ts`): `/fs/stat`, `/fs/raw` and `/fs/browse?files=1` all refuse the sandbox hidden lists (`~/.halo/secrets`, `~/.ssh`, `.git-credentials`, the global dbs …) via `isHiddenHostPath` (exported from `tools/sandbox.ts`; no second list), judged on the **realpath** so a symlink can't reach them. A refused path answers with the same 404 and message as a missing file, and a listing silently omits hidden entries. `/fs/browse?files=1` lists the same noise-filtered tree as `/files/tree` but with dot-entries shown and symlinks counted as what they point at; `sizes=1` adds file sizes. The default folder-picker response is unchanged. See [dev/api.md → Filesystem browse](../dev/api.md#filesystem-browse-not-project-scoped--for-the-workspace-picker).
213
+ - **Hidden-path guard** (`routes/files.ts`): `/fs/stat`, `/fs/raw`, `/fs/browse?files=1` and `/files/download` given an absolute path all refuse the sandbox hidden lists (`~/.halo/secrets`, `~/.ssh`, `.git-credentials`, the global dbs …) via `isHiddenHostPath` (exported from `tools/sandbox.ts`; no second list), judged on the **realpath** so a symlink can't reach them. A refused path answers with the same 404 and message as a missing file, and a listing silently omits hidden entries. `/fs/browse?files=1` lists the same noise-filtered tree as `/files/tree` but with dot-entries shown and symlinks counted as what they point at; `sizes=1` adds file sizes. The default folder-picker response is unchanged. See [dev/api.md → Filesystem browse](../dev/api.md#filesystem-browse-not-project-scoped--for-the-workspace-picker).
214
214
  - Settings → Extensions shows a "Reads files on this machine" tag for an extension that declares it.
215
215
 
216
216
  ### Platforms
@@ -35,7 +35,7 @@ File: `packages/server/src/routes/files.ts`
35
35
  | GET | `/api/files/search?projectId=&q=[&limit=][&dirsOnly=1]` | Recursive name search. Default limit 200, max 1000. Scans up to 50000 entries then truncates; returns `{matches, truncated}`. `dirsOnly=1` matches directories instead of files (powers the chat `@scope` directory completion). |
36
36
  | GET | `/api/files?path=&projectId=` | Read file content (max 10 MB) |
37
37
  | GET | `/api/files/stat?path=&projectId=` | Lightweight mtime + size |
38
- | GET | `/api/files/download?path=&projectId=&inline=` | Download or inline-preview — streams the file (no full read into memory), supports `Range` (206 Partial Content) so `<video>`/`<audio>` can seek + partial-load; aborts the read if the client disconnects. Missing file → 404 `{error:'File not found'}` |
38
+ | GET | `/api/files/download?path=&projectId=&inline=` | Download or inline-preview — streams the file (no full read into memory), supports `Range` (206 Partial Content) so `<video>`/`<audio>` can seek + partial-load; aborts the read if the client disconnects. A **relative** `path` is confined to the workspace (`..` out of it → 403). An **absolute** `path` may be any file on the host, under `/api/fs/raw`'s rules: no `..` segment (→ 400), judged by realpath, the sandbox hidden lists answer like a missing file; admin cookie only (this is how chat `MEDIA:` chips load files from other workspaces / temp dirs). `projectId` is still required. Missing or hidden file → 404 `{error:'File not found'}`; a directory → 400 |
39
39
  | GET | `/api/files/download-folder?path=&projectId=[&include=excluded][&estimate=1]` | Folder → one zip, built by yazl while it streams (zip64, UTF-8 names; already-compressed extensions stored, the rest deflated; one file open at a time, paced by backpressure; never staged on disk or in memory). `path` must be a directory inside the project, `''` = workspace root; it may itself be a folder symlink inside the workspace (resolved, then checked like any target); no `/tmp` exception. `Content-Disposition: attachment` with RFC 5987 `filename*` = `<folder name>.zip` (root → workspace dir name); no `Content-Length`, no Range. **Excluded by default**: any *folder* whose name is in `IGNORED_SEGMENTS` (`ws/file-watcher.ts`); `include=excluded` brings them back. **Always excluded**: `isHiddenHostPath` / `isHiddenWorkspacePath` (also against a nested `.halo/`), plus common credential stores (~/.kube, cloud CLI configs, shell histories — a zip-only list in `folder-zip.ts`, matched relative to the home dir), `.halo/settings.yaml`, `.env` / `.env.*`. Names a zip can't hold — any containing `\`, or a top-level `X:` prefix — are skipped as `unreadable`. Directory symlinks never followed; file symlinks only when the realpath stays inside the workspace and passes those checks. `estimate=1` → `{files, bytes, excluded: {<reason>: n}, ignoredNames: {<folder>: n}}` with reasons `ignored` / `blocked` / `symlink` / `unreadable`, same rules, no content read. More than 200,000 files or a walk over 10 s → **413** `{error}` (both modes, before any header). A blocked target → 403. Anything left out → `_halo-excluded.txt` at the zip root (grouped by reason, a pruned dir listed once, 1000 paths per reason + a count). Mid-stream (status already sent): a file that fails to open is skipped, a read error partway through truncates that entry — both are listed there. A client disconnect stops the walk and destroys the zip stream |
40
40
  | PUT | `/api/files` | Save file (body: `{path, content, projectId}`) |
41
41
  | PUT | `/api/files/raw?path=&projectId=[&expectMtime=][&create=1][&append=1][&root=]` | Replace an **existing** file's bytes with the raw request body (binary-safe; `PUT /api/files` is utf-8 text only). Used by canvas preview extensions' save path. 404 if the file doesn't exist (save never creates) unless `create=1`; 400 for a directory. `expectMtime` is the `modifiedAt` the client loaded from `/api/files/stat` (float ms — compared after `Math.round`): when the on-disk mtime differs → **409** `{error:'conflict', mtime, size}` so the client can offer overwrite (retry without / with the new `expectMtime`). `create=1` creates a missing file (parent dirs `mkdir -p`); `append=1` appends instead of overwriting (`expectMtime` ignored; with `create=1` a missing file is created first) — the bundle extensions' `fs` write / append. `root=<dir>` (workspace-relative; the bundle host always sends its bundle path): `<dir>` must be an existing directory and `path` strictly inside it, else **404** `{error:'Bundle root not found'}` with nothing created. Success → `{ok, path, mtime, size}` |
@@ -47,7 +47,7 @@ File: `packages/server/src/routes/files.ts`
47
47
 
48
48
  **Inline Content-Type** for images comes from core's shared extension→MIME table (`imageMimeFromExt`, `packages/core/src/media/mime.ts`) on both `/api/files/download?inline=1` and `/api/web/file`; each route keeps only its own non-image entries (pdf / html / video / audio) and falls back to `application/octet-stream`. That table is why `.bmp` now serves as `image/bmp` on both — the two routes used to carry their own copies and `/api/web/file` returned `application/octet-stream` for it. `.svg` / `.ico` / `.avif` get a real image Content-Type when served, but are deliberately not "photos" (they're outside `IMAGE_EXTS`) so they never reach a vision model or a channel's sendPhoto.
49
49
 
50
- All file operations validate the path stays inside the project root (prevents path traversal). The check (`validatePath` in `routes/workspace-path.ts`, shared with `data-preview.ts` and `git.ts`) realpaths both sides — longest existing ancestor plus the re-appended tail — so a symlink inside the workspace pointing outside it is rejected too, not just lexical `../`. One exception: `GET /api/files/download` (not `download-folder`) also accepts absolute paths under `/tmp/` so that agent-produced working files (e.g. Playwright screenshots) can be inline-previewed from chat media chips.
50
+ All file operations validate the path stays inside the project root (prevents path traversal). The check (`validatePath` in `routes/workspace-path.ts`, shared with `data-preview.ts` and `git.ts`) realpaths both sides — longest existing ancestor plus the re-appended tail — so a symlink inside the workspace pointing outside it is rejected too, not just lexical `../`. One exception: `GET /api/files/download` (not `download-folder`) also accepts an absolute path anywhere on the host, with the same rules and trust boundary as `/api/fs/raw` (below), so chat media chips can preview / download agent files outside the active workspace.
51
51
 
52
52
  ### Filesystem browse (not project-scoped — for the workspace picker)
53
53
 
@@ -60,7 +60,7 @@ All file operations validate the path stays inside the project root (prevents pa
60
60
  | GET | `/api/fs/raw?path=/abs` | `fs-read` `scope: 'system'` read: the file's bytes, streamed (`application/octet-stream` + `Content-Length`; the stream is destroyed if the client aborts). Same path rules and error shapes as `/api/fs/stat`; 400 `not a file` for a directory. |
61
61
  | POST | `/api/fs/workspace/resolve` | Resolve `{path}` to an absolute path and run `ensureWorkspaceHalo()`. Returns `{id, path}`. Used by the workspace-picker on switch. 404 `path not found` when it doesn't exist; 400 `not a directory` for a file; 400 `filesystem root cannot be a workspace` for `/` (or a drive root) — `ensureWorkspaceHalo()` writes a whole `.halo/` scaffold, so those two shapes are refused before the write. Deeper system trees (`/usr`, `/etc`) are deliberately **not** banned. |
62
62
 
63
- Absolute paths only. Purpose: Explorer's workspace picker and switching validation. `/api/fs/browse` is intentionally unrestricted (it's a read-only picker over the server's filesystem — same trust boundary as the admin cookie). Reading/writing files still goes through `/api/files/*` and remains project-sandboxed. The one exception is the read-only `/api/fs/stat` + `/api/fs/raw` + `/api/fs/browse?files=1` trio behind the `fs-read` extension capability: they take absolute paths (no `..` segment) and refuse the sandbox hidden lists (`~/.halo/secrets`, `~/.ssh`, `.git-credentials`, the global dbs … — `isHiddenHostPath` in `tools/sandbox.ts`, the same lists the agent sandbox masks) by **realpath**, so a symlink can't reach them. They are admin-cookie routes, never in `PUBLIC_PATHS`; `fs-read` itself is host-side UX gating (the extension iframe is same-origin and could call them directly), which is why the guard lives on the routes.
63
+ Absolute paths only. Purpose: Explorer's workspace picker and switching validation. `/api/fs/browse` is intentionally unrestricted (it's a read-only picker over the server's filesystem — same trust boundary as the admin cookie). Reading/writing files still goes through `/api/files/*` and remains project-sandboxed, except `GET /api/files/download` with an absolute path, which follows the `/api/fs/raw` rules below. The read-only exceptions are that and the `/api/fs/stat` + `/api/fs/raw` + `/api/fs/browse?files=1` trio behind the `fs-read` extension capability: they take absolute paths (no `..` segment) and refuse the sandbox hidden lists (`~/.halo/secrets`, `~/.ssh`, `.git-credentials`, the global dbs … — `isHiddenHostPath` in `tools/sandbox.ts`, the same lists the agent sandbox masks) by **realpath**, so a symlink can't reach them. They are admin-cookie routes, never in `PUBLIC_PATHS`; `fs-read` itself is host-side UX gating (the extension iframe is same-origin and could call them directly), which is why the guard lives on the routes.
64
64
 
65
65
  ## Data Preview
66
66
 
@@ -120,7 +120,7 @@ A Scissors button in the toolbar's input group (upload · **screenshot** · scre
120
120
  - Shown only when a frame source exists and the selected agent's model accepts images — same gate as live capture (no button on mobile browsers).
121
121
 
122
122
  ### Inline media chips
123
- Any message containing `[图片/视频/语音/文件 已保存: /path]` markers (WeChat + web) or a leading `MEDIA: /path` line (agent-emitted, e.g. from `wechat-send`) renders a compact chip with filename + icon. Clicking opens a full-size preview modal (image/video/audio inline, file → download link). The modal has a Download button (top-right, next to close) for image/video/audio; the media URL carries a per-open cache-buster (`&t=<timestamp>`) so overwritten files (same path, new bytes) always show current content. Paths inside the active workspace or under the OS temp dir (`/tmp/`) are previewable; everything else degrades to a non-clickable chip.
123
+ Any message containing `[图片/视频/语音/文件 已保存: /path]` markers (WeChat + web) or a leading `MEDIA: /path` line (agent-emitted, e.g. from `wechat-send`) renders a compact chip with filename + icon. Clicking opens a full-size preview modal (image/video/audio inline, file → download link). The modal has a Download button (top-right, next to close) for image/video/audio; the media URL carries a per-open cache-buster (`&t=<timestamp>`) so overwritten files (same path, new bytes) always show current content. Any absolute path is previewable and downloadable — including files in another workspace or the OS temp dir; sensitive dirs (`~/.halo/secrets`, `~/.ssh`, …) and missing files show the preview's failed state. Only a relative path, or no active workspace, degrades to a non-clickable chip.
124
124
 
125
125
  Images in chat (the modal's full-size image, a user message's screenshot strip and its zoom, markdown images in replies) never show the browser's broken-image icon: a themed pulsing box while loading, the image once loaded, and an `ImageOff` icon + "Image unavailable" / 「图片无法加载」 box if it fails (`shared/components/safe-image.tsx`).
126
126
 
@@ -87,7 +87,7 @@ File types without a built-in plugin can be handled by an **installed extension*
87
87
  ### Renderable text formats (Markdown / HTML)
88
88
  Markdown and HTML open as text in Monaco *and* have a rendered view — Canvas defaults to the **rendered** view since the primary audience is an AI generating reports / pages for humans to read.
89
89
  - Each pane's tab bar shows an **Edit / Preview** toggle for the active Markdown / HTML tab; the state is per pane, shared by both formats
90
- - **Markdown** → `MarkdownPreview` (react-markdown + GFM; relative image `src` rewritten to the download endpoint so local images work)
90
+ - **Markdown** → `MarkdownPreview` (react-markdown + GFM; relative image `src` rewritten to the download endpoint so local images work; an absolute `src` may point anywhere on the server except Halo's hidden secrets)
91
91
  - **HTML** → sandboxed iframe (`sandbox="allow-scripts allow-same-origin"`: the page's own JS runs, so a self-contained page renders live; top-navigation, forms and pop-ups stay blocked. Trusted like opening the file in Monaco — it comes from the user's own workspace)
92
92
  - Toggle to Edit → Monaco source, Cmd+S saves as usual
93
93
 
package/dist/index.js CHANGED
@@ -15857,7 +15857,7 @@ async function initObservability(haloProcess = "server") {
15857
15857
  return true;
15858
15858
  }
15859
15859
  const { registerSdk: registerSdk2 } = await Promise.resolve().then(() => (init_otel_sdk(), otel_sdk_exports));
15860
- providers = await registerSdk2(process.env.OTEL_SERVICE_NAME, "2.0.5", haloProcess);
15860
+ providers = await registerSdk2(process.env.OTEL_SERVICE_NAME, "2.0.6", haloProcess);
15861
15861
  console.log(`[Observability] OTLP export \u2192 ${process.env.OTEL_EXPORTER_OTLP_ENDPOINT} (service.name=${process.env.OTEL_SERVICE_NAME}, halo.process=${haloProcess}, capture_content=${config.observability.captureContent})`);
15862
15862
  return true;
15863
15863
  }
@@ -23626,6 +23626,24 @@ function createFileRoutes(opts = {}) {
23626
23626
  m4a: "audio/mp4",
23627
23627
  wasm: "application/wasm"
23628
23628
  };
23629
+ function systemPath(target) {
23630
+ if (!target || !path60.isAbsolute(target) || target.split(/[\\/]/).includes(".."))
23631
+ return null;
23632
+ return path60.resolve(target);
23633
+ }
23634
+ const fsErrorStatus = (err) => {
23635
+ const code = err.code;
23636
+ return code === "ENOENT" || code === "ENOTDIR" ? 404 : code === "EACCES" || code === "EPERM" ? 403 : 500;
23637
+ };
23638
+ function hiddenAsMissing(syscall, target) {
23639
+ return Object.assign(new Error(`ENOENT: no such file or directory, ${syscall} '${target}'`), { code: "ENOENT" });
23640
+ }
23641
+ async function readableRealPath(target) {
23642
+ const real = await fs51.realpath(target);
23643
+ if (isHiddenHostPath(real))
23644
+ throw hiddenAsMissing("realpath", target);
23645
+ return real;
23646
+ }
23629
23647
  app2.get("/files/download", async (c) => {
23630
23648
  try {
23631
23649
  const filePath = c.req.query("path");
@@ -23638,16 +23656,23 @@ function createFileRoutes(opts = {}) {
23638
23656
  if (!projectPath) {
23639
23657
  return c.json({ error: "Project not found" }, 404);
23640
23658
  }
23641
- const isTmp = path60.isAbsolute(filePath) && isInTempDir(filePath);
23642
- if (!isTmp && !validatePath(filePath, projectPath)) {
23643
- return c.json({ error: "Path traversal not allowed" }, 403);
23659
+ let absolutePath;
23660
+ if (path60.isAbsolute(filePath)) {
23661
+ const target = systemPath(filePath);
23662
+ if (!target)
23663
+ return c.json({ error: "absolute path without .. required" }, 400);
23664
+ absolutePath = await readableRealPath(target);
23665
+ } else {
23666
+ if (!validatePath(filePath, projectPath)) {
23667
+ return c.json({ error: "Path traversal not allowed" }, 403);
23668
+ }
23669
+ absolutePath = path60.resolve(projectPath, filePath);
23644
23670
  }
23645
- const absolutePath = isTmp ? path60.resolve(filePath) : path60.resolve(projectPath, filePath);
23646
23671
  const stat = await fs51.stat(absolutePath);
23647
23672
  if (stat.isDirectory()) {
23648
23673
  return c.json({ error: "Cannot download a directory" }, 400);
23649
23674
  }
23650
- const fileName = path60.basename(filePath);
23675
+ const fileName = path60.basename(absolutePath);
23651
23676
  const ext = fileName.split(".").pop()?.toLowerCase() ?? "";
23652
23677
  const mime = inline ? imageMimeFromExt(ext) ?? MIME_MAP[ext] ?? "application/octet-stream" : "application/octet-stream";
23653
23678
  const disposition = inline ? `inline; filename="${encodeURIComponent(fileName)}"` : `attachment; filename="${encodeURIComponent(fileName)}"`;
@@ -23690,11 +23715,12 @@ function createFileRoutes(opts = {}) {
23690
23715
  }
23691
23716
  return new Response(webStream, { status, headers });
23692
23717
  } catch (err) {
23693
- if (err.code === "ENOENT")
23718
+ const status = fsErrorStatus(err);
23719
+ if (status === 404)
23694
23720
  return c.json({ error: "File not found" }, 404);
23695
23721
  const errorMessage = err instanceof Error ? err.message : String(err);
23696
23722
  console.log(`[Files] Error downloading: ${errorMessage}`);
23697
- return c.json({ error: errorMessage }, 500);
23723
+ return c.json({ error: errorMessage }, status);
23698
23724
  }
23699
23725
  });
23700
23726
  app2.get("/files/download-folder", async (c) => {
@@ -23874,24 +23900,6 @@ function createFileRoutes(opts = {}) {
23874
23900
  return c.json({ error: err.message }, 404);
23875
23901
  }
23876
23902
  });
23877
- function systemPath(target) {
23878
- if (!target || !path60.isAbsolute(target) || target.split(/[\\/]/).includes(".."))
23879
- return null;
23880
- return path60.resolve(target);
23881
- }
23882
- const fsErrorStatus = (err) => {
23883
- const code = err.code;
23884
- return code === "ENOENT" || code === "ENOTDIR" ? 404 : code === "EACCES" || code === "EPERM" ? 403 : 500;
23885
- };
23886
- function hiddenAsMissing(syscall, target) {
23887
- return Object.assign(new Error(`ENOENT: no such file or directory, ${syscall} '${target}'`), { code: "ENOENT" });
23888
- }
23889
- async function readableRealPath(target) {
23890
- const real = await fs51.realpath(target);
23891
- if (isHiddenHostPath(real))
23892
- throw hiddenAsMissing("realpath", target);
23893
- return real;
23894
- }
23895
23903
  app2.get("/fs/stat", async (c) => {
23896
23904
  const target = systemPath(c.req.query("path"));
23897
23905
  if (!target)
@@ -23928,7 +23936,6 @@ var init_files2 = __esm({
23928
23936
  "../server/dist/routes/files.js"() {
23929
23937
  "use strict";
23930
23938
  init_dist();
23931
- init_media();
23932
23939
  init_workspace_path();
23933
23940
  init_sandbox();
23934
23941
  init_folder_zip();
@@ -31001,7 +31008,7 @@ function buildCard(workspace, interfaceUrl, caps) {
31001
31008
  return {
31002
31009
  name: raw.name,
31003
31010
  description: raw.description,
31004
- version: typeof raw.version === "string" ? raw.version : "2.0.5",
31011
+ version: typeof raw.version === "string" ? raw.version : "2.0.6",
31005
31012
  supportedInterfaces: [{ url: interfaceUrl, protocolBinding: "JSONRPC", protocolVersion: A2A_VERSION }],
31006
31013
  capabilities: { streaming: caps.streaming, pushNotifications: true, extendedAgentCard: false },
31007
31014
  ...caps.tokenAuth === false ? {} : {
@@ -33760,7 +33767,7 @@ function createCoreChecker(opts) {
33760
33767
  }
33761
33768
  function getCoreStatus(force) {
33762
33769
  checker ??= createCoreChecker({
33763
- haloVersion: "2.0.5",
33770
+ haloVersion: "2.0.6",
33764
33771
  fetchLatest: fetchNpmLatest,
33765
33772
  onChange: (status) => broadcast({ type: "updates:changed", scope: "core", status })
33766
33773
  });
@@ -33928,7 +33935,7 @@ function hubBase() {
33928
33935
  }
33929
33936
  function serverChecker() {
33930
33937
  checker2 ??= createExtensionsChecker({
33931
- haloVersion: "2.0.5",
33938
+ haloVersion: "2.0.6",
33932
33939
  installed: () => {
33933
33940
  const s = getSnapshot();
33934
33941
  return [...s.extensions, ...s.disabled];
@@ -40213,7 +40220,7 @@ var init_dist2 = __esm({
40213
40220
  init_git_ssh();
40214
40221
  __dirname3 = path90.dirname(fileURLToPath3(import.meta.url));
40215
40222
  PORT = config.server.port;
40216
- HALO_VERSION = "2.0.5";
40223
+ HALO_VERSION = "2.0.6";
40217
40224
  PROJECT_ROOT = findProjectRoot();
40218
40225
  HALO_HOME4 = path90.join(homedir25(), ".halo");
40219
40226
  GIT_SHA = readGitSha();
@@ -42391,7 +42398,7 @@ function installUserUnit(opts, run = runCommand) {
42391
42398
  }
42392
42399
 
42393
42400
  // src/index.ts
42394
- var VERSION = "2.0.5";
42401
+ var VERSION = "2.0.6";
42395
42402
  var HELP_TOP = `Usage: halo <command> [options]
42396
42403
 
42397
42404
  Commands:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@turmind/halo",
3
- "version": "2.0.5",
3
+ "version": "2.0.6",
4
4
  "description": "Halo — multi-agent collaborative workspace. CLI + TUI + HTTP/WS server in one package.",
5
5
  "type": "module",
6
6
  "license": "MIT",