kanbaii 0.3.3 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dashboard/404.html +1 -1
- package/dashboard/index.html +1 -1
- package/dashboard/index.txt +1 -1
- package/dist/server/mcp/kanbaii-mcp-server.js +496 -0
- package/package.json +4 -4
- /package/dashboard/_next/static/{Tp6HPn---FNpuYm3B24fA → PAWhPHPqRCFfVFpsqwO5u}/_buildManifest.js +0 -0
- /package/dashboard/_next/static/{Tp6HPn---FNpuYm3B24fA → PAWhPHPqRCFfVFpsqwO5u}/_ssgManifest.js +0 -0
package/dashboard/404.html
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="/_next/static/css/85ce8ef4f13f9778.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/webpack-5c1d03322d6ecf76.js"/><script src="/_next/static/chunks/fd9d1056-1f1f859026f5f0fa.js" async=""></script><script src="/_next/static/chunks/117-749dc8b5f56031ab.js" async=""></script><script src="/_next/static/chunks/main-app-2f313c3206a6e049.js" async=""></script><script src="/_next/static/chunks/184-15d72b1991c86ab9.js" async=""></script><script src="/_next/static/chunks/23-4a72ba4a90f008a6.js" async=""></script><script src="/_next/static/chunks/app/layout-5b89132efd82b0a2.js" async=""></script><meta name="robots" content="noindex"/><meta name="theme-color" content="#6366f1"/><title>KANBAII</title><meta name="description" content="Structure for your ideas. AI to move them forward."/><link rel="manifest" href="/manifest.json" crossorigin="use-credentials"/><link rel="icon" href="/favicon.svg" type="image/svg+xml"/><link rel="icon" href="/favicon-16x16.svg" sizes="16x16" type="image/svg+xml"/><script src="/_next/static/chunks/polyfills-42372ed130431b0a.js" noModule=""></script></head><body><script src="/_next/static/chunks/webpack-5c1d03322d6ecf76.js" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0]);self.__next_f.push([2,null])</script><script>self.__next_f.push([1,"1:HL[\"/_next/static/css/85ce8ef4f13f9778.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"2:I[2846,[],\"\"]\n4:I[4707,[],\"\"]\n5:I[6423,[],\"\"]\n6:I[792,[\"184\",\"static/chunks/184-15d72b1991c86ab9.js\",\"23\",\"static/chunks/23-4a72ba4a90f008a6.js\",\"185\",\"static/chunks/app/layout-5b89132efd82b0a2.js\"],\"AppShell\"]\nc:I[1060,[],\"\"]\n7:{\"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\"}\n8:{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"}\n9:{\"display\":\"inline-block\"}\na:{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0}\nd:[]\n"])</script><script>self.__next_f.push([1,"0:[\"$\",\"$L2\",null,{\"buildId\":\"
|
|
1
|
+
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="/_next/static/css/85ce8ef4f13f9778.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/webpack-5c1d03322d6ecf76.js"/><script src="/_next/static/chunks/fd9d1056-1f1f859026f5f0fa.js" async=""></script><script src="/_next/static/chunks/117-749dc8b5f56031ab.js" async=""></script><script src="/_next/static/chunks/main-app-2f313c3206a6e049.js" async=""></script><script src="/_next/static/chunks/184-15d72b1991c86ab9.js" async=""></script><script src="/_next/static/chunks/23-4a72ba4a90f008a6.js" async=""></script><script src="/_next/static/chunks/app/layout-5b89132efd82b0a2.js" async=""></script><meta name="robots" content="noindex"/><meta name="theme-color" content="#6366f1"/><title>KANBAII</title><meta name="description" content="Structure for your ideas. AI to move them forward."/><link rel="manifest" href="/manifest.json" crossorigin="use-credentials"/><link rel="icon" href="/favicon.svg" type="image/svg+xml"/><link rel="icon" href="/favicon-16x16.svg" sizes="16x16" type="image/svg+xml"/><script src="/_next/static/chunks/polyfills-42372ed130431b0a.js" noModule=""></script></head><body><script src="/_next/static/chunks/webpack-5c1d03322d6ecf76.js" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0]);self.__next_f.push([2,null])</script><script>self.__next_f.push([1,"1:HL[\"/_next/static/css/85ce8ef4f13f9778.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"2:I[2846,[],\"\"]\n4:I[4707,[],\"\"]\n5:I[6423,[],\"\"]\n6:I[792,[\"184\",\"static/chunks/184-15d72b1991c86ab9.js\",\"23\",\"static/chunks/23-4a72ba4a90f008a6.js\",\"185\",\"static/chunks/app/layout-5b89132efd82b0a2.js\"],\"AppShell\"]\nc:I[1060,[],\"\"]\n7:{\"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\"}\n8:{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"}\n9:{\"display\":\"inline-block\"}\na:{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0}\nd:[]\n"])</script><script>self.__next_f.push([1,"0:[\"$\",\"$L2\",null,{\"buildId\":\"PAWhPHPqRCFfVFpsqwO5u\",\"assetPrefix\":\"\",\"urlParts\":[\"\",\"_not-found\"],\"initialTree\":[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{}]}]},\"$undefined\",\"$undefined\",true],\"initialSeedData\":[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{},[[\"$L3\",[[\"$\",\"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.\"}]}]]}]}]],null],null],null]},[null,[\"$\",\"$L4\",null,{\"parallelRouterKey\":\"children\",\"segmentPath\":[\"children\",\"/_not-found\",\"children\"],\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L5\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"notFoundStyles\":\"$undefined\"}]],null]},[[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/85ce8ef4f13f9778.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"children\":[\"$\",\"body\",null,{\"children\":[\"$\",\"$L6\",null,{\"children\":[\"$\",\"$L4\",null,{\"parallelRouterKey\":\"children\",\"segmentPath\":[\"children\"],\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L5\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":\"$7\",\"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\":\"$8\",\"children\":\"404\"}],[\"$\",\"div\",null,{\"style\":\"$9\",\"children\":[\"$\",\"h2\",null,{\"style\":\"$a\",\"children\":\"This page could not be found.\"}]}]]}]}]],\"notFoundStyles\":[]}]}]}]}]],null],null],\"couldBeIntercepted\":false,\"initialHead\":[[\"$\",\"meta\",null,{\"name\":\"robots\",\"content\":\"noindex\"}],\"$Lb\"],\"globalErrorComponent\":\"$c\",\"missingSlots\":\"$Wd\"}]\n"])</script><script>self.__next_f.push([1,"b:[[\"$\",\"meta\",\"0\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}],[\"$\",\"meta\",\"1\",{\"name\":\"theme-color\",\"content\":\"#6366f1\"}],[\"$\",\"meta\",\"2\",{\"charSet\":\"utf-8\"}],[\"$\",\"title\",\"3\",{\"children\":\"KANBAII\"}],[\"$\",\"meta\",\"4\",{\"name\":\"description\",\"content\":\"Structure for your ideas. AI to move them forward.\"}],[\"$\",\"link\",\"5\",{\"rel\":\"manifest\",\"href\":\"/manifest.json\",\"crossOrigin\":\"use-credentials\"}],[\"$\",\"link\",\"6\",{\"rel\":\"icon\",\"href\":\"/favicon.svg\",\"type\":\"image/svg+xml\"}],[\"$\",\"link\",\"7\",{\"rel\":\"icon\",\"href\":\"/favicon-16x16.svg\",\"sizes\":\"16x16\",\"type\":\"image/svg+xml\"}]]\n3:null\n"])</script></body></html>
|
package/dashboard/index.html
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="/_next/static/css/85ce8ef4f13f9778.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/webpack-5c1d03322d6ecf76.js"/><script src="/_next/static/chunks/fd9d1056-1f1f859026f5f0fa.js" async=""></script><script src="/_next/static/chunks/117-749dc8b5f56031ab.js" async=""></script><script src="/_next/static/chunks/main-app-2f313c3206a6e049.js" async=""></script><script src="/_next/static/chunks/184-15d72b1991c86ab9.js" async=""></script><script src="/_next/static/chunks/759-3d8fc7952548ec08.js" async=""></script><script src="/_next/static/chunks/23-4a72ba4a90f008a6.js" async=""></script><script src="/_next/static/chunks/app/page-e96878de09e0c519.js" async=""></script><script src="/_next/static/chunks/app/layout-5b89132efd82b0a2.js" async=""></script><meta name="theme-color" content="#6366f1"/><title>KANBAII</title><meta name="description" content="Structure for your ideas. AI to move them forward."/><link rel="manifest" href="/manifest.json" crossorigin="use-credentials"/><link rel="icon" href="/favicon.svg" type="image/svg+xml"/><link rel="icon" href="/favicon-16x16.svg" sizes="16x16" type="image/svg+xml"/><script src="/_next/static/chunks/polyfills-42372ed130431b0a.js" noModule=""></script></head><body><script src="/_next/static/chunks/webpack-5c1d03322d6ecf76.js" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0]);self.__next_f.push([2,null])</script><script>self.__next_f.push([1,"1:HL[\"/_next/static/css/85ce8ef4f13f9778.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"2:I[2846,[],\"\"]\n4:I[9107,[],\"ClientPageRoot\"]\n5:I[2039,[\"184\",\"static/chunks/184-15d72b1991c86ab9.js\",\"759\",\"static/chunks/759-3d8fc7952548ec08.js\",\"23\",\"static/chunks/23-4a72ba4a90f008a6.js\",\"931\",\"static/chunks/app/page-e96878de09e0c519.js\"],\"default\",1]\n6:I[792,[\"184\",\"static/chunks/184-15d72b1991c86ab9.js\",\"23\",\"static/chunks/23-4a72ba4a90f008a6.js\",\"185\",\"static/chunks/app/layout-5b89132efd82b0a2.js\"],\"AppShell\"]\n7:I[4707,[],\"\"]\n8:I[6423,[],\"\"]\na:I[1060,[],\"\"]\nb:[]\n0:[\"$\",\"$L2\",null,{\"buildId\":\"
|
|
1
|
+
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="/_next/static/css/85ce8ef4f13f9778.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/webpack-5c1d03322d6ecf76.js"/><script src="/_next/static/chunks/fd9d1056-1f1f859026f5f0fa.js" async=""></script><script src="/_next/static/chunks/117-749dc8b5f56031ab.js" async=""></script><script src="/_next/static/chunks/main-app-2f313c3206a6e049.js" async=""></script><script src="/_next/static/chunks/184-15d72b1991c86ab9.js" async=""></script><script src="/_next/static/chunks/759-3d8fc7952548ec08.js" async=""></script><script src="/_next/static/chunks/23-4a72ba4a90f008a6.js" async=""></script><script src="/_next/static/chunks/app/page-e96878de09e0c519.js" async=""></script><script src="/_next/static/chunks/app/layout-5b89132efd82b0a2.js" async=""></script><meta name="theme-color" content="#6366f1"/><title>KANBAII</title><meta name="description" content="Structure for your ideas. AI to move them forward."/><link rel="manifest" href="/manifest.json" crossorigin="use-credentials"/><link rel="icon" href="/favicon.svg" type="image/svg+xml"/><link rel="icon" href="/favicon-16x16.svg" sizes="16x16" type="image/svg+xml"/><script src="/_next/static/chunks/polyfills-42372ed130431b0a.js" noModule=""></script></head><body><script src="/_next/static/chunks/webpack-5c1d03322d6ecf76.js" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0]);self.__next_f.push([2,null])</script><script>self.__next_f.push([1,"1:HL[\"/_next/static/css/85ce8ef4f13f9778.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"2:I[2846,[],\"\"]\n4:I[9107,[],\"ClientPageRoot\"]\n5:I[2039,[\"184\",\"static/chunks/184-15d72b1991c86ab9.js\",\"759\",\"static/chunks/759-3d8fc7952548ec08.js\",\"23\",\"static/chunks/23-4a72ba4a90f008a6.js\",\"931\",\"static/chunks/app/page-e96878de09e0c519.js\"],\"default\",1]\n6:I[792,[\"184\",\"static/chunks/184-15d72b1991c86ab9.js\",\"23\",\"static/chunks/23-4a72ba4a90f008a6.js\",\"185\",\"static/chunks/app/layout-5b89132efd82b0a2.js\"],\"AppShell\"]\n7:I[4707,[],\"\"]\n8:I[6423,[],\"\"]\na:I[1060,[],\"\"]\nb:[]\n0:[\"$\",\"$L2\",null,{\"buildId\":\"PAWhPHPqRCFfVFpsqwO5u\",\"assetPrefix\":\"\",\"urlParts\":[\"\",\"\"],\"initialTree\":[\"\",{\"children\":[\"__PAGE__\",{}]},\"$undefined\",\"$undefined\",true],\"initialSeedData\":[\"\",{\"children\":[\"__PAGE__\",{},[[\"$L3\",[\"$\",\"$L4\",null,{\"props\":{\"params\":{},\"searchParams\":{}},\"Component\":\"$5\"}],null],null],null]},[[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/85ce8ef4f13f9778.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"children\":[\"$\",\"body\",null,{\"children\":[\"$\",\"$L6\",null,{\"children\":[\"$\",\"$L7\",null,{\"parallelRouterKey\":\"children\",\"segmentPath\":[\"children\"],\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L8\",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\",\"pad"])</script><script>self.__next_f.push([1,"ding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":\"404\"}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],\"notFoundStyles\":[]}]}]}]}]],null],null],\"couldBeIntercepted\":false,\"initialHead\":[null,\"$L9\"],\"globalErrorComponent\":\"$a\",\"missingSlots\":\"$Wb\"}]\n"])</script><script>self.__next_f.push([1,"9:[[\"$\",\"meta\",\"0\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}],[\"$\",\"meta\",\"1\",{\"name\":\"theme-color\",\"content\":\"#6366f1\"}],[\"$\",\"meta\",\"2\",{\"charSet\":\"utf-8\"}],[\"$\",\"title\",\"3\",{\"children\":\"KANBAII\"}],[\"$\",\"meta\",\"4\",{\"name\":\"description\",\"content\":\"Structure for your ideas. AI to move them forward.\"}],[\"$\",\"link\",\"5\",{\"rel\":\"manifest\",\"href\":\"/manifest.json\",\"crossOrigin\":\"use-credentials\"}],[\"$\",\"link\",\"6\",{\"rel\":\"icon\",\"href\":\"/favicon.svg\",\"type\":\"image/svg+xml\"}],[\"$\",\"link\",\"7\",{\"rel\":\"icon\",\"href\":\"/favicon-16x16.svg\",\"sizes\":\"16x16\",\"type\":\"image/svg+xml\"}]]\n3:null\n"])</script></body></html>
|
package/dashboard/index.txt
CHANGED
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
4:I[792,["184","static/chunks/184-15d72b1991c86ab9.js","23","static/chunks/23-4a72ba4a90f008a6.js","185","static/chunks/app/layout-5b89132efd82b0a2.js"],"AppShell"]
|
|
4
4
|
5:I[4707,[],""]
|
|
5
5
|
6:I[6423,[],""]
|
|
6
|
-
0:["
|
|
6
|
+
0:["PAWhPHPqRCFfVFpsqwO5u",[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],["",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/85ce8ef4f13f9778.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"en","children":["$","body",null,{"children":["$","$L4",null,{"children":["$","$L5",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L6",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]}]}]],null],null],["$L7",null]]]]
|
|
7
7
|
7:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"name":"theme-color","content":"#6366f1"}],["$","meta","2",{"charSet":"utf-8"}],["$","title","3",{"children":"KANBAII"}],["$","meta","4",{"name":"description","content":"Structure for your ideas. AI to move them forward."}],["$","link","5",{"rel":"manifest","href":"/manifest.json","crossOrigin":"use-credentials"}],["$","link","6",{"rel":"icon","href":"/favicon.svg","type":"image/svg+xml"}],["$","link","7",{"rel":"icon","href":"/favicon-16x16.svg","sizes":"16x16","type":"image/svg+xml"}]]
|
|
8
8
|
1:null
|
|
@@ -0,0 +1,496 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* KANBAII MCP Server — Orchestration tools for Claude agents.
|
|
5
|
+
*
|
|
6
|
+
* This runs as a stdio MCP server that Claude CLI connects to.
|
|
7
|
+
* Tools available:
|
|
8
|
+
* - escalate_to_human : blocking poll for human response via dashboard
|
|
9
|
+
* - send_notification : fire-and-forget message to dashboard
|
|
10
|
+
* - list_tasks : GET /api/teams/tasks → tasks grouped by column
|
|
11
|
+
* - assign_task : POST /api/teams/assign → spin up a worker
|
|
12
|
+
* - check_workers : GET /api/teams/workers → worker pool status
|
|
13
|
+
* - wait_for_completion : poll workers until taskIds complete (or timeout)
|
|
14
|
+
* - send_message : POST /api/escalation/create (teams source, non-blocking)
|
|
15
|
+
*
|
|
16
|
+
* Supports both transports:
|
|
17
|
+
* - JSONL (newline-delimited JSON) — used by Claude CLI 2.x+
|
|
18
|
+
* - Content-Length (LSP-style) — used by older MCP clients
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
const http = require('http');
|
|
22
|
+
|
|
23
|
+
const KANBAII_PORT = process.env.KANBAII_PORT || '5555';
|
|
24
|
+
const KANBAII_HOST = process.env.KANBAII_HOST || 'localhost';
|
|
25
|
+
const POLL_INTERVAL = 3000;
|
|
26
|
+
|
|
27
|
+
// ─── HTTP helpers ───
|
|
28
|
+
|
|
29
|
+
function post(path, body) {
|
|
30
|
+
return new Promise((resolve, reject) => {
|
|
31
|
+
const data = JSON.stringify(body);
|
|
32
|
+
const req = http.request({
|
|
33
|
+
hostname: KANBAII_HOST, port: KANBAII_PORT, path, method: 'POST',
|
|
34
|
+
headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(data) },
|
|
35
|
+
}, (res) => {
|
|
36
|
+
let buf = '';
|
|
37
|
+
res.on('data', c => buf += c);
|
|
38
|
+
res.on('end', () => { try { resolve(JSON.parse(buf)); } catch { resolve({ ok: false }); } });
|
|
39
|
+
});
|
|
40
|
+
req.on('error', reject);
|
|
41
|
+
req.write(data);
|
|
42
|
+
req.end();
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function get(path) {
|
|
47
|
+
return new Promise((resolve, reject) => {
|
|
48
|
+
const req = http.request({
|
|
49
|
+
hostname: KANBAII_HOST, port: KANBAII_PORT, path, method: 'GET',
|
|
50
|
+
}, (res) => {
|
|
51
|
+
let buf = '';
|
|
52
|
+
res.on('data', c => buf += c);
|
|
53
|
+
res.on('end', () => { try { resolve(JSON.parse(buf)); } catch { resolve({ ok: false }); } });
|
|
54
|
+
});
|
|
55
|
+
req.on('error', reject);
|
|
56
|
+
req.end();
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// ─── MCP Protocol (stdio JSON-RPC, auto-detect JSONL vs Content-Length) ───
|
|
61
|
+
|
|
62
|
+
let buffer = '';
|
|
63
|
+
let useJsonl = null; // Auto-detect on first message
|
|
64
|
+
|
|
65
|
+
process.stdin.setEncoding('utf8');
|
|
66
|
+
process.stdin.on('data', (chunk) => {
|
|
67
|
+
buffer += chunk;
|
|
68
|
+
processBuffer();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
function processBuffer() {
|
|
72
|
+
// Auto-detect format on first meaningful data
|
|
73
|
+
if (useJsonl === null) {
|
|
74
|
+
const trimmed = buffer.trimStart();
|
|
75
|
+
if (trimmed.startsWith('{')) {
|
|
76
|
+
useJsonl = true;
|
|
77
|
+
} else if (trimmed.startsWith('Content-Length:')) {
|
|
78
|
+
useJsonl = false;
|
|
79
|
+
} else {
|
|
80
|
+
return; // Wait for more data
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (useJsonl) {
|
|
85
|
+
processJsonl();
|
|
86
|
+
} else {
|
|
87
|
+
processContentLength();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function processJsonl() {
|
|
92
|
+
const lines = buffer.split('\n');
|
|
93
|
+
buffer = lines.pop() || ''; // Keep incomplete line in buffer
|
|
94
|
+
for (const line of lines) {
|
|
95
|
+
const trimmed = line.trim();
|
|
96
|
+
if (!trimmed) continue;
|
|
97
|
+
try {
|
|
98
|
+
handleMessage(JSON.parse(trimmed));
|
|
99
|
+
} catch {}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function processContentLength() {
|
|
104
|
+
while (true) {
|
|
105
|
+
const headerEnd = buffer.indexOf('\r\n\r\n');
|
|
106
|
+
if (headerEnd === -1) return;
|
|
107
|
+
const header = buffer.substring(0, headerEnd);
|
|
108
|
+
const match = header.match(/Content-Length:\s*(\d+)/i);
|
|
109
|
+
if (!match) { buffer = buffer.substring(headerEnd + 4); continue; }
|
|
110
|
+
const contentLength = parseInt(match[1], 10);
|
|
111
|
+
const bodyStart = headerEnd + 4;
|
|
112
|
+
if (buffer.length < bodyStart + contentLength) return;
|
|
113
|
+
const body = buffer.substring(bodyStart, bodyStart + contentLength);
|
|
114
|
+
buffer = buffer.substring(bodyStart + contentLength);
|
|
115
|
+
try { handleMessage(JSON.parse(body)); } catch {}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function sendResponse(msg) {
|
|
120
|
+
const body = JSON.stringify(msg);
|
|
121
|
+
if (useJsonl) {
|
|
122
|
+
process.stdout.write(body + '\n');
|
|
123
|
+
} else {
|
|
124
|
+
process.stdout.write(`Content-Length: ${Buffer.byteLength(body)}\r\n\r\n${body}`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// ─── Tool Definitions ───
|
|
129
|
+
|
|
130
|
+
const TOOLS = [
|
|
131
|
+
{
|
|
132
|
+
name: 'escalate_to_human',
|
|
133
|
+
description: 'Escalate a question or decision to the human operator. Posts the question to the KANBAII dashboard and Telegram. If blocking=true (default), waits for the human response before returning. Use this whenever you need human input, approval, or a decision.',
|
|
134
|
+
inputSchema: {
|
|
135
|
+
type: 'object',
|
|
136
|
+
properties: {
|
|
137
|
+
question: { type: 'string', description: 'The question to present to the human' },
|
|
138
|
+
options: { type: 'array', items: { type: 'string' }, description: 'Optional response options' },
|
|
139
|
+
blocking: { type: 'boolean', description: 'If true (default), wait for response. If false, fire-and-forget.' },
|
|
140
|
+
timeout_seconds: { type: 'number', description: 'Timeout in seconds (default 1800 = 30 min)' },
|
|
141
|
+
},
|
|
142
|
+
required: ['question'],
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
name: 'send_notification',
|
|
147
|
+
description: 'Send a notification message to the KANBAII dashboard. Use for progress updates or important messages that do not require a response.',
|
|
148
|
+
inputSchema: {
|
|
149
|
+
type: 'object',
|
|
150
|
+
properties: {
|
|
151
|
+
message: { type: 'string', description: 'The message to display' },
|
|
152
|
+
type: { type: 'string', enum: ['info', 'warning', 'error', 'success'], description: 'Message type' },
|
|
153
|
+
},
|
|
154
|
+
required: ['message'],
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
name: 'list_tasks',
|
|
159
|
+
description: 'List all tasks in the Teams queue, grouped by column (Backlog, Todo, In Progress, Review, Done). Use this to understand what work is available or in progress before assigning tasks.',
|
|
160
|
+
inputSchema: {
|
|
161
|
+
type: 'object',
|
|
162
|
+
properties: {
|
|
163
|
+
projectSlug: { type: 'string', description: 'Optional project slug to filter tasks' },
|
|
164
|
+
workItemSlug: { type: 'string', description: 'Optional work item slug to filter tasks' },
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
name: 'assign_task',
|
|
170
|
+
description: 'Assign a task to an agent worker. Posts to the Teams engine to spin up a worker for the given task. Returns the workerId that can be tracked via check_workers or wait_for_completion.',
|
|
171
|
+
inputSchema: {
|
|
172
|
+
type: 'object',
|
|
173
|
+
properties: {
|
|
174
|
+
taskId: { type: 'string', description: 'The task ID to assign' },
|
|
175
|
+
agent: { type: 'string', description: 'Optional agent name to assign the task to' },
|
|
176
|
+
model: { type: 'string', description: 'Optional model override (e.g. claude-opus-4-5)' },
|
|
177
|
+
additionalContext: { type: 'string', description: 'Optional additional context or instructions for the worker' },
|
|
178
|
+
},
|
|
179
|
+
required: ['taskId'],
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
name: 'check_workers',
|
|
184
|
+
description: 'Check the current worker pool status. Returns all active, completed, and failed workers with their task assignments and output summaries.',
|
|
185
|
+
inputSchema: {
|
|
186
|
+
type: 'object',
|
|
187
|
+
properties: {},
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
name: 'wait_for_completion',
|
|
192
|
+
description: 'Poll the worker pool every 3 seconds until the specified taskIds appear in completedResults, or until timeout. If no taskIds are provided, waits for the next ANY new completion. Returns the completed worker results.',
|
|
193
|
+
inputSchema: {
|
|
194
|
+
type: 'object',
|
|
195
|
+
properties: {
|
|
196
|
+
taskIds: {
|
|
197
|
+
type: 'array',
|
|
198
|
+
items: { type: 'string' },
|
|
199
|
+
description: 'Task IDs to wait for. If omitted, waits for any new completion.',
|
|
200
|
+
},
|
|
201
|
+
timeout_seconds: {
|
|
202
|
+
type: 'number',
|
|
203
|
+
description: 'Max seconds to wait (default 900 = 15 min)',
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
name: 'send_message',
|
|
210
|
+
description: 'Send a simple message or status update to the KANBAII dashboard from a teams agent. Unlike escalate_to_human, this never blocks — it is purely informational.',
|
|
211
|
+
inputSchema: {
|
|
212
|
+
type: 'object',
|
|
213
|
+
properties: {
|
|
214
|
+
message: { type: 'string', description: 'The message to send to the dashboard' },
|
|
215
|
+
},
|
|
216
|
+
required: ['message'],
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
name: 'report_work_item',
|
|
221
|
+
description: 'Register a discovered work item (feature, bug, or refactor) in the KANBAII planner dashboard. The item appears on the discovery board for the user to see. Call this as soon as you identify a work item.',
|
|
222
|
+
inputSchema: {
|
|
223
|
+
type: 'object',
|
|
224
|
+
properties: {
|
|
225
|
+
id: { type: 'string', description: 'Unique ID for this item (e.g. disc-1, disc-2)' },
|
|
226
|
+
title: { type: 'string', description: 'Short descriptive title' },
|
|
227
|
+
category: { type: 'string', enum: ['feature', 'bug', 'refactor'], description: 'Type of work item' },
|
|
228
|
+
},
|
|
229
|
+
required: ['id', 'title', 'category'],
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
name: 'update_work_item',
|
|
234
|
+
description: 'Update a work item with plan and/or tasks. Use status "planning" when you start working on it, and "ready" when plan + tasks are complete. The user can then approve it from the dashboard.',
|
|
235
|
+
inputSchema: {
|
|
236
|
+
type: 'object',
|
|
237
|
+
properties: {
|
|
238
|
+
id: { type: 'string', description: 'The item ID (e.g. disc-1) from report_work_item' },
|
|
239
|
+
status: { type: 'string', enum: ['planning', 'ready'], description: '"planning" = working on it, "ready" = plan + tasks complete' },
|
|
240
|
+
plan: { type: 'string', description: 'Markdown plan content (Objective, Approach, Key Decisions)' },
|
|
241
|
+
tasks: {
|
|
242
|
+
type: 'array',
|
|
243
|
+
description: 'Array of tasks (required when status is "ready")',
|
|
244
|
+
items: {
|
|
245
|
+
type: 'object',
|
|
246
|
+
properties: {
|
|
247
|
+
title: { type: 'string' },
|
|
248
|
+
description: { type: 'string' },
|
|
249
|
+
model: { type: 'string', description: 'Claude model: sonnet, opus, or haiku' },
|
|
250
|
+
priority: { type: 'string', enum: ['low', 'medium', 'high', 'urgent'] },
|
|
251
|
+
tags: { type: 'array', items: { type: 'string' } },
|
|
252
|
+
},
|
|
253
|
+
required: ['title', 'description'],
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
required: ['id', 'status'],
|
|
258
|
+
},
|
|
259
|
+
},
|
|
260
|
+
];
|
|
261
|
+
|
|
262
|
+
// ─── Message Handler ───
|
|
263
|
+
|
|
264
|
+
async function handleMessage(msg) {
|
|
265
|
+
if (msg.method === 'initialize') {
|
|
266
|
+
// Mirror the protocol version the client sends
|
|
267
|
+
const clientVersion = msg.params?.protocolVersion || '2024-11-05';
|
|
268
|
+
sendResponse({
|
|
269
|
+
jsonrpc: '2.0', id: msg.id,
|
|
270
|
+
result: {
|
|
271
|
+
protocolVersion: clientVersion,
|
|
272
|
+
serverInfo: { name: 'kanbaii', version: '1.0.0' },
|
|
273
|
+
capabilities: { tools: { listChanged: false } },
|
|
274
|
+
},
|
|
275
|
+
});
|
|
276
|
+
} else if (msg.method === 'notifications/initialized') {
|
|
277
|
+
// No response needed
|
|
278
|
+
} else if (msg.method === 'tools/list') {
|
|
279
|
+
sendResponse({
|
|
280
|
+
jsonrpc: '2.0', id: msg.id,
|
|
281
|
+
result: { tools: TOOLS },
|
|
282
|
+
});
|
|
283
|
+
} else if (msg.method === 'tools/call') {
|
|
284
|
+
const { name, arguments: args } = msg.params;
|
|
285
|
+
try {
|
|
286
|
+
const result = await dispatchTool(name, args || {});
|
|
287
|
+
sendResponse({
|
|
288
|
+
jsonrpc: '2.0', id: msg.id,
|
|
289
|
+
result: { content: [{ type: 'text', text: typeof result === 'string' ? result : JSON.stringify(result, null, 2) }] },
|
|
290
|
+
});
|
|
291
|
+
} catch (e) {
|
|
292
|
+
sendResponse({
|
|
293
|
+
jsonrpc: '2.0', id: msg.id,
|
|
294
|
+
result: { content: [{ type: 'text', text: `Error: ${e.message}` }], isError: true },
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
} else if (msg.id) {
|
|
298
|
+
sendResponse({ jsonrpc: '2.0', id: msg.id, error: { code: -32601, message: `Unknown method: ${msg.method}` } });
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// ─── Tool Dispatcher ───
|
|
303
|
+
|
|
304
|
+
async function dispatchTool(name, args) {
|
|
305
|
+
switch (name) {
|
|
306
|
+
case 'escalate_to_human': return handleEscalation(args);
|
|
307
|
+
case 'send_notification': return handleSendNotification(args);
|
|
308
|
+
case 'list_tasks': return handleListTasks(args);
|
|
309
|
+
case 'assign_task': return handleAssignTask(args);
|
|
310
|
+
case 'check_workers': return handleCheckWorkers();
|
|
311
|
+
case 'wait_for_completion': return handleWaitForCompletion(args);
|
|
312
|
+
case 'send_message': return handleSendMessage(args);
|
|
313
|
+
case 'report_work_item': return handleReportWorkItem(args);
|
|
314
|
+
case 'update_work_item': return handleUpdateWorkItem(args);
|
|
315
|
+
default:
|
|
316
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// ─── Tool Implementations ───
|
|
321
|
+
|
|
322
|
+
async function handleEscalation(args) {
|
|
323
|
+
const { question, options, blocking, timeout_seconds } = args;
|
|
324
|
+
const isBlocking = blocking !== false;
|
|
325
|
+
|
|
326
|
+
const createRes = await post('/api/escalation/create', {
|
|
327
|
+
source: 'ralph', taskId: '', taskTitle: '',
|
|
328
|
+
question, options: options || [], timeoutSeconds: timeout_seconds || 1800,
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
if (!createRes.ok) throw new Error('Failed to create escalation');
|
|
332
|
+
|
|
333
|
+
const escalationId = createRes.data.escalationId;
|
|
334
|
+
|
|
335
|
+
if (!isBlocking) {
|
|
336
|
+
return { escalationId, status: 'sent', message: 'Escalation sent (non-blocking)' };
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Poll for response
|
|
340
|
+
const deadline = Date.now() + (timeout_seconds || 1800) * 1000;
|
|
341
|
+
|
|
342
|
+
while (Date.now() < deadline) {
|
|
343
|
+
await sleep(POLL_INTERVAL);
|
|
344
|
+
|
|
345
|
+
const status = await get('/api/escalation/status');
|
|
346
|
+
if (status.ok && status.data?.responded && status.data.escalation?.response) {
|
|
347
|
+
const response = status.data.escalation.response;
|
|
348
|
+
await post('/api/escalation/clear', {});
|
|
349
|
+
return { escalationId, status: 'responded', response, question };
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
if (status.ok && status.data?.escalation?.status === 'timed_out') {
|
|
353
|
+
return { escalationId, status: 'timed_out', message: 'No response received', question };
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
return { escalationId, status: 'timed_out', message: 'Timeout', question };
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
async function handleSendNotification(args) {
|
|
361
|
+
await post('/api/escalation/create', {
|
|
362
|
+
source: 'ralph', question: args.message, options: [],
|
|
363
|
+
taskId: '', taskTitle: 'Notification', timeoutSeconds: 5,
|
|
364
|
+
});
|
|
365
|
+
return 'Notification sent';
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
async function handleListTasks(args) {
|
|
369
|
+
let path = '/api/teams/tasks';
|
|
370
|
+
const params = [];
|
|
371
|
+
if (args.projectSlug) params.push(`projectSlug=${encodeURIComponent(args.projectSlug)}`);
|
|
372
|
+
if (args.workItemSlug) params.push(`workItemSlug=${encodeURIComponent(args.workItemSlug)}`);
|
|
373
|
+
if (params.length) path += '?' + params.join('&');
|
|
374
|
+
|
|
375
|
+
const res = await get(path);
|
|
376
|
+
if (!res.ok) throw new Error('Failed to fetch tasks');
|
|
377
|
+
return res.data || res;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
async function handleAssignTask(args) {
|
|
381
|
+
const { taskId, agent, model, additionalContext } = args;
|
|
382
|
+
|
|
383
|
+
const body = { taskId };
|
|
384
|
+
if (agent !== undefined) body.agent = agent;
|
|
385
|
+
if (model !== undefined) body.model = model;
|
|
386
|
+
if (additionalContext !== undefined) body.additionalContext = additionalContext;
|
|
387
|
+
|
|
388
|
+
const res = await post('/api/teams/assign', body);
|
|
389
|
+
if (!res.ok) throw new Error(res.error || 'Failed to assign task');
|
|
390
|
+
return res.data || res;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
async function handleCheckWorkers() {
|
|
394
|
+
const res = await get('/api/teams/workers');
|
|
395
|
+
if (!res.ok) throw new Error('Failed to fetch workers');
|
|
396
|
+
return res.data || res;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
async function handleWaitForCompletion(args) {
|
|
400
|
+
const { taskIds, timeout_seconds } = args;
|
|
401
|
+
const timeoutMs = (timeout_seconds || 900) * 1000;
|
|
402
|
+
const deadline = Date.now() + timeoutMs;
|
|
403
|
+
const targetIds = taskIds && taskIds.length > 0 ? new Set(taskIds) : null;
|
|
404
|
+
|
|
405
|
+
// Snapshot initial completed count for "any new completion" mode
|
|
406
|
+
let initialCompletedCount = null;
|
|
407
|
+
if (!targetIds) {
|
|
408
|
+
try {
|
|
409
|
+
const snapshot = await get('/api/teams/workers');
|
|
410
|
+
if (snapshot.ok) {
|
|
411
|
+
const data = snapshot.data || snapshot;
|
|
412
|
+
const completed = data.completedResults || data.completed || [];
|
|
413
|
+
initialCompletedCount = completed.length;
|
|
414
|
+
}
|
|
415
|
+
} catch {
|
|
416
|
+
initialCompletedCount = 0;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
while (Date.now() < deadline) {
|
|
421
|
+
await sleep(POLL_INTERVAL);
|
|
422
|
+
|
|
423
|
+
const res = await get('/api/teams/workers');
|
|
424
|
+
if (!res.ok) continue;
|
|
425
|
+
|
|
426
|
+
const data = res.data || res;
|
|
427
|
+
const completed = data.completedResults || data.completed || [];
|
|
428
|
+
|
|
429
|
+
if (targetIds) {
|
|
430
|
+
// Wait for all specified taskIds to appear in completedResults
|
|
431
|
+
const completedIds = new Set(completed.map(r => r.taskId || r.id).filter(Boolean));
|
|
432
|
+
const allDone = [...targetIds].every(id => completedIds.has(id));
|
|
433
|
+
if (allDone) {
|
|
434
|
+
const matching = completed.filter(r => targetIds.has(r.taskId || r.id));
|
|
435
|
+
return { status: 'completed', results: matching, allWorkers: data };
|
|
436
|
+
}
|
|
437
|
+
} else {
|
|
438
|
+
// Wait for any new completion
|
|
439
|
+
if (completed.length > initialCompletedCount) {
|
|
440
|
+
const newResults = completed.slice(initialCompletedCount);
|
|
441
|
+
return { status: 'completed', results: newResults, allWorkers: data };
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// Timeout — return current state
|
|
447
|
+
const finalRes = await get('/api/teams/workers');
|
|
448
|
+
const finalData = finalRes.ok ? (finalRes.data || finalRes) : {};
|
|
449
|
+
return {
|
|
450
|
+
status: 'timed_out',
|
|
451
|
+
message: `No completion after ${timeout_seconds || 900}s`,
|
|
452
|
+
allWorkers: finalData,
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
async function handleSendMessage(args) {
|
|
457
|
+
await post('/api/escalation/create', {
|
|
458
|
+
source: 'teams', question: args.message, options: [],
|
|
459
|
+
taskId: '', taskTitle: 'Message', timeoutSeconds: 5,
|
|
460
|
+
});
|
|
461
|
+
return 'Message sent';
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
async function handleReportWorkItem(args) {
|
|
465
|
+
const { id, title, category } = args;
|
|
466
|
+
if (!id || !title) throw new Error('id and title are required');
|
|
467
|
+
const res = await post('/api/planner/report-item', { id, title, category: category || 'feature' });
|
|
468
|
+
if (!res.ok) throw new Error(res.error || 'Failed to report item');
|
|
469
|
+
return res.data || { message: `Item "${title}" registered on the planner dashboard.` };
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
async function handleUpdateWorkItem(args) {
|
|
473
|
+
const { id, status, plan, tasks } = args;
|
|
474
|
+
if (!id || !status) throw new Error('id and status are required');
|
|
475
|
+
const body = { id, status };
|
|
476
|
+
if (plan) body.plan = plan;
|
|
477
|
+
if (tasks) body.tasks = tasks.map(t => ({
|
|
478
|
+
title: t.title,
|
|
479
|
+
description: t.description || '',
|
|
480
|
+
model: t.model || 'sonnet',
|
|
481
|
+
priority: t.priority || 'medium',
|
|
482
|
+
tags: t.tags || [],
|
|
483
|
+
}));
|
|
484
|
+
const res = await post('/api/planner/update-item', body);
|
|
485
|
+
if (!res.ok) throw new Error(res.error || 'Failed to update item');
|
|
486
|
+
return res.data || { message: `Item updated to "${status}".` };
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// ─── Utilities ───
|
|
490
|
+
|
|
491
|
+
function sleep(ms) {
|
|
492
|
+
return new Promise(r => setTimeout(r, ms));
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
// Keep process alive
|
|
496
|
+
process.stdin.resume();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kanbaii",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"description": "The organization layer that Claude Code doesn't have. Plan visually, track progress, let AI execute.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"kanban",
|
|
@@ -52,10 +52,10 @@
|
|
|
52
52
|
"dev:server": "tsx watch src/server/index.ts",
|
|
53
53
|
"dev:frontend": "cd frontend && npm run dev",
|
|
54
54
|
"dev": "concurrently \"npm run dev:server\" \"npm run dev:frontend\"",
|
|
55
|
-
"build:server": "tsc -p tsconfig.server.json",
|
|
56
|
-
"build:cli": "tsc -p tsconfig.cli.json",
|
|
55
|
+
"build:server": "tsc -p tsconfig.server.json && node -e \"const fs=require('fs'),p=require('path');const s='src/server/mcp',d='dist/server/mcp';fs.mkdirSync(d,{recursive:true});fs.readdirSync(s).filter(f=>f.endsWith('.js')).forEach(f=>fs.copyFileSync(p.join(s,f),p.join(d,f)));\"",
|
|
56
|
+
"build:cli": "tsc -p tsconfig.cli.json && node -e \"const fs=require('fs'),p=require('path');const s='src/server/mcp',d='dist/server/mcp';fs.mkdirSync(d,{recursive:true});fs.readdirSync(s).filter(f=>f.endsWith('.js')).forEach(f=>fs.copyFileSync(p.join(s,f),p.join(d,f)));\"",
|
|
57
57
|
"build:frontend": "cd frontend && npm ci && npm run build && node -e \"const fs=require('fs');fs.rmSync('../dashboard',{recursive:true,force:true});fs.cpSync('out','../dashboard',{recursive:true});\"",
|
|
58
|
-
"build": "
|
|
58
|
+
"build": "npm run build:cli && npm run build:frontend",
|
|
59
59
|
"postbuild": "node -e \"require('fs').chmodSync('dist/cli/index.js', '755')\"",
|
|
60
60
|
"prepublishOnly": "echo 'Build handled by CI'",
|
|
61
61
|
"start": "node dist/server/index.js",
|
/package/dashboard/_next/static/{Tp6HPn---FNpuYm3B24fA → PAWhPHPqRCFfVFpsqwO5u}/_buildManifest.js
RENAMED
|
File without changes
|
/package/dashboard/_next/static/{Tp6HPn---FNpuYm3B24fA → PAWhPHPqRCFfVFpsqwO5u}/_ssgManifest.js
RENAMED
|
File without changes
|