@turmind/halo 1.6.1 → 1.6.2

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><!--j6buZnQDPISEFgtAuTGyl--><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/3b4dcd0ac6b8eae8.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-ddba0eb72566da23.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/147-d4200c70445aabb6.js" async=""></script><script src="/_next/static/chunks/app/page-be47983ba8ff20b1.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-ddba0eb72566da23.js\",\"177\",\"static/chunks/app/layout-ea161287d934ba96.js\"],\"ThemeProvider\"]\n3:I[24554,[\"989\",\"static/chunks/989-ddba0eb72566da23.js\",\"177\",\"static/chunks/app/layout-ea161287d934ba96.js\"],\"AppI18nProvider\"]\n4:I[63693,[],\"\"]\n5:I[74713,[],\"\"]\n6:I[5444,[],\"ClientPageRoot\"]\n7:I[41506,[\"560\",\"static/chunks/1d2d5650-d8d130c85727fdbb.js\",\"147\",\"static/chunks/147-d4200c70445aabb6.js\",\"989\",\"static/chunks/989-ddba0eb72566da23.js\",\"974\",\"static/chunks/app/page-be47983ba8ff20b1.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/3b4dcd0ac6b8eae8.css\",\"style\"]\n:HL[\"/_next/static/css/659eccb5db697b76.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"b\":\"j6buZnQDPISEFgtAuTGyl\",\"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/3b4dcd0ac6b8eae8.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><!--VgAe62AuGEiYrF4JQ7WQe--><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/3b4dcd0ac6b8eae8.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-ddba0eb72566da23.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/147-d4200c70445aabb6.js" async=""></script><script src="/_next/static/chunks/app/page-1d27029caba48956.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-ddba0eb72566da23.js\",\"177\",\"static/chunks/app/layout-ea161287d934ba96.js\"],\"ThemeProvider\"]\n3:I[24554,[\"989\",\"static/chunks/989-ddba0eb72566da23.js\",\"177\",\"static/chunks/app/layout-ea161287d934ba96.js\"],\"AppI18nProvider\"]\n4:I[63693,[],\"\"]\n5:I[74713,[],\"\"]\n6:I[5444,[],\"ClientPageRoot\"]\n7:I[41506,[\"560\",\"static/chunks/1d2d5650-d8d130c85727fdbb.js\",\"147\",\"static/chunks/147-d4200c70445aabb6.js\",\"989\",\"static/chunks/989-ddba0eb72566da23.js\",\"974\",\"static/chunks/app/page-1d27029caba48956.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/3b4dcd0ac6b8eae8.css\",\"style\"]\n:HL[\"/_next/static/css/659eccb5db697b76.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"b\":\"VgAe62AuGEiYrF4JQ7WQe\",\"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/3b4dcd0ac6b8eae8.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[41506,["560","static/chunks/1d2d5650-d8d130c85727fdbb.js","147","static/chunks/147-d4200c70445aabb6.js","989","static/chunks/989-ddba0eb72566da23.js","974","static/chunks/app/page-be47983ba8ff20b1.js"],"default"]
7
+ 7:I[41506,["560","static/chunks/1d2d5650-d8d130c85727fdbb.js","147","static/chunks/147-d4200c70445aabb6.js","989","static/chunks/989-ddba0eb72566da23.js","974","static/chunks/app/page-1d27029caba48956.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/3b4dcd0ac6b8eae8.css","style"]
17
17
  :HL["/_next/static/css/659eccb5db697b76.css","style"]
18
- 0:{"P":null,"b":"j6buZnQDPISEFgtAuTGyl","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/3b4dcd0ac6b8eae8.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":"VgAe62AuGEiYrF4JQ7WQe","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/3b4dcd0ac6b8eae8.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"}]]
@@ -239,7 +239,7 @@ The ipynb extension (2.0.0+) runs cells on **real kernels on the Halo machine**.
239
239
 
240
240
  An extension can ship agent skills next to its viewer: `~/.halo/global/extensions/<extId>/skills/<id>/` (`SKILL.md` + resource files + optional `config.yaml`, the ordinary skill layout). Discovery is by directory; the manifest has no skills field. `packages/server/src/agents/skill-sources.ts` is the one resolver: every skill reader goes through `listSkillDirs` / `skillSourceDir`. That covers session build / `activate_skill`, slash commands, the `/skill` verbs, `GET /skills`, Settings → Skills and evo's listing.
241
241
 
242
- - **Which folders count**: only extensions whose manifest passes the registry's own validator (`readExtensionDir`, verdict cached per manifest mtime; an extension with no `skills/` subdirs is skipped without reading its manifest). A skill id must match `^[\w-]+$` and equal `<extId>` or start with `<extId>-`; anything else is ignored with one `[Skills] extension "<extId>": ignoring skills/<id> …` warning per manifest version, not per scan. If two extensions claim one id (`foo`'s `foo-bar` vs extension `foo-bar`), the lower extension id keeps it. Manifest `platforms` is not applied: it only decides where the viewer is offered, and an extension's skills load on every platform.
242
+ - **Which folders count**: only extensions whose manifest passes the registry's own validator (`readExtensionDir`, verdict and entry path cached per manifest mtime, the entry file re-checked on every scan; an extension with no `skills/` subdirs is skipped without reading its manifest). A skill id must match `^[\w-]+$` and equal `<extId>` or start with `<extId>-`; anything else is ignored with one `[Skills] extension "<extId>": ignoring skills/<id> …` warning per manifest version, not per scan. If two extensions claim one id (`foo`'s `foo-bar` vs extension `foo-bar`), the lower extension id keeps it. Manifest `platforms` is not applied: it only decides where the viewer is offered, and an extension's skills load on every platform.
243
243
  - **Precedence**: workspace > global > extension. A higher source with the same id wholly overrides (the whole folder, no per-file fallback); the shadowed extension copy is still listed with `overridden: true`. To customise an extension skill, copy its folder into `~/.halo/global/skills/<id>/` or `<workspace>/.halo/skills/<id>/`.
244
244
  - **Scope `extension`, read-only**: `GET /skills` returns them with `scope: 'extension'` and `extId`. `POST` / `DELETE /skills` with that scope answer 403, so they never fall through to a same-id global skill. `/skill delete` refuses them, and evo neither lists nor patches them. The admin shows them in a Skills → **Extensions** section, rendered as a read-only file view with no editor, create or delete, and the subtitle "from extension X".
245
245
  - **Not auto-enabled**: an agent uses one only when its `skills:` lists the id (ticked in the agent form like any skill). An id whose extension is gone shows the usual "not installed" hint.
@@ -40,6 +40,8 @@ Exactly **one** of `schedule` / `runAt` is set per job. `runner.ts` `scheduleJob
40
40
  - Clearing the active side with nothing to replace it (`schedule: ''` on a recurring job, `runAt: null` on an at-mode job) → `400 schedule or runAt required`. A triggerless job would sit `enabled` and never fire.
41
41
  - A non-number, non-null `runAt` is rejected (`400`) *before* the exclusivity check — otherwise garbage types slip past `typeof body.runAt === 'number'` and land in the db as-is.
42
42
 
43
+ The skill helper `manage-cron.py update` follows the same rules (`--schedule` / `--run-at` switch the mode, both or neither left is refused); `test/manage-cron-py.test.ts` pins its parity with REST.
44
+
43
45
  ### Hot-reload + out-of-band edits
44
46
 
45
47
  REST route mutations call `scheduleJob` / `unscheduleJob` directly. But the `cron` skill (and manual ops) edit `cron.db` over a *different* sqlite connection. `reconcileFromDb` (10s timer) catches those:
@@ -222,7 +222,7 @@ type ContentBlockEntry =
222
222
 
223
223
  `turnId` uniquely identifies each LLM API call. Content blocks and the corresponding usage message in the same turn share the same turnId.
224
224
 
225
- The `usage` event rotates `turnId` on both root and sub-session turn state without flushing the assistant message: the agent loop yields `tool_call`s before `usage` and runs the tools after, so at usage time every tool call of that model call is still pending — a flush there would split thinking/text from the tool_calls into two assistant messages (the pre-fix sub-session behavior). One assistant message therefore spans all model calls of a turn, each call's blocks tagged with its own turnId; it reaches disk at `complete` / `agent_done`, the next `user` or `system` event, or the interrupt flush. Root and sub-session logs persist by one rule: `persistLog` overwrites the session's own file whole from its UI log, and every save carries the in-flight turn as a temporary assistant message (`createSaveSnapshot`). A sub-session log starts from its own file (`loadSubHistory`), so it always holds the full history; writes are debounced 500ms per session id (tool_call / tool_result / usage / context / user / system / error) and flushed at turn end (root `complete`, sub `agent_done`) and on interrupt.
225
+ The `usage` event rotates `turnId` on both root and sub-session turn state without flushing the assistant message: the agent loop yields `tool_call`s before `usage` and runs the tools after, so at usage time every tool call of that model call is still pending — a flush there would split thinking/text from the tool_calls into two assistant messages (the pre-fix sub-session behavior). One assistant message therefore spans all model calls of a turn, each call's blocks tagged with its own turnId; it reaches disk at `complete` / `agent_done`, the next `user`, `system` or `error` event, or the interrupt flush. Those three run `flushCompletedAssistantMessage` before logging their row: the content up to the first pending tool call is flushed above the row, and the pending tail stays in the buffer below it. `error` always lands in the root log, a sub-session's error included, so it splits the root's buffer (the admin adds the error frame with no taskId, and `placeAroundStreaming` splits the root bubble the same way). Root and sub-session logs persist by one rule: `persistLog` overwrites the session's own file whole from its UI log, and every save carries the in-flight turn as a temporary assistant message (`createSaveSnapshot`). A sub-session log starts from its own file (`loadSubHistory`), so it always holds the full history; writes are debounced 500ms per session id (tool_call / tool_result / usage / context / user / system / error) and flushed at turn end (root `complete`, sub `agent_done`) and on interrupt.
226
226
 
227
227
  ### Render rules
228
228
 
@@ -231,6 +231,8 @@ The `usage` event rotates `turnId` on both root and sub-session turn state witho
231
231
  | Normal | user, assistant, notification | tool_call, tool_result, usage, context, agent_start, agent_done |
232
232
  | Debug | user, assistant, notification, context, agent_start, agent_done + inlined usage | tool_call, tool_result (already inlined in the assistant's contentBlocks) |
233
233
 
234
+ Debug usage badges are grouped by turnId, not by log position: `buildExchanges` (`message-list.tsx`) puts each usage row in the exchange holding the last assistant message with a block of that turnId, and the badge renders after that turnId's last block. A usage row reaches the log when its model call returns, before the call's tools run, so a user row that lands mid-call is logged after the badge while the pending tool_calls are flushed below it. Grouping by position left the badge on the bubble above the user row. A usage row with no matching block falls back to the last assistant message of its own exchange.
235
+
234
236
  Assistant rendering priority:
235
237
  1. Has `contentBlocks` → render in contentBlocks order
236
238
  2. No contentBlocks, has `toolCalls` → tools first, then content (legacy)
@@ -526,8 +528,8 @@ Existing agent yaml values always win over these defaults — switching provider
526
528
  - `image` / `video` / `audio` (boolean) → modality badges in the form; at runtime, unsupported modality inputs are filtered out with a text notice instead of causing API errors
527
529
  - `promptCaching.ttlPresets` → Prompt Caching dropdown
528
530
  - `thinking.mode`:
529
- - `adaptive` → wire format `thinking: {type: 'adaptive'}` + `output_config.effort` (Sonnet 4.6+ / Opus 4.6 and later, incl. Opus 5)
530
- - `manual` → wire format `thinking: {type: 'enabled', budget_tokens: N}` (Haiku 4.5 and other legacy thinking models). UI offers a budget number input; runtime translates effort labels via the table in `bedrock-agent.ts` if needed.
531
+ - `adaptive` → wire format `thinking: {type: 'adaptive'}` + `output_config.effort` (Sonnet 4.6+ / Opus 4.6 and later, incl. Opus 5). Qwen 3.8 Max / Flash use the same `output_config.effort` with `thinking: {type: 'enabled'}`, unless the agent.yaml carries an explicit `budget_tokens`.
532
+ - `manual` → wire format `thinking: {type: 'enabled', budget_tokens: N}` (Haiku 4.5 and other legacy thinking models). UI offers a budget number input; runtime translates effort labels via `effortToBudget` in `anthropic-request.ts` if needed.
531
533
  - `thinking.effortPresets` → Thinking effort dropdown (when `mode: adaptive`)
532
534
  - Omit a block → the UI hides that control for this model
533
535
 
@@ -92,10 +92,10 @@ Source: [event-processor.ts](../../../packages/server/src/ws/event-processor.ts)
92
92
 
93
93
  | Agent event | WS type | Fields |
94
94
  |---|---|---|
95
- | `thinking_delta` | `chat:thinking` | text, agentName, taskId, turnId, sessionId |
96
- | `stream_delta` | `chat:stream` | text, agentName, taskId, turnId, sessionId |
97
- | `thinking` | `chat:thinking` | text, agentName, taskId, turnId, sessionId — **not forwarded** when `streamed: true` |
98
- | `stream` | `chat:stream` | text, agentName, taskId, turnId, sessionId — **not forwarded** when `streamed: true` |
95
+ | `thinking_delta` (no taskId) | `chat:thinking` | text, agentName, turnId, sessionId |
96
+ | `stream_delta` (no taskId) | `chat:stream` | text, agentName, turnId, sessionId |
97
+ | `thinking` (no taskId) | `chat:thinking` | text, agentName, turnId, sessionId — **not forwarded** when `streamed: true` |
98
+ | `stream` (no taskId) | `chat:stream` | text, agentName, turnId, sessionId — **not forwarded** when `streamed: true` |
99
99
  | `agent_start` | `agent:start` | agentName, task, taskId, sessionId |
100
100
  | `agent_done` | `agent:done` | agentName, taskId, sessionId |
101
101
  | `tool_call` | `agent:tool_call` | tool, toolUseId, input, agentName, taskId, turnId, sessionId |
@@ -110,6 +110,8 @@ Source: [event-processor.ts](../../../packages/server/src/ws/event-processor.ts)
110
110
 
111
111
  Every provider streams (Bedrock, the Anthropic-Messages providers anthropic / mimo / minimax / qwen, the OpenAI-family openai / deepseek / kimi / zhipu / doubao / hunyuan, and Mantle aws-bedrock-mantle / aws-bedrock-openai): they emit `stream_delta` / `thinking_delta` per chunk *during* the model call, and the whole `stream` / `thinking` that follows the call is stamped `streamed: true` — the wire frame is the same `chat:stream` / `chat:thinking` either way (the admin appends by `turnId`), so the whole event is dropped to avoid rendering the text twice. A provider that never calls `onDelta` would still send the whole event only, exactly as before streaming existed.
112
112
 
113
+ Sub-agent text is root-tree noise on this wire: the listener is the root's (sub ids normalize to it), every admin view filters `taskId` rows out, and the Sessions tab reads a sub-session's log from disk. So the four text events above go out **root only**. A sub-agent's `stream*` / `thinking*` produce no frame, while its `agent:start` / `agent:done`, tool frames, `agent:context`, `chat:system` and `error` still carry `taskId`. Web SSE (and ACP on top of it), the IM channels and A2A register their own event listeners rather than reading these frames, so they are unaffected. Two harmless side effects in the admin. A text-only sub-agent leaves its empty `agent:start` placeholder in the root store, and after a link drop `convergeStaleStreaming` may mark it interrupted; every view filters that row out anyway. A background tab's unread dot no longer lights for sub-agent text alone, though the sub-agent's tool and `agent:*` frames still light it.
114
+
113
115
  `sessionId` is the session the emitting listener belongs to. A connection holds one listener per subscribed session (`createEventListener(client, sessionId)`), and each listener is bound to its id when it is created. Since 1.5.3-alpha the session-scoped frames sent outside the event mapping carry it too: `compact:started` / `compact:summarizing` / `compact:done`, `session:compacted`, `chat:queued`, `chat:system` / `error` replies to a command or chat, the detached-buffer replays (`agent:start` / `agent:done` / `error` / `chat:followup` from `bufferDetachedNotification`), and `chat:usage` on subscribe.
114
116
 
115
117
  **Admin routing** (`storeForFrame` in `chat-tabs.ts`, used by `chat-handlers.ts` / `agent-handlers.ts` / `state-handlers.ts`): a frame with a `sessionId` goes to the store of the loaded tab holding that session, background tabs included. A frame landing in a background tab lights its unread dot; state flips (snapshot, compact progress) don't. A frame for a session no tab has loaded (never opened, or released by a reconnect) is dropped. A frame without a `sessionId` (connection-level replies) goes to the tab on screen. `<<<CAPTURE>>>` / `<<<SHOW>>>` markers fire on `chat:complete` only for the tab on screen — a background session must not grab a screen frame or drive the face the user is looking at.
@@ -24,9 +24,9 @@ Runtime names (`runtime:` value → class): `bedrock-invoke` → `BedrockAgent`,
24
24
  |---|---|---|---|---|
25
25
  | `aws-bedrock-claude-invoke` | `bedrock-invoke` | `BedrockAgent` | `bedrock-agent.ts` | Anthropic Messages API via AWS SDK |
26
26
  | `kimi` | `kimi` | `KimiAgent` | `kimi-agent.ts` | OpenAI-compatible, streaming via `fetchChatCompletionStream` (usage arrives in its own `choices: []` chunk), thinking (reasoning_content). Cached tokens via `cachedPromptTokens` (every known usage key — which one Kimi reports isn't pinned). Two API generations, branched on modelId: **K3** — vision (base64 data URLs only, no public-URL input), thinking always-on server-side, sole knob is top-level `reasoning_effort` (enum currently just `"max"`); **K2.6** — no vision, no `reasoning_effort` field at all, only the `thinking:{type:'enabled'|'disabled'}` toggle. Never send the K2.x `thinking` parameter to K3 |
27
- | `deepseek` | `deepseek` | `DeepSeekAgent` | `deepseek-agent.ts` | OpenAI-compatible, streaming via `fetchChatCompletionStream` (first chunk has `content: null` + `reasoning_content: ''`; the usage chunk still carries `choices`), thinking (reasoning_content). Vision per model: `deepseek-flash` (V4.1-Flash) sees `image_url` data URLs; `deepseek-v4-pro` accepts the block but ignores it (live-probed 2026-09-24 with a 64×64 blue PNG) — registry `image` flag gates it |
27
+ | `deepseek` | `deepseek` | `DeepSeekAgent` | `deepseek-agent.ts` | OpenAI-compatible, streaming via `fetchChatCompletionStream` (first chunk has `content: null` + `reasoning_content: ''`; the usage chunk still carries `choices`), thinking (reasoning_content). Thinking is on by default, so off is sent explicitly as `thinking:{type:'disabled'}`. On, it sends `reasoning_effort` with the label unmapped: presets are the API's own low / high / max, and the API folds medium / xhigh to high itself, so older agents keep working. Vision per model: `deepseek-flash` (V4.1-Flash) sees `image_url` data URLs; `deepseek-v4-pro` accepts the block but ignores it (live-probed 2026-09-24 with a 64×64 blue PNG) — registry `image` flag gates it |
28
28
  | `minimax` | `minimax` | `MiniMaxAgent` | `minimax-agent.ts` | Anthropic Messages API (x-api-key), streaming via `fetchAnthropicStream` — note `message_start.usage` is all zeros and the real input / cache counts arrive in `message_delta.usage` (the accumulator takes them from there). Two thinking schemes, branched on registry `thinking.mode`: **M3** (default) — vision, thinking off by default and enabled via `thinking:{type:'adaptive'}` (no levels, no budget_tokens), no `promptCaching` in the manifest on purpose (official docs scope `cache_control` to M2.x only; M3 has passive automatic caching); **M2.7** — no vision, thinking always-on (manual budget_tokens), prompt caching (5m, M2.7 doesn't report cache_creation_input_tokens) |
29
- | `qwen` | `qwen` | `QwenAgent` | `qwen-agent.ts` | Aliyun Bailian Anthropic-compatible API, streaming via `fetchAnthropicStream` (SSE frames come as `data:{…}` with no space after the colon — the reader accepts both), thinking enable/disable both honored, prompt caching (5m only), vision on Plus, max no vision |
29
+ | `qwen` | `qwen` | `QwenAgent` | `qwen-agent.ts` | Aliyun Bailian Anthropic-compatible API, streaming via `fetchAnthropicStream` (SSE frames come as `data:{…}` with no space after the colon — the reader accepts both), thinking enable/disable both honored; omitting the field means thinking on, so off is always sent as `type:'disabled'`. Two thinking schemes, branched on registry `thinking.mode`: **3.8 Max / Flash** (`adaptive`) send `thinking:{type:'enabled'}` + `output_config.effort` (low / medium / xhigh; the API folds high / max onto xhigh). **3.7 / 3.6** (`manual`) send `budget_tokens` via `effortToBudget`. An agent.yaml with an explicit `budget_tokens` keeps sending it on either. Prompt caching (5m only), vision on Plus, max no vision |
30
30
  | `hunyuan` | `hunyuan` | `HunyuanAgent` | `hunyuan-agent.ts` | Tencent Hy3 / Hy4 preview / Hy3 preview via OpenAI-compatible (tokenhub.tencentmaas.com), streaming via `fetchChatCompletionStream` (`stream_options.include_usage` accepted; usage in its own `choices: []` chunk), reasoning_effort low/high, thinking off sends `reasoning_effort: 'none'` (an omitted field thinks by default — live-probed 2026-10-10), automatic prompt caching (cached_tokens), no vision |
31
31
  | `doubao` | `doubao` | `DoubaoAgent` | `doubao-agent.ts` | ByteDance Doubao Seed 2.1 Pro + Seed-2.0 (pro/lite/mini/code) on Volcengine Ark, OpenAI-compatible, streaming via `fetchChatCompletionStream` (usage in its own `choices: []` chunk) + `thinking:{type:'enabled'/'disabled'}` (no `auto`), automatic prompt caching. Images go out as `image_url` content parts; only 2.1 Pro is `image: true` (the 2.0 models misread a red PNG), so the registry flag gates the rest |
32
32
  | `zhipu` | `zhipu` | `ZhipuAgent` | `zhipu-agent.ts` | Zhipu GLM-5.x on open.bigmodel.cn, OpenAI-compatible, streaming via `fetchChatCompletionStream` (tool-call arguments arrive complete in one fragment; usage chunk carries `choices`). Output cap via `max_tokens` only (`max_completion_tokens` is silently ignored). Thinking branched on modelId: **glm-5.3\*** always thinks — always sends `thinking:{type:'enabled',clear_thinking:false}`, `reasoning_effort` only when low/high/max (`disabled` / other efforts 400); other ids (glm-5.2) honour `thinking:{type:'disabled'}`. Vision per model: `glm-5.3-flash` / `glm-5.3-flashx` see `image_url` data URLs; `glm-5.3` / `glm-5.2` are text-only and 400 on any image part (code 1210, classified `multimodal_4xx` so leftover history images degrade). Automatic caching, `prompt_tokens_details.cached_tokens` (included in `prompt_tokens`, subtracted). |
@@ -981,8 +981,8 @@ It does not remove session files. The full delete (rows + JSON + archive segment
981
981
 
982
982
  | Type | Fields | Purpose |
983
983
  |---|---|---|
984
- | `chat:stream` | `text`, `agentName`, `turnId`, `taskId?` | Text chunk from the agent |
985
- | `chat:thinking` | `text`, `agentName`, `turnId`, `taskId?` | Thinking chunk |
984
+ | `chat:stream` | `text`, `agentName`, `turnId` | Text chunk from the root agent (a sub-agent's text isn't sent on this wire — see [design/ws.md](../design/ws.md#agent-event--ws-message-mapping)) |
985
+ | `chat:thinking` | `text`, `agentName`, `turnId` | Thinking chunk (root only, as above) |
986
986
  | `agent:tool_call` | `tool`, `toolUseId`, `input`, `agentName`, `turnId`, `taskId?` | Tool invocation card |
987
987
  | `agent:tool_result` | `result`, `toolUseId`, `agentName`, `durationMs`, `taskId?` | Tool result |
988
988
  | `chat:usage` | `contextTokens`, `outputTokens`, `usage`, `modelId`, `turnId` | Token accounting per model call (root only) |
@@ -23,7 +23,7 @@ The primary surface for talking to an agent.
23
23
  - Markdown + code-block highlighting
24
24
  - Tool-call card: expandable, shows tool name / input / output
25
25
  - Sub-agent streams stay out of the chat: their reports land as a green callout, and Debug mode adds agent start/done markers labelled with the agent name (e.g. "Coder", "Researcher")
26
- - A reply that has produced nothing yet shows a spinner with "Thinking..."; once the model streams reasoning text, the spinner gives way to a **live thinking panel**: expanded, muted, with a "Thinking..." header and char count, capped at about 9 lines and tailing its own text (so the chat log grows by at most the cap). It folds to the one-line collapsed "Thinking · N chars" header (click to expand; it stays in the log) as soon as text or a tool call follows, or the message settles. Providers that stream no reasoning text stay on the spinner; Debug mode is unchanged (spinner until text or a tool call arrives, collapsed headers only)
26
+ - A reply that has produced nothing yet shows a spinner with "Thinking..."; once the model streams reasoning text, the spinner gives way to a **live thinking panel**: expanded, muted, with a "Thinking..." header and char count, capped at about 9 lines and tailing its own text (so the chat log grows by at most the cap). It folds to the one-line collapsed "Thinking · N chars" header (click to expand; it stays in the log) as soon as text or a tool call follows, or the message settles. Providers that stream no reasoning text stay on the spinner. Debug mode shows the same live panel; it only adds to the normal view
27
27
  - **Follow the bottom by intent**: while a reply streams the log follows its end, and scrolling up stops the follow. Upward input — mouse wheel, touch drag, PageUp / ArrowUp / Home / Shift+Space, or grabbing the scrollbar — detaches the moment it arrives, so a fast stream can't snap the view back mid-gesture; upward input that a nested scroller (the live thinking panel, an expanded tool body) would take doesn't count. The log re-attaches only when the view is scrolled back down to within 80 px of the end. Applies to the chat panel, the Sessions tab viewer and the live thinking panel alike; a reader scrolling inside the thinking panel stops its tail the same way
28
28
  - The user bubble shows its send time (`HH:mm`, browser-local) at the left of its header row, after the expand chevron (see [User-message actions](#user-message-actions-expand--copy--delete)); hovering it gives the full date. Same bubble component as the Sessions tab, so both surfaces get it
29
29
  - In Debug mode the system-prompt `context` row stays in the list but doesn't open an exchange of its own, so there is no blank strip above the first bubble
@@ -86,7 +86,7 @@ See [requirements/command.md](command.md) for the full command surface.
86
86
  ### Graceful interrupt
87
87
  Sending a new message while the agent is generating **does not** abort — the message goes to the server queue, the agent finishes the current turn at the next safe checkpoint (after a tool call), and then runs the queued message. Queueing multiple messages is supported; they run in order.
88
88
 
89
- **Live placement.** When a main user message or notification lands while the main bubble is still streaming, the live view lays it out the way the server persists it, so it matches what a reload shows. Before logging such a row the server runs `flushCompletedAssistantMessage`: the streaming content up to its first pending tool call settles **above** the row, and the rest (or a fresh empty streaming slot) continues streaming **below** it (`placeAroundStreaming` in `chat-store.ts`).
89
+ **Live placement.** When a main user message or notification (an error row included) lands while the main bubble is still streaming, the live view lays it out the way the server persists it, so it matches what a reload shows. Before logging such a row the server runs `flushCompletedAssistantMessage`: the streaming content up to its first pending tool call settles **above** the row, and the rest (or a fresh empty streaming slot) continues streaming **below** it (`placeAroundStreaming` in `chat-store.ts`).
90
90
 
91
91
  ### Stop
92
92
  The Stop button hard-aborts — the server receives `chat:stop`, AbortController fires, queue clears, buffers flush.
@@ -25,7 +25,7 @@ Session history viewer: hierarchy tree, message playback, debug mode, system pro
25
25
  Top Debug toggle (Bug icon), persisted in `localStorage` as `halo_session_debug`. When on:
26
26
  - **Normal mode**: user message + assistant reply (with inline tool-call cards, click to expand IN / OUT); sub-agent notifications hidden
27
27
  - **Debug mode**: adds, on top of the normal view:
28
- - **Thinking** blocks (purple, expandable, with char count) inside assistant messages
28
+ - **Thinking** blocks (purple, expandable, with char count) inside assistant messages. While a reply streams, its thinking shows in the same live panel as the normal view
29
29
  - **Usage** line after each turn — timestamp, token counts (in / out / ctx, cache read / write / hit ratio), latency (ttft / e2e), thinking effort, model ID
30
30
  - Sub-agent start / done markers labelled with the agent name
31
31
 
package/dist/index.js CHANGED
@@ -1719,6 +1719,13 @@ import { homedir as homedir6 } from "node:os";
1719
1719
  function isSkillDisabled(disabledSet, id) {
1720
1720
  return SKILL_SCOPES.some((scope) => disabledSet.has(`${scope}:${id}`));
1721
1721
  }
1722
+ function isFile(p) {
1723
+ try {
1724
+ return fs6.statSync(p).isFile();
1725
+ } catch {
1726
+ return false;
1727
+ }
1728
+ }
1722
1729
  function childDirs(parent) {
1723
1730
  let names;
1724
1731
  try {
@@ -1756,8 +1763,12 @@ function extensionSkillDirs() {
1756
1763
  } catch {
1757
1764
  continue;
1758
1765
  }
1759
- const ok = _manifestOk.get(manifest, mtimeMs) ?? _manifestOk.set(manifest, mtimeMs, !("error" in readExtensionDir(extDir)));
1760
- if (!ok)
1766
+ let entry = _manifestEntry.get(manifest, mtimeMs);
1767
+ if (entry === void 0) {
1768
+ const ext = readExtensionDir(extDir);
1769
+ entry = _manifestEntry.set(manifest, mtimeMs, "error" in ext ? null : path8.join(extDir, ext.entry));
1770
+ }
1771
+ if (!entry || !isFile(entry))
1761
1772
  continue;
1762
1773
  const ignored = [];
1763
1774
  for (const id of ids.sort()) {
@@ -1810,7 +1821,7 @@ function skillSourceDir(skillId, workspaceRoot) {
1810
1821
  return globalDir2;
1811
1822
  return extensionSkillDirs().find((s) => s.id === skillId)?.dir ?? globalDir2;
1812
1823
  }
1813
- var GLOBAL_SKILLS_DIR, SKILL_ID_RE, SKILL_SCOPES, _manifestOk, _warned;
1824
+ var GLOBAL_SKILLS_DIR, SKILL_ID_RE, SKILL_SCOPES, _manifestEntry, _warned;
1814
1825
  var init_skill_sources = __esm({
1815
1826
  "../server/dist/agents/skill-sources.js"() {
1816
1827
  "use strict";
@@ -1819,7 +1830,7 @@ var init_skill_sources = __esm({
1819
1830
  GLOBAL_SKILLS_DIR = path8.join(homedir6(), ".halo", "global", "skills");
1820
1831
  SKILL_ID_RE = /^[\w-]+$/;
1821
1832
  SKILL_SCOPES = ["workspace", "global", "extension"];
1822
- _manifestOk = createMtimeCache();
1833
+ _manifestEntry = createMtimeCache();
1823
1834
  _warned = /* @__PURE__ */ new Set();
1824
1835
  }
1825
1836
  });
@@ -1914,9 +1925,12 @@ function generalSection() {
1914
1925
  }
1915
1926
  function readYamlFile(p) {
1916
1927
  try {
1917
- const raw = fs7.readFileSync(p, "utf-8");
1918
- const parsed = YAML3.parse(raw);
1919
- return parsed && typeof parsed === "object" ? parsed : null;
1928
+ const { mtimeMs } = fs7.statSync(p);
1929
+ const hit = _yamlCache.get(p, mtimeMs);
1930
+ if (hit !== void 0)
1931
+ return hit;
1932
+ const parsed = YAML3.parse(fs7.readFileSync(p, "utf-8"));
1933
+ return _yamlCache.set(p, mtimeMs, parsed && typeof parsed === "object" ? parsed : null);
1920
1934
  } catch {
1921
1935
  return null;
1922
1936
  }
@@ -1981,13 +1995,16 @@ function buildSkillSection(skillsDir, skillId) {
1981
1995
  return null;
1982
1996
  let displayName = skillId;
1983
1997
  try {
1984
- const md = fs7.readFileSync(path9.join(skillsDir, skillId, "SKILL.md"), "utf-8");
1985
- const m = md.match(/^---\s*\n([\s\S]*?)\n---/);
1986
- if (m) {
1987
- const nameMatch = m[1].match(/^name:\s*(.+)$/m);
1988
- if (nameMatch)
1989
- displayName = nameMatch[1].trim();
1990
- }
1998
+ const mdPath = path9.join(skillsDir, skillId, "SKILL.md");
1999
+ const { mtimeMs } = fs7.statSync(mdPath);
2000
+ let name = _skillNameCache.get(mdPath, mtimeMs);
2001
+ if (name === void 0) {
2002
+ const m = fs7.readFileSync(mdPath, "utf-8").match(/^---\s*\n([\s\S]*?)\n---/);
2003
+ const nameMatch = m?.[1].match(/^name:\s*(.+)$/m);
2004
+ name = _skillNameCache.set(mdPath, mtimeMs, nameMatch ? nameMatch[1].trim() : null);
2005
+ }
2006
+ if (name)
2007
+ displayName = name;
1991
2008
  } catch {
1992
2009
  }
1993
2010
  return {
@@ -2074,7 +2091,7 @@ function extensionSections() {
2074
2091
  }
2075
2092
  return sections;
2076
2093
  }
2077
- var GLOBAL_AGENTS_DIR, DEFAULT_A2A_URL_ALLOWLIST, DEFAULT_FILES_SUMMARY, VALID_TYPES;
2094
+ var GLOBAL_AGENTS_DIR, DEFAULT_A2A_URL_ALLOWLIST, DEFAULT_FILES_SUMMARY, _yamlCache, _skillNameCache, VALID_TYPES;
2078
2095
  var init_settings_schema = __esm({
2079
2096
  "../server/dist/settings-schema.js"() {
2080
2097
  "use strict";
@@ -2082,9 +2099,12 @@ var init_settings_schema = __esm({
2082
2099
  init_registry();
2083
2100
  init_registry2();
2084
2101
  init_skill_sources();
2102
+ init_mtime_cache();
2085
2103
  GLOBAL_AGENTS_DIR = path9.join(homedir7(), ".halo", "global", "agents");
2086
2104
  DEFAULT_A2A_URL_ALLOWLIST = "100.64.0.0/10,*.ts.net";
2087
2105
  DEFAULT_FILES_SUMMARY = DEFAULT_HIDDEN_FILES.filter((f) => !/-(wal|shm)$/.test(f)).join(", ");
2106
+ _yamlCache = createMtimeCache();
2107
+ _skillNameCache = createMtimeCache();
2088
2108
  VALID_TYPES = /* @__PURE__ */ new Set(["string", "int", "float", "boolean", "enum"]);
2089
2109
  }
2090
2110
  });
@@ -4024,7 +4044,7 @@ var init_init = __esm({
4024
4044
  path13.resolve(__dirname, "..", "bundled-docs"),
4025
4045
  path13.resolve(__dirname, "..", "..", "..", ".halo", "docs")
4026
4046
  ];
4027
- TEMPLATE_VERSION = 98;
4047
+ TEMPLATE_VERSION = 99;
4028
4048
  VERSION_FILE = ".template-version";
4029
4049
  SKIP_NAMES = /* @__PURE__ */ new Set([".DS_Store", "schema.sql", "__pycache__", ".pytest_cache"]);
4030
4050
  BUILTIN_AGENT_IDS = /* @__PURE__ */ new Set([
@@ -5888,8 +5908,13 @@ async function readEntries(dirs) {
5888
5908
  for (const { id: entryName, dir: skillDir } of dirs) {
5889
5909
  const skillMdPath = path21.join(skillDir, "SKILL.md");
5890
5910
  try {
5891
- const content = await fs18.readFile(skillMdPath, "utf-8");
5892
- const { name, description, command, requiresAccess, verbs, userInvocable } = parseSkillFrontmatter(content);
5911
+ const { mtimeMs } = await fs18.stat(skillMdPath);
5912
+ let fm = _frontmatterCache.get(skillMdPath, mtimeMs);
5913
+ if (!fm) {
5914
+ const { name: name2, description: description2, command: command2, requiresAccess: requiresAccess2, verbs: verbs2, userInvocable: userInvocable2 } = parseSkillFrontmatter(await fs18.readFile(skillMdPath, "utf-8"));
5915
+ fm = _frontmatterCache.set(skillMdPath, mtimeMs, { name: name2, description: description2, command: command2, requiresAccess: requiresAccess2, verbs: verbs2, userInvocable: userInvocable2 });
5916
+ }
5917
+ const { name, description, command, requiresAccess, verbs, userInvocable } = fm;
5893
5918
  if (userInvocable === false) {
5894
5919
  entries.push({ id: entryName, name: name || entryName, description: description ?? "", command: "", skillPath: skillMdPath, requiresAccess, verbs });
5895
5920
  continue;
@@ -6000,6 +6025,7 @@ ${body}`;
6000
6025
  });
6001
6026
  return "ok";
6002
6027
  }
6028
+ var _frontmatterCache;
6003
6029
  var init_skill_command = __esm({
6004
6030
  "../server/dist/commands/skill-command.js"() {
6005
6031
  "use strict";
@@ -6008,7 +6034,9 @@ var init_skill_command = __esm({
6008
6034
  init_skill_sources();
6009
6035
  init_md_vars();
6010
6036
  init_db();
6037
+ init_mtime_cache();
6011
6038
  init_i18n();
6039
+ _frontmatterCache = createMtimeCache();
6012
6040
  }
6013
6041
  });
6014
6042
 
@@ -9651,6 +9679,7 @@ function applyEvent(state, event, loadHistory2) {
9651
9679
  break;
9652
9680
  }
9653
9681
  case "error":
9682
+ flushCompletedAssistantMessage(state);
9654
9683
  state.messageLog.push({
9655
9684
  id: genId(),
9656
9685
  type: "notification",
@@ -11146,10 +11175,13 @@ var init_deepseek_agent = __esm({
11146
11175
  max_completion_tokens: this.config.maxTokens ?? resolveMaxOutputTokens(this.config.modelId),
11147
11176
  ...tools.length > 0 ? { tools } : {}
11148
11177
  };
11149
- if (this.config.thinking?.effort === "disabled") {
11178
+ const effort = this.config.thinking?.enabled ? this.config.thinking.effort : void 0;
11179
+ if (!this.config.thinking?.enabled || effort === "disabled") {
11150
11180
  body.thinking = { type: "disabled" };
11151
11181
  } else {
11152
11182
  body.thinking = { type: "enabled" };
11183
+ if (effort)
11184
+ body.reasoning_effort = effort;
11153
11185
  }
11154
11186
  const folded = await fetchChatCompletionStream({
11155
11187
  url,
@@ -11306,9 +11338,14 @@ var init_qwen_agent = __esm({
11306
11338
  ...anthropicPromptFields(this.config.systemPrompt, this.config.tools, this.messages, cacheControl)
11307
11339
  };
11308
11340
  if (this.config.thinking?.enabled && this.config.thinking.effort) {
11309
- const budget = this.config.thinkingBudgetTokens ?? effortToBudget(this.config.thinking.effort, this.config.maxTokens);
11310
- body.thinking = { type: "enabled", budget_tokens: capThinkingBudget(budget, this.config.maxTokens) };
11311
- } else if (this.config.thinking && !this.config.thinking.enabled) {
11341
+ if (this.config.thinkingMode === "adaptive" && this.config.thinkingBudgetTokens == null) {
11342
+ body.thinking = { type: "enabled" };
11343
+ body.output_config = { effort: this.config.thinking.effort };
11344
+ } else {
11345
+ const budget = this.config.thinkingBudgetTokens ?? effortToBudget(this.config.thinking.effort, this.config.maxTokens);
11346
+ body.thinking = { type: "enabled", budget_tokens: capThinkingBudget(budget, this.config.maxTokens) };
11347
+ }
11348
+ } else if (!this.config.thinking?.enabled) {
11312
11349
  body.thinking = { type: "disabled" };
11313
11350
  }
11314
11351
  return body;
@@ -11920,6 +11957,7 @@ function createModelRuntime(runtime, cfg) {
11920
11957
  maxTokens: cfg.maxTokens,
11921
11958
  promptCaching: cfg.promptCaching,
11922
11959
  thinking: cfg.thinking,
11960
+ thinkingMode: cfg.thinkingMode,
11923
11961
  thinkingBudgetTokens: cfg.thinkingBudgetTokens
11924
11962
  });
11925
11963
  case "hunyuan":
@@ -13944,7 +13982,7 @@ async function initObservability(haloProcess = "server") {
13944
13982
  return true;
13945
13983
  }
13946
13984
  const { registerSdk: registerSdk2 } = await Promise.resolve().then(() => (init_otel_sdk(), otel_sdk_exports));
13947
- providers = await registerSdk2(process.env.OTEL_SERVICE_NAME, "1.6.1", haloProcess);
13985
+ providers = await registerSdk2(process.env.OTEL_SERVICE_NAME, "1.6.2", haloProcess);
13948
13986
  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})`);
13949
13987
  return true;
13950
13988
  }
@@ -20751,13 +20789,13 @@ function createFileRoutes() {
20751
20789
  const full = path53.join(resolved, e.name);
20752
20790
  const st = e.isSymbolicLink() ? await fs45.stat(full).catch(() => null) : null;
20753
20791
  const isDir = st ? st.isDirectory() : e.isDirectory();
20754
- const isFile = st ? st.isFile() : e.isFile();
20755
- if (!isDir && !isFile)
20792
+ const isFile2 = st ? st.isFile() : e.isFile();
20793
+ if (!isDir && !isFile2)
20756
20794
  continue;
20757
20795
  const real = st ? await fs45.realpath(full).catch(() => full) : path53.join(realDir, e.name);
20758
20796
  if (isHiddenHostPath(real))
20759
20797
  continue;
20760
- const size = isFile && withSizes ? (st ?? await fs45.stat(full).catch(() => null))?.size : void 0;
20798
+ const size = isFile2 && withSizes ? (st ?? await fs45.stat(full).catch(() => null))?.size : void 0;
20761
20799
  list.push({ name: e.name, path: full, type: isDir ? "directory" : "file", ...size !== void 0 ? { size } : {} });
20762
20800
  }
20763
20801
  list.sort((a, b) => a.type === b.type ? a.name.localeCompare(b.name) : a.type === "directory" ? -1 : 1);
@@ -21927,7 +21965,7 @@ async function scanAgentsDir(dir, scope) {
21927
21965
  const yamlPath = path58.join(agentDir, "agent.yaml");
21928
21966
  try {
21929
21967
  const yamlStat = await fs49.stat(yamlPath);
21930
- const parsed = _yamlCache.get(yamlPath, yamlStat.mtimeMs) ?? _yamlCache.set(yamlPath, yamlStat.mtimeMs, parseAgentYaml(await fs49.readFile(yamlPath, "utf-8")));
21968
+ const parsed = _yamlCache2.get(yamlPath, yamlStat.mtimeMs) ?? _yamlCache2.set(yamlPath, yamlStat.mtimeMs, parseAgentYaml(await fs49.readFile(yamlPath, "utf-8")));
21931
21969
  const { name, description, model, priority, tools, skills, internal } = parsed;
21932
21970
  agents.push({
21933
21971
  id: entryName,
@@ -22343,7 +22381,7 @@ ${body.description ?? ""}
22343
22381
  });
22344
22382
  return app2;
22345
22383
  }
22346
- var _cachedTools, GLOBAL_AGENTS_DIR4, FALLBACK_SCAFFOLD_PROVIDER, _yamlCache;
22384
+ var _cachedTools, GLOBAL_AGENTS_DIR4, FALLBACK_SCAFFOLD_PROVIDER, _yamlCache2;
22347
22385
  var init_agent_configs = __esm({
22348
22386
  "../server/dist/routes/agent-configs.js"() {
22349
22387
  "use strict";
@@ -22361,7 +22399,7 @@ var init_agent_configs = __esm({
22361
22399
  _cachedTools = null;
22362
22400
  GLOBAL_AGENTS_DIR4 = path58.join(homedir20(), ".halo", "global", "agents");
22363
22401
  FALLBACK_SCAFFOLD_PROVIDER = "aws-bedrock-claude-invoke";
22364
- _yamlCache = createMtimeCache();
22402
+ _yamlCache2 = createMtimeCache();
22365
22403
  }
22366
22404
  });
22367
22405
 
@@ -26096,22 +26134,29 @@ function sendWsNotification(event, state, turnId, ctx) {
26096
26134
  // Streaming chunks ride the same frames as the whole-text events — the
26097
26135
  // admin appends chat:thinking / chat:stream by turnId either way. The whole
26098
26136
  // event that follows a streamed call is stamped `streamed` and dropped so
26099
- // the client doesn't render the text twice.
26137
+ // the client doesn't render the text twice. Root only: a sub-agent's
26138
+ // (taskId) text never renders in a chat view — the listener is the root
26139
+ // tree's and every view filters taskId rows out — so its deltas were pure
26140
+ // per-token store churn; its log is read from disk (Sessions tab).
26100
26141
  case "thinking_delta":
26101
- sendJson(ctx.ws, { type: "chat:thinking", text: event.text ?? "", agentName, taskId, turnId, sessionId });
26142
+ if (taskId)
26143
+ break;
26144
+ sendJson(ctx.ws, { type: "chat:thinking", text: event.text ?? "", agentName, turnId, sessionId });
26102
26145
  break;
26103
26146
  case "stream_delta":
26104
- sendJson(ctx.ws, { type: "chat:stream", text: event.text ?? "", agentName, taskId, turnId, sessionId });
26147
+ if (taskId)
26148
+ break;
26149
+ sendJson(ctx.ws, { type: "chat:stream", text: event.text ?? "", agentName, turnId, sessionId });
26105
26150
  break;
26106
26151
  case "thinking":
26107
- if (event.streamed)
26152
+ if (event.streamed || taskId)
26108
26153
  break;
26109
- sendJson(ctx.ws, { type: "chat:thinking", text: event.text ?? "", agentName, taskId, turnId, sessionId });
26154
+ sendJson(ctx.ws, { type: "chat:thinking", text: event.text ?? "", agentName, turnId, sessionId });
26110
26155
  break;
26111
26156
  case "stream":
26112
- if (event.streamed)
26157
+ if (event.streamed || taskId)
26113
26158
  break;
26114
- sendJson(ctx.ws, { type: "chat:stream", text: event.text ?? "", agentName, taskId, turnId, sessionId });
26159
+ sendJson(ctx.ws, { type: "chat:stream", text: event.text ?? "", agentName, turnId, sessionId });
26115
26160
  break;
26116
26161
  case "agent_start":
26117
26162
  sendJson(ctx.ws, { type: "agent:start", agentName, task: event.text, taskId, sessionId });
@@ -27339,7 +27384,7 @@ function buildCard(workspace, interfaceUrl, caps) {
27339
27384
  return {
27340
27385
  name: raw.name,
27341
27386
  description: raw.description,
27342
- version: typeof raw.version === "string" ? raw.version : "1.6.1",
27387
+ version: typeof raw.version === "string" ? raw.version : "1.6.2",
27343
27388
  supportedInterfaces: [{ url: interfaceUrl, protocolBinding: "JSONRPC", protocolVersion: A2A_VERSION }],
27344
27389
  capabilities: { streaming: caps.streaming, pushNotifications: true, extendedAgentCard: false },
27345
27390
  ...caps.tokenAuth === false ? {} : {
@@ -35405,7 +35450,7 @@ var init_dist2 = __esm({
35405
35450
  init_git_ssh();
35406
35451
  __dirname3 = path83.dirname(fileURLToPath3(import.meta.url));
35407
35452
  PORT = config.server.port;
35408
- HALO_VERSION = "1.6.1";
35453
+ HALO_VERSION = "1.6.2";
35409
35454
  PROJECT_ROOT = findProjectRoot();
35410
35455
  HALO_HOME4 = path83.join(homedir25(), ".halo");
35411
35456
  GIT_SHA = readGitSha();
@@ -36720,7 +36765,7 @@ import path85 from "node:path";
36720
36765
  import fs76 from "node:fs";
36721
36766
  import { homedir as homedir26 } from "node:os";
36722
36767
  import { parseArgs as parseArgs2 } from "node:util";
36723
- var VERSION = "1.6.1";
36768
+ var VERSION = "1.6.2";
36724
36769
  var HELP_TOP = `Usage: halo <command> [options]
36725
36770
 
36726
36771
  Commands:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@turmind/halo",
3
- "version": "1.6.1",
3
+ "version": "1.6.2",
4
4
  "description": "Halo — multi-agent collaborative workspace. CLI + TUI + HTTP/WS server in one package.",
5
5
  "type": "module",
6
6
  "license": "MIT",