aiexecode 1.0.74 → 1.0.76
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.
Potentially problematic release.
This version of aiexecode might be problematic. Click here for more details.
- package/package.json +1 -1
- package/payload_viewer/out/404/index.html +1 -1
- package/payload_viewer/out/404.html +1 -1
- package/payload_viewer/out/index.html +1 -1
- package/payload_viewer/out/index.txt +1 -1
- package/prompts/orchestrator.txt +34 -0
- package/src/frontend/components/ConversationItem.js +9 -3
- package/src/frontend/utils/GridRenderer.js +140 -0
- package/src/frontend/utils/InlineFormatter.js +156 -0
- package/src/frontend/utils/markdownParser.js +330 -184
- package/src/system/ai_request.js +14 -1
- /package/payload_viewer/out/_next/static/{S5OZ2xYxrJopcK8El7EbO → Wnr9eYJaRUoC5a3SUgrBr}/_buildManifest.js +0 -0
- /package/payload_viewer/out/_next/static/{S5OZ2xYxrJopcK8El7EbO → Wnr9eYJaRUoC5a3SUgrBr}/_clientMiddlewareManifest.json +0 -0
- /package/payload_viewer/out/_next/static/{S5OZ2xYxrJopcK8El7EbO → Wnr9eYJaRUoC5a3SUgrBr}/_ssgManifest.js +0 -0
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><!--
|
|
1
|
+
<!DOCTYPE html><!--Wnr9eYJaRUoC5a3SUgrBr--><html lang="ko" class="dark h-full"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="/_next/static/chunks/ecd2072ebf41611f.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/e411019f55d87c42.js"/><script src="/_next/static/chunks/103c802c8f4a5ea1.js" async=""></script><script src="/_next/static/chunks/305b077a9873cf54.js" async=""></script><script src="/_next/static/chunks/turbopack-0ac29803ce3c3c7a.js" async=""></script><script src="/_next/static/chunks/060f9a97930f3d04.js" async=""></script><script src="/_next/static/chunks/cdd12d5c1a5a6064.js" async=""></script><meta name="robots" content="noindex"/><meta name="next-size-adjust" content=""/><title>404: This page could not be found.</title><title>Payload Log Viewer</title><meta name="description" content="AI Agent 로그 파일 뷰어 및 편집기"/><link rel="icon" href="/favicon.ico?favicon.0b3bf435.ico" sizes="256x256" type="image/x-icon"/><script src="/_next/static/chunks/a6dad97d9634a72d.js" noModule=""></script></head><body class="geist_a71539c9-module__T19VSG__variable geist_mono_8d43a2aa-module__8Li5zG__variable antialiased h-screen overflow-hidden"><div hidden=""><!--$--><!--/$--></div><div style="font-family:system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div><style>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)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding:0 23px 0 0;font-size:24px;font-weight:500;vertical-align:top;line-height:49px">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:49px;margin:0">This page could not be found.</h2></div></div></div><!--$--><!--/$--><div data-rht-toaster="" style="position:fixed;z-index:9999;top:16px;left:16px;right:16px;bottom:16px;pointer-events:none"></div><script src="/_next/static/chunks/e411019f55d87c42.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[39756,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"default\"]\n3:I[37457,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"default\"]\n4:I[5766,[\"/_next/static/chunks/cdd12d5c1a5a6064.js\"],\"Toaster\"]\n5:I[97367,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"OutletBoundary\"]\n7:I[11533,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"AsyncMetadataOutlet\"]\n9:I[97367,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"ViewportBoundary\"]\nb:I[97367,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"MetadataBoundary\"]\nc:\"$Sreact.suspense\"\ne:I[68027,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"default\"]\n:HL[\"/_next/static/chunks/ecd2072ebf41611f.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"b\":\"Wnr9eYJaRUoC5a3SUgrBr\",\"p\":\"\",\"c\":[\"\",\"_not-found\",\"\"],\"i\":false,\"f\":[[[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{}]}]},\"$undefined\",\"$undefined\",true],[\"\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/ecd2072ebf41611f.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/cdd12d5c1a5a6064.js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"ko\",\"className\":\"dark h-full\",\"children\":[\"$\",\"body\",null,{\"className\":\"geist_a71539c9-module__T19VSG__variable geist_mono_8d43a2aa-module__8Li5zG__variable antialiased h-screen overflow-hidden\",\"children\":[[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",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\"}],[\"$\",\"$L4\",null,{\"position\":\"bottom-right\",\"toastOptions\":{\"duration\":4000,\"style\":{\"background\":\"hsl(var(--background))\",\"color\":\"hsl(var(--foreground))\",\"border\":\"1px solid hsl(var(--border))\"}}}]]}]}]]}],{\"children\":[\"/_not-found\",[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[\"__PAGE__\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":\"$0:f:0:1:1:props:children:1:props:children:props:children:0:props:notFound:0:1:props:style\",\"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\":\"$0:f:0:1:1:props:children:1:props:children:props:children:0:props:notFound:0:1:props:children:props:children:1:props:style\",\"children\":404}],[\"$\",\"div\",null,{\"style\":\"$0:f:0:1:1:props:children:1:props:children:props:children:0:props:notFound:0:1:props:children:props:children:2:props:style\",\"children\":[\"$\",\"h2\",null,{\"style\":\"$0:f:0:1:1:props:children:1:props:children:props:children:0:props:notFound:0:1:props:children:props:children:2:props:children:props:style\",\"children\":\"This page could not be found.\"}]}]]}]}]],null,[\"$\",\"$L5\",null,{\"children\":[\"$L6\",[\"$\",\"$L7\",null,{\"promise\":\"$@8\"}]]}]]}],{},null,false]},null,false]},null,false],[\"$\",\"$1\",\"h\",{\"children\":[[\"$\",\"meta\",null,{\"name\":\"robots\",\"content\":\"noindex\"}],[[\"$\",\"$L9\",null,{\"children\":\"$La\"}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]],[\"$\",\"$Lb\",null,{\"children\":[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$c\",null,{\"fallback\":null,\"children\":\"$Ld\"}]}]}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$e\",\"$undefined\"],\"s\":false,\"S\":true}\n"])</script><script>self.__next_f.push([1,"a:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\n6:null\n"])</script><script>self.__next_f.push([1,"f:I[27201,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"IconMark\"]\n8:{\"metadata\":[[\"$\",\"title\",\"0\",{\"children\":\"Payload Log Viewer\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"AI Agent 로그 파일 뷰어 및 편집기\"}],[\"$\",\"link\",\"2\",{\"rel\":\"icon\",\"href\":\"/favicon.ico?favicon.0b3bf435.ico\",\"sizes\":\"256x256\",\"type\":\"image/x-icon\"}],[\"$\",\"$Lf\",\"3\",{}]],\"error\":null,\"digest\":\"$undefined\"}\n"])</script><script>self.__next_f.push([1,"d:\"$8:metadata\"\n"])</script></body></html>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><!--
|
|
1
|
+
<!DOCTYPE html><!--Wnr9eYJaRUoC5a3SUgrBr--><html lang="ko" class="dark h-full"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="/_next/static/chunks/ecd2072ebf41611f.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/e411019f55d87c42.js"/><script src="/_next/static/chunks/103c802c8f4a5ea1.js" async=""></script><script src="/_next/static/chunks/305b077a9873cf54.js" async=""></script><script src="/_next/static/chunks/turbopack-0ac29803ce3c3c7a.js" async=""></script><script src="/_next/static/chunks/060f9a97930f3d04.js" async=""></script><script src="/_next/static/chunks/cdd12d5c1a5a6064.js" async=""></script><meta name="robots" content="noindex"/><meta name="next-size-adjust" content=""/><title>404: This page could not be found.</title><title>Payload Log Viewer</title><meta name="description" content="AI Agent 로그 파일 뷰어 및 편집기"/><link rel="icon" href="/favicon.ico?favicon.0b3bf435.ico" sizes="256x256" type="image/x-icon"/><script src="/_next/static/chunks/a6dad97d9634a72d.js" noModule=""></script></head><body class="geist_a71539c9-module__T19VSG__variable geist_mono_8d43a2aa-module__8Li5zG__variable antialiased h-screen overflow-hidden"><div hidden=""><!--$--><!--/$--></div><div style="font-family:system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div><style>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)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding:0 23px 0 0;font-size:24px;font-weight:500;vertical-align:top;line-height:49px">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:49px;margin:0">This page could not be found.</h2></div></div></div><!--$--><!--/$--><div data-rht-toaster="" style="position:fixed;z-index:9999;top:16px;left:16px;right:16px;bottom:16px;pointer-events:none"></div><script src="/_next/static/chunks/e411019f55d87c42.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[39756,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"default\"]\n3:I[37457,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"default\"]\n4:I[5766,[\"/_next/static/chunks/cdd12d5c1a5a6064.js\"],\"Toaster\"]\n5:I[97367,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"OutletBoundary\"]\n7:I[11533,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"AsyncMetadataOutlet\"]\n9:I[97367,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"ViewportBoundary\"]\nb:I[97367,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"MetadataBoundary\"]\nc:\"$Sreact.suspense\"\ne:I[68027,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"default\"]\n:HL[\"/_next/static/chunks/ecd2072ebf41611f.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"b\":\"Wnr9eYJaRUoC5a3SUgrBr\",\"p\":\"\",\"c\":[\"\",\"_not-found\",\"\"],\"i\":false,\"f\":[[[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{}]}]},\"$undefined\",\"$undefined\",true],[\"\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/ecd2072ebf41611f.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/cdd12d5c1a5a6064.js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"ko\",\"className\":\"dark h-full\",\"children\":[\"$\",\"body\",null,{\"className\":\"geist_a71539c9-module__T19VSG__variable geist_mono_8d43a2aa-module__8Li5zG__variable antialiased h-screen overflow-hidden\",\"children\":[[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",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\"}],[\"$\",\"$L4\",null,{\"position\":\"bottom-right\",\"toastOptions\":{\"duration\":4000,\"style\":{\"background\":\"hsl(var(--background))\",\"color\":\"hsl(var(--foreground))\",\"border\":\"1px solid hsl(var(--border))\"}}}]]}]}]]}],{\"children\":[\"/_not-found\",[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[\"__PAGE__\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":\"$0:f:0:1:1:props:children:1:props:children:props:children:0:props:notFound:0:1:props:style\",\"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\":\"$0:f:0:1:1:props:children:1:props:children:props:children:0:props:notFound:0:1:props:children:props:children:1:props:style\",\"children\":404}],[\"$\",\"div\",null,{\"style\":\"$0:f:0:1:1:props:children:1:props:children:props:children:0:props:notFound:0:1:props:children:props:children:2:props:style\",\"children\":[\"$\",\"h2\",null,{\"style\":\"$0:f:0:1:1:props:children:1:props:children:props:children:0:props:notFound:0:1:props:children:props:children:2:props:children:props:style\",\"children\":\"This page could not be found.\"}]}]]}]}]],null,[\"$\",\"$L5\",null,{\"children\":[\"$L6\",[\"$\",\"$L7\",null,{\"promise\":\"$@8\"}]]}]]}],{},null,false]},null,false]},null,false],[\"$\",\"$1\",\"h\",{\"children\":[[\"$\",\"meta\",null,{\"name\":\"robots\",\"content\":\"noindex\"}],[[\"$\",\"$L9\",null,{\"children\":\"$La\"}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]],[\"$\",\"$Lb\",null,{\"children\":[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$c\",null,{\"fallback\":null,\"children\":\"$Ld\"}]}]}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$e\",\"$undefined\"],\"s\":false,\"S\":true}\n"])</script><script>self.__next_f.push([1,"a:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\n6:null\n"])</script><script>self.__next_f.push([1,"f:I[27201,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"IconMark\"]\n8:{\"metadata\":[[\"$\",\"title\",\"0\",{\"children\":\"Payload Log Viewer\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"AI Agent 로그 파일 뷰어 및 편집기\"}],[\"$\",\"link\",\"2\",{\"rel\":\"icon\",\"href\":\"/favicon.ico?favicon.0b3bf435.ico\",\"sizes\":\"256x256\",\"type\":\"image/x-icon\"}],[\"$\",\"$Lf\",\"3\",{}]],\"error\":null,\"digest\":\"$undefined\"}\n"])</script><script>self.__next_f.push([1,"d:\"$8:metadata\"\n"])</script></body></html>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><!--S5OZ2xYxrJopcK8El7EbO--><html lang="ko" class="dark h-full"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" href="/_next/static/media/797e433ab948586e-s.p.dbea232f.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="preload" href="/_next/static/media/caa3a2e1cccd8315-s.p.853070df.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="stylesheet" href="/_next/static/chunks/ecd2072ebf41611f.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/e411019f55d87c42.js"/><script src="/_next/static/chunks/103c802c8f4a5ea1.js" async=""></script><script src="/_next/static/chunks/305b077a9873cf54.js" async=""></script><script src="/_next/static/chunks/turbopack-0ac29803ce3c3c7a.js" async=""></script><script src="/_next/static/chunks/060f9a97930f3d04.js" async=""></script><script src="/_next/static/chunks/cdd12d5c1a5a6064.js" async=""></script><script src="/_next/static/chunks/f1ac9047ac4a3fde.js" async=""></script><script src="/_next/static/chunks/37d0cd2587a38f79.js" async=""></script><meta name="next-size-adjust" content=""/><title>Payload Log Viewer</title><meta name="description" content="AI Agent 로그 파일 뷰어 및 편집기"/><link rel="icon" href="/favicon.ico?favicon.0b3bf435.ico" sizes="256x256" type="image/x-icon"/><script src="/_next/static/chunks/a6dad97d9634a72d.js" noModule=""></script></head><body class="geist_a71539c9-module__T19VSG__variable geist_mono_8d43a2aa-module__8Li5zG__variable antialiased h-screen overflow-hidden"><div hidden=""><!--$--><!--/$--></div><div class="h-screen bg-background flex"><div class="flex-shrink-0 w-80 border-r border-border bg-background flex flex-col"><div class="flex-shrink-0 border-b border-border p-4"><h2 class="text-lg font-semibold flex items-center gap-2"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-file-text h-5 w-5" aria-hidden="true"><path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"></path><path d="M14 2v4a2 2 0 0 0 2 2h4"></path><path d="M10 9H8"></path><path d="M16 13H8"></path><path d="M16 17H8"></path></svg>로그 파일</h2><p class="text-sm text-muted-foreground">로딩 중...</p></div><div class="flex-1 min-h-0"><div dir="ltr" class="relative overflow-hidden h-full" style="position:relative;--radix-scroll-area-corner-width:0px;--radix-scroll-area-corner-height:0px"><style>[data-radix-scroll-area-viewport]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}[data-radix-scroll-area-viewport]::-webkit-scrollbar{display:none}</style><div data-radix-scroll-area-viewport="" class="h-full w-full rounded-[inherit]" style="overflow-x:hidden;overflow-y:hidden"><div style="min-width:100%;display:table"><div class="p-4 text-center text-muted-foreground"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-refresh-cw h-6 w-6 animate-spin mx-auto mb-2" aria-hidden="true"><path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"></path><path d="M21 3v5h-5"></path><path d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16"></path><path d="M8 16H3v5"></path></svg>로딩 중...</div></div></div></div></div></div><div class="flex-1 min-w-0"><div class="rounded-lg border bg-card text-card-foreground shadow-sm h-full"><div class="p-6 pt-0 flex items-center justify-center h-full"><div class="text-center text-muted-foreground"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-square-pen h-12 w-12 mx-auto mb-4 opacity-50" aria-hidden="true"><path d="M12 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path><path d="M18.375 2.625a1 1 0 0 1 3 3l-9.013 9.014a2 2 0 0 1-.853.505l-2.873.84a.5.5 0 0 1-.62-.62l.84-2.873a2 2 0 0 1 .506-.852z"></path></svg><p class="text-lg">REQ 파일을 선택하세요</p><p class="text-sm">요청 파일을 선택하면 내용을 편집하고 재실행할 수 있습니다</p></div></div></div></div></div><!--$--><!--/$--><div data-rht-toaster="" style="position:fixed;z-index:9999;top:16px;left:16px;right:16px;bottom:16px;pointer-events:none"></div><script src="/_next/static/chunks/e411019f55d87c42.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[39756,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"default\"]\n3:I[37457,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"default\"]\n4:I[5766,[\"/_next/static/chunks/cdd12d5c1a5a6064.js\"],\"Toaster\"]\n5:I[47257,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"ClientPageRoot\"]\n6:I[31713,[\"/_next/static/chunks/cdd12d5c1a5a6064.js\",\"/_next/static/chunks/f1ac9047ac4a3fde.js\",\"/_next/static/chunks/37d0cd2587a38f79.js\"],\"default\"]\n9:I[97367,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"OutletBoundary\"]\nb:I[11533,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"AsyncMetadataOutlet\"]\nd:I[97367,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"ViewportBoundary\"]\nf:I[97367,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"MetadataBoundary\"]\n10:\"$Sreact.suspense\"\n12:I[68027,[\"/_next/static/chunks/cdd12d5c1a5a6064.js\"],\"default\"]\n:HL[\"/_next/static/chunks/ecd2072ebf41611f.css\",\"style\"]\n:HL[\"/_next/static/media/797e433ab948586e-s.p.dbea232f.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n:HL[\"/_next/static/media/caa3a2e1cccd8315-s.p.853070df.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"b\":\"S5OZ2xYxrJopcK8El7EbO\",\"p\":\"\",\"c\":[\"\",\"\"],\"i\":false,\"f\":[[[\"\",{\"children\":[\"__PAGE__\",{}]},\"$undefined\",\"$undefined\",true],[\"\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/ecd2072ebf41611f.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/cdd12d5c1a5a6064.js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"ko\",\"className\":\"dark h-full\",\"children\":[\"$\",\"body\",null,{\"className\":\"geist_a71539c9-module__T19VSG__variable geist_mono_8d43a2aa-module__8Li5zG__variable antialiased h-screen overflow-hidden\",\"children\":[[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",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\"}],[\"$\",\"$L4\",null,{\"position\":\"bottom-right\",\"toastOptions\":{\"duration\":4000,\"style\":{\"background\":\"hsl(var(--background))\",\"color\":\"hsl(var(--foreground))\",\"border\":\"1px solid hsl(var(--border))\"}}}]]}]}]]}],{\"children\":[\"__PAGE__\",[\"$\",\"$1\",\"c\",{\"children\":[[\"$\",\"$L5\",null,{\"Component\":\"$6\",\"searchParams\":{},\"params\":{},\"promises\":[\"$@7\",\"$@8\"]}],[[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/f1ac9047ac4a3fde.js\",\"async\":true,\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-1\",{\"src\":\"/_next/static/chunks/37d0cd2587a38f79.js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"$L9\",null,{\"children\":[\"$La\",[\"$\",\"$Lb\",null,{\"promise\":\"$@c\"}]]}]]}],{},null,false]},null,false],[\"$\",\"$1\",\"h\",{\"children\":[null,[[\"$\",\"$Ld\",null,{\"children\":\"$Le\"}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]],[\"$\",\"$Lf\",null,{\"children\":[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$10\",null,{\"fallback\":null,\"children\":\"$L11\"}]}]}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$12\",[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/ecd2072ebf41611f.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]]],\"s\":false,\"S\":true}\n"])</script><script>self.__next_f.push([1,"7:{}\n8:\"$0:f:0:1:2:children:1:props:children:0:props:params\"\n"])</script><script>self.__next_f.push([1,"e:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\na:null\n"])</script><script>self.__next_f.push([1,"13:I[27201,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"IconMark\"]\nc:{\"metadata\":[[\"$\",\"title\",\"0\",{\"children\":\"Payload Log Viewer\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"AI Agent 로그 파일 뷰어 및 편집기\"}],[\"$\",\"link\",\"2\",{\"rel\":\"icon\",\"href\":\"/favicon.ico?favicon.0b3bf435.ico\",\"sizes\":\"256x256\",\"type\":\"image/x-icon\"}],[\"$\",\"$L13\",\"3\",{}]],\"error\":null,\"digest\":\"$undefined\"}\n"])</script><script>self.__next_f.push([1,"11:\"$c:metadata\"\n"])</script></body></html>
|
|
1
|
+
<!DOCTYPE html><!--Wnr9eYJaRUoC5a3SUgrBr--><html lang="ko" class="dark h-full"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" href="/_next/static/media/797e433ab948586e-s.p.dbea232f.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="preload" href="/_next/static/media/caa3a2e1cccd8315-s.p.853070df.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="stylesheet" href="/_next/static/chunks/ecd2072ebf41611f.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/e411019f55d87c42.js"/><script src="/_next/static/chunks/103c802c8f4a5ea1.js" async=""></script><script src="/_next/static/chunks/305b077a9873cf54.js" async=""></script><script src="/_next/static/chunks/turbopack-0ac29803ce3c3c7a.js" async=""></script><script src="/_next/static/chunks/060f9a97930f3d04.js" async=""></script><script src="/_next/static/chunks/cdd12d5c1a5a6064.js" async=""></script><script src="/_next/static/chunks/f1ac9047ac4a3fde.js" async=""></script><script src="/_next/static/chunks/37d0cd2587a38f79.js" async=""></script><meta name="next-size-adjust" content=""/><title>Payload Log Viewer</title><meta name="description" content="AI Agent 로그 파일 뷰어 및 편집기"/><link rel="icon" href="/favicon.ico?favicon.0b3bf435.ico" sizes="256x256" type="image/x-icon"/><script src="/_next/static/chunks/a6dad97d9634a72d.js" noModule=""></script></head><body class="geist_a71539c9-module__T19VSG__variable geist_mono_8d43a2aa-module__8Li5zG__variable antialiased h-screen overflow-hidden"><div hidden=""><!--$--><!--/$--></div><div class="h-screen bg-background flex"><div class="flex-shrink-0 w-80 border-r border-border bg-background flex flex-col"><div class="flex-shrink-0 border-b border-border p-4"><h2 class="text-lg font-semibold flex items-center gap-2"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-file-text h-5 w-5" aria-hidden="true"><path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"></path><path d="M14 2v4a2 2 0 0 0 2 2h4"></path><path d="M10 9H8"></path><path d="M16 13H8"></path><path d="M16 17H8"></path></svg>로그 파일</h2><p class="text-sm text-muted-foreground">로딩 중...</p></div><div class="flex-1 min-h-0"><div dir="ltr" class="relative overflow-hidden h-full" style="position:relative;--radix-scroll-area-corner-width:0px;--radix-scroll-area-corner-height:0px"><style>[data-radix-scroll-area-viewport]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}[data-radix-scroll-area-viewport]::-webkit-scrollbar{display:none}</style><div data-radix-scroll-area-viewport="" class="h-full w-full rounded-[inherit]" style="overflow-x:hidden;overflow-y:hidden"><div style="min-width:100%;display:table"><div class="p-4 text-center text-muted-foreground"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-refresh-cw h-6 w-6 animate-spin mx-auto mb-2" aria-hidden="true"><path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"></path><path d="M21 3v5h-5"></path><path d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16"></path><path d="M8 16H3v5"></path></svg>로딩 중...</div></div></div></div></div></div><div class="flex-1 min-w-0"><div class="rounded-lg border bg-card text-card-foreground shadow-sm h-full"><div class="p-6 pt-0 flex items-center justify-center h-full"><div class="text-center text-muted-foreground"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-square-pen h-12 w-12 mx-auto mb-4 opacity-50" aria-hidden="true"><path d="M12 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path><path d="M18.375 2.625a1 1 0 0 1 3 3l-9.013 9.014a2 2 0 0 1-.853.505l-2.873.84a.5.5 0 0 1-.62-.62l.84-2.873a2 2 0 0 1 .506-.852z"></path></svg><p class="text-lg">REQ 파일을 선택하세요</p><p class="text-sm">요청 파일을 선택하면 내용을 편집하고 재실행할 수 있습니다</p></div></div></div></div></div><!--$--><!--/$--><div data-rht-toaster="" style="position:fixed;z-index:9999;top:16px;left:16px;right:16px;bottom:16px;pointer-events:none"></div><script src="/_next/static/chunks/e411019f55d87c42.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[39756,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"default\"]\n3:I[37457,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"default\"]\n4:I[5766,[\"/_next/static/chunks/cdd12d5c1a5a6064.js\"],\"Toaster\"]\n5:I[47257,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"ClientPageRoot\"]\n6:I[31713,[\"/_next/static/chunks/cdd12d5c1a5a6064.js\",\"/_next/static/chunks/f1ac9047ac4a3fde.js\",\"/_next/static/chunks/37d0cd2587a38f79.js\"],\"default\"]\n9:I[97367,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"OutletBoundary\"]\nb:I[11533,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"AsyncMetadataOutlet\"]\nd:I[97367,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"ViewportBoundary\"]\nf:I[97367,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"MetadataBoundary\"]\n10:\"$Sreact.suspense\"\n12:I[68027,[\"/_next/static/chunks/cdd12d5c1a5a6064.js\"],\"default\"]\n:HL[\"/_next/static/chunks/ecd2072ebf41611f.css\",\"style\"]\n:HL[\"/_next/static/media/797e433ab948586e-s.p.dbea232f.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n:HL[\"/_next/static/media/caa3a2e1cccd8315-s.p.853070df.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"b\":\"Wnr9eYJaRUoC5a3SUgrBr\",\"p\":\"\",\"c\":[\"\",\"\"],\"i\":false,\"f\":[[[\"\",{\"children\":[\"__PAGE__\",{}]},\"$undefined\",\"$undefined\",true],[\"\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/ecd2072ebf41611f.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/cdd12d5c1a5a6064.js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"ko\",\"className\":\"dark h-full\",\"children\":[\"$\",\"body\",null,{\"className\":\"geist_a71539c9-module__T19VSG__variable geist_mono_8d43a2aa-module__8Li5zG__variable antialiased h-screen overflow-hidden\",\"children\":[[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",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\"}],[\"$\",\"$L4\",null,{\"position\":\"bottom-right\",\"toastOptions\":{\"duration\":4000,\"style\":{\"background\":\"hsl(var(--background))\",\"color\":\"hsl(var(--foreground))\",\"border\":\"1px solid hsl(var(--border))\"}}}]]}]}]]}],{\"children\":[\"__PAGE__\",[\"$\",\"$1\",\"c\",{\"children\":[[\"$\",\"$L5\",null,{\"Component\":\"$6\",\"searchParams\":{},\"params\":{},\"promises\":[\"$@7\",\"$@8\"]}],[[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/f1ac9047ac4a3fde.js\",\"async\":true,\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-1\",{\"src\":\"/_next/static/chunks/37d0cd2587a38f79.js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"$L9\",null,{\"children\":[\"$La\",[\"$\",\"$Lb\",null,{\"promise\":\"$@c\"}]]}]]}],{},null,false]},null,false],[\"$\",\"$1\",\"h\",{\"children\":[null,[[\"$\",\"$Ld\",null,{\"children\":\"$Le\"}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]],[\"$\",\"$Lf\",null,{\"children\":[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$10\",null,{\"fallback\":null,\"children\":\"$L11\"}]}]}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$12\",[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/ecd2072ebf41611f.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]]],\"s\":false,\"S\":true}\n"])</script><script>self.__next_f.push([1,"7:{}\n8:\"$0:f:0:1:2:children:1:props:children:0:props:params\"\n"])</script><script>self.__next_f.push([1,"e:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\na:null\n"])</script><script>self.__next_f.push([1,"13:I[27201,[\"/_next/static/chunks/060f9a97930f3d04.js\"],\"IconMark\"]\nc:{\"metadata\":[[\"$\",\"title\",\"0\",{\"children\":\"Payload Log Viewer\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"AI Agent 로그 파일 뷰어 및 편집기\"}],[\"$\",\"link\",\"2\",{\"rel\":\"icon\",\"href\":\"/favicon.ico?favicon.0b3bf435.ico\",\"sizes\":\"256x256\",\"type\":\"image/x-icon\"}],[\"$\",\"$L13\",\"3\",{}]],\"error\":null,\"digest\":\"$undefined\"}\n"])</script><script>self.__next_f.push([1,"11:\"$c:metadata\"\n"])</script></body></html>
|
|
@@ -13,7 +13,7 @@ f:I[97367,["/_next/static/chunks/060f9a97930f3d04.js"],"MetadataBoundary"]
|
|
|
13
13
|
:HL["/_next/static/chunks/ecd2072ebf41611f.css","style"]
|
|
14
14
|
:HL["/_next/static/media/797e433ab948586e-s.p.dbea232f.woff2","font",{"crossOrigin":"","type":"font/woff2"}]
|
|
15
15
|
:HL["/_next/static/media/caa3a2e1cccd8315-s.p.853070df.woff2","font",{"crossOrigin":"","type":"font/woff2"}]
|
|
16
|
-
0:{"P":null,"b":"
|
|
16
|
+
0:{"P":null,"b":"Wnr9eYJaRUoC5a3SUgrBr","p":"","c":["",""],"i":false,"f":[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/chunks/ecd2072ebf41611f.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","script","script-0",{"src":"/_next/static/chunks/cdd12d5c1a5a6064.js","async":true,"nonce":"$undefined"}]],["$","html",null,{"lang":"ko","className":"dark h-full","children":["$","body",null,{"className":"geist_a71539c9-module__T19VSG__variable geist_mono_8d43a2aa-module__8Li5zG__variable antialiased h-screen overflow-hidden","children":[["$","$L2",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",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"}],["$","$L4",null,{"position":"bottom-right","toastOptions":{"duration":4000,"style":{"background":"hsl(var(--background))","color":"hsl(var(--foreground))","border":"1px solid hsl(var(--border))"}}}]]}]}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$L5",null,{"Component":"$6","searchParams":{},"params":{},"promises":["$@7","$@8"]}],[["$","script","script-0",{"src":"/_next/static/chunks/f1ac9047ac4a3fde.js","async":true,"nonce":"$undefined"}],["$","script","script-1",{"src":"/_next/static/chunks/37d0cd2587a38f79.js","async":true,"nonce":"$undefined"}]],["$","$L9",null,{"children":["$La",["$","$Lb",null,{"promise":"$@c"}]]}]]}],{},null,false]},null,false],["$","$1","h",{"children":[null,[["$","$Ld",null,{"children":"$Le"}],["$","meta",null,{"name":"next-size-adjust","content":""}]],["$","$Lf",null,{"children":["$","div",null,{"hidden":true,"children":["$","$10",null,{"fallback":null,"children":"$L11"}]}]}]]}],false]],"m":"$undefined","G":["$12",[["$","link","0",{"rel":"stylesheet","href":"/_next/static/chunks/ecd2072ebf41611f.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]]],"s":false,"S":true}
|
|
17
17
|
7:{}
|
|
18
18
|
8:"$0:f:0:1:2:children:1:props:children:0:props:params"
|
|
19
19
|
e:[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]
|
package/prompts/orchestrator.txt
CHANGED
|
@@ -865,6 +865,40 @@ edit_file_replace({
|
|
|
865
865
|
bash({ script: "npm test" })
|
|
866
866
|
```
|
|
867
867
|
|
|
868
|
+
## Markdown formatting in responses
|
|
869
|
+
|
|
870
|
+
**ALWAYS use Markdown** in all text responses. The terminal UI renders rich Markdown formatting.
|
|
871
|
+
|
|
872
|
+
**Supported features:**
|
|
873
|
+
- Headers: `#` to `####` (H1-H4) - use to structure responses
|
|
874
|
+
- Lists: `-` `*` `+` (unordered), `1.` (ordered) - nestable with indentation
|
|
875
|
+
- Tables: `|` pipes - keep to 3-5 columns for readability
|
|
876
|
+
- Code blocks: ` ```language ` - always include language tag for syntax highlighting
|
|
877
|
+
- Inline: `**bold**` `*italic*` `` `code` `` `~~strike~~` `[link](url)`
|
|
878
|
+
- Horizontal rules: `---` for visual separation
|
|
879
|
+
- Not supported: blockquotes, images, HTML tags
|
|
880
|
+
|
|
881
|
+
**Formatting requirements:**
|
|
882
|
+
- Structure all responses with headers and lists
|
|
883
|
+
- Use `code` for file names, commands, variable names
|
|
884
|
+
- Use **bold** for important points or status
|
|
885
|
+
- Use tables for structured data comparison
|
|
886
|
+
- Always tag code blocks with language (js, python, bash, etc.)
|
|
887
|
+
|
|
888
|
+
**Example:**
|
|
889
|
+
```markdown
|
|
890
|
+
## Changes Made
|
|
891
|
+
- Updated authentication with OAuth integration
|
|
892
|
+
- Added 5 new test cases in `auth.test.js`
|
|
893
|
+
|
|
894
|
+
| File | Status |
|
|
895
|
+
|------|--------|
|
|
896
|
+
| auth.js | **Modified** |
|
|
897
|
+
| config.js | Added |
|
|
898
|
+
|
|
899
|
+
**Verification:** All tests passing ✓
|
|
900
|
+
```
|
|
901
|
+
|
|
868
902
|
## Communication during execution
|
|
869
903
|
|
|
870
904
|
**response_message: Brief Upcoming Action Guidance**
|
|
@@ -173,7 +173,7 @@ function CodeResultDisplay({ item }) {
|
|
|
173
173
|
);
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
-
function StandardDisplay({ item, isPending, hasFollowingResult, nextItem, isLastInBatch = false }) {
|
|
176
|
+
function StandardDisplay({ item, isPending, hasFollowingResult, nextItem, isLastInBatch = false, terminalWidth }) {
|
|
177
177
|
const { type, text, operations = [], toolName, toolInput, args } = item;
|
|
178
178
|
const config = getTypeConfig(type);
|
|
179
179
|
|
|
@@ -542,7 +542,7 @@ function StandardDisplay({ item, isPending, hasFollowingResult, nextItem, isLast
|
|
|
542
542
|
bold: config.bold
|
|
543
543
|
}, config.icon),
|
|
544
544
|
React.createElement(Box, { flexDirection: "column", flexGrow: 1 },
|
|
545
|
-
renderMarkdown(text)
|
|
545
|
+
renderMarkdown(text, { terminalWidth: terminalWidth || 80 })
|
|
546
546
|
)
|
|
547
547
|
);
|
|
548
548
|
}
|
|
@@ -781,6 +781,7 @@ function StandardDisplay({ item, isPending, hasFollowingResult, nextItem, isLast
|
|
|
781
781
|
let textContent;
|
|
782
782
|
if (text && typeof text === 'object' && text.type === 'formatted' && Array.isArray(text.parts)) {
|
|
783
783
|
// 구조화된 parts를 렌더링
|
|
784
|
+
debugLog(`Rendering formatted text with ${text.parts.length} parts`);
|
|
784
785
|
textContent = React.createElement(Box, { flexDirection: "row" },
|
|
785
786
|
...text.parts.map((part, idx) =>
|
|
786
787
|
React.createElement(Text, {
|
|
@@ -790,8 +791,13 @@ function StandardDisplay({ item, isPending, hasFollowingResult, nextItem, isLast
|
|
|
790
791
|
}, part.text)
|
|
791
792
|
)
|
|
792
793
|
);
|
|
794
|
+
} else if (type === 'assistant' && typeof text === 'string') {
|
|
795
|
+
// assistant 응답은 마크다운 렌더링 적용
|
|
796
|
+
debugLog(`Rendering assistant response with Markdown, text length: ${text.length}, terminalWidth: ${terminalWidth || 80}`);
|
|
797
|
+
textContent = renderMarkdown(text, { terminalWidth: terminalWidth || 80 });
|
|
793
798
|
} else {
|
|
794
799
|
// 일반 문자열
|
|
800
|
+
debugLog(`Rendering plain text, type: ${type}, text length: ${typeof text === 'string' ? text.length : 'N/A'}`);
|
|
795
801
|
textContent = React.createElement(Text, {
|
|
796
802
|
color: textColor
|
|
797
803
|
}, text);
|
|
@@ -831,7 +837,7 @@ export function ConversationItem({ item, isPending = false, terminalWidth, nextI
|
|
|
831
837
|
debugLog(`hasFollowingResult: ${hasFollowingResult}`);
|
|
832
838
|
debugLog('Rendering StandardDisplay');
|
|
833
839
|
|
|
834
|
-
const result = React.createElement(StandardDisplay, { item, isPending, hasFollowingResult, nextItem, isLastInBatch });
|
|
840
|
+
const result = React.createElement(StandardDisplay, { item, isPending, hasFollowingResult, nextItem, isLastInBatch, terminalWidth });
|
|
835
841
|
|
|
836
842
|
return result;
|
|
837
843
|
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Grid Renderer
|
|
3
|
+
* 마크다운 테이블을 렌더링하는 컴포넌트
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import { Text, Box } from 'ink';
|
|
8
|
+
import { theme } from '../design/themeColors.js';
|
|
9
|
+
import { ProcessInlineText, calculateTextWidth } from './InlineFormatter.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* 마크다운 테이블을 렌더링하는 컴포넌트
|
|
13
|
+
* @param {Object} props
|
|
14
|
+
* @param {string[]} props.columnHeaders - 테이블 헤더
|
|
15
|
+
* @param {string[][]} props.dataRows - 테이블 데이터 행
|
|
16
|
+
* @param {number} props.maxWidth - 터미널 최대 너비
|
|
17
|
+
*/
|
|
18
|
+
export const GridRenderer = ({ columnHeaders, dataRows, maxWidth }) => {
|
|
19
|
+
// 컬럼 너비 계산 (마크다운 처리 후 실제 표시 너비 기준)
|
|
20
|
+
const widthPerColumn = columnHeaders.map((headerText, columnIndex) => {
|
|
21
|
+
const headerDisplayWidth = calculateTextWidth(headerText);
|
|
22
|
+
const maxDataWidth = Math.max(
|
|
23
|
+
...dataRows.map((rowData) => calculateTextWidth(rowData[columnIndex] || ''))
|
|
24
|
+
);
|
|
25
|
+
return Math.max(headerDisplayWidth, maxDataWidth) + 2; // 패딩 추가
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// 테이블이 터미널 너비를 초과하지 않도록 조정
|
|
29
|
+
const totalRequiredWidth = widthPerColumn.reduce((sum, w) => sum + w + 1, 1);
|
|
30
|
+
const shrinkRatio = totalRequiredWidth > maxWidth ? maxWidth / totalRequiredWidth : 1;
|
|
31
|
+
const finalWidths = widthPerColumn.map((w) => Math.floor(w * shrinkRatio));
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 셀 내용을 렌더링 (너비에 맞게 잘라내거나 패딩 추가)
|
|
35
|
+
*/
|
|
36
|
+
const buildCell = (cellText, cellWidth, isHeaderCell = false) => {
|
|
37
|
+
const availableWidth = Math.max(0, cellWidth - 2);
|
|
38
|
+
const actualWidth = calculateTextWidth(cellText);
|
|
39
|
+
|
|
40
|
+
let displayText = cellText;
|
|
41
|
+
if (actualWidth > availableWidth) {
|
|
42
|
+
if (availableWidth <= 3) {
|
|
43
|
+
// 너비가 매우 작으면 단순 잘라내기
|
|
44
|
+
displayText = cellText.substring(0, Math.min(cellText.length, availableWidth));
|
|
45
|
+
} else {
|
|
46
|
+
// 이진 탐색으로 마크다운을 보존하면서 최적 절단점 찾기
|
|
47
|
+
let leftBound = 0;
|
|
48
|
+
let rightBound = cellText.length;
|
|
49
|
+
let bestFit = cellText;
|
|
50
|
+
|
|
51
|
+
while (leftBound <= rightBound) {
|
|
52
|
+
const midPoint = Math.floor((leftBound + rightBound) / 2);
|
|
53
|
+
const testText = cellText.substring(0, midPoint);
|
|
54
|
+
const testWidth = calculateTextWidth(testText);
|
|
55
|
+
|
|
56
|
+
if (testWidth <= availableWidth - 3) {
|
|
57
|
+
bestFit = testText;
|
|
58
|
+
leftBound = midPoint + 1;
|
|
59
|
+
} else {
|
|
60
|
+
rightBound = midPoint - 1;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
displayText = bestFit + '...';
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// 정확한 패딩 계산
|
|
69
|
+
const finalDisplayWidth = calculateTextWidth(displayText);
|
|
70
|
+
const paddingRequired = Math.max(0, availableWidth - finalDisplayWidth);
|
|
71
|
+
|
|
72
|
+
return React.createElement(Text, null,
|
|
73
|
+
isHeaderCell
|
|
74
|
+
? React.createElement(Text, { bold: true, color: theme.text.link },
|
|
75
|
+
React.createElement(ProcessInlineText, { content: displayText })
|
|
76
|
+
)
|
|
77
|
+
: React.createElement(ProcessInlineText, { content: displayText }),
|
|
78
|
+
' '.repeat(paddingRequired)
|
|
79
|
+
);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* 테두리 렌더링
|
|
84
|
+
*/
|
|
85
|
+
const buildBorderLine = (position) => {
|
|
86
|
+
const borderStyles = {
|
|
87
|
+
top: { leftCorner: '┌', junction: '┬', rightCorner: '┐', line: '─' },
|
|
88
|
+
mid: { leftCorner: '├', junction: '┼', rightCorner: '┤', line: '─' },
|
|
89
|
+
bottom: { leftCorner: '└', junction: '┴', rightCorner: '┘', line: '─' }
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const style = borderStyles[position];
|
|
93
|
+
const segments = finalWidths.map((width) => style.line.repeat(width));
|
|
94
|
+
const borderText = style.leftCorner + segments.join(style.junction) + style.rightCorner;
|
|
95
|
+
|
|
96
|
+
return React.createElement(Text, { color: theme.text.secondary }, borderText);
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* 테이블 행 렌더링
|
|
101
|
+
*/
|
|
102
|
+
const buildTableRow = (rowCells, isHeaderRow = false) => {
|
|
103
|
+
const renderedCells = rowCells.map((cellContent, idx) => {
|
|
104
|
+
const width = finalWidths[idx] || 0;
|
|
105
|
+
return buildCell(cellContent || '', width, isHeaderRow);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
return React.createElement(Text, { color: theme.text.primary },
|
|
109
|
+
'│ ',
|
|
110
|
+
...renderedCells.map((cell, idx) =>
|
|
111
|
+
React.createElement(React.Fragment, { key: idx },
|
|
112
|
+
cell,
|
|
113
|
+
idx < renderedCells.length - 1 ? ' │ ' : ''
|
|
114
|
+
)
|
|
115
|
+
),
|
|
116
|
+
' │'
|
|
117
|
+
);
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
return React.createElement(Box, { flexDirection: 'column', marginY: 1 },
|
|
121
|
+
// 상단 테두리
|
|
122
|
+
buildBorderLine('top'),
|
|
123
|
+
|
|
124
|
+
// 헤더 행
|
|
125
|
+
buildTableRow(columnHeaders, true),
|
|
126
|
+
|
|
127
|
+
// 중간 테두리
|
|
128
|
+
buildBorderLine('mid'),
|
|
129
|
+
|
|
130
|
+
// 데이터 행
|
|
131
|
+
...dataRows.map((row, idx) =>
|
|
132
|
+
React.createElement(React.Fragment, { key: idx },
|
|
133
|
+
buildTableRow(row)
|
|
134
|
+
)
|
|
135
|
+
),
|
|
136
|
+
|
|
137
|
+
// 하단 테두리
|
|
138
|
+
buildBorderLine('bottom')
|
|
139
|
+
);
|
|
140
|
+
};
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inline Formatter
|
|
3
|
+
* 인라인 마크다운 요소를 파싱하여 Ink 컴포넌트로 변환
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import { Text } from 'ink';
|
|
8
|
+
import { theme } from '../design/themeColors.js';
|
|
9
|
+
import stringWidth from 'string-width';
|
|
10
|
+
|
|
11
|
+
// 마크다운 마커 길이 상수
|
|
12
|
+
const MARKER_LENGTHS = {
|
|
13
|
+
BOLD: 2, // "**"
|
|
14
|
+
ITALIC: 1, // "*" or "_"
|
|
15
|
+
STRIKE: 2, // "~~"
|
|
16
|
+
CODE: 1, // "`"
|
|
17
|
+
UNDERLINE_START: 3, // "<u>"
|
|
18
|
+
UNDERLINE_END: 4 // "</u>"
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 인라인 마크다운을 렌더링하는 컴포넌트
|
|
23
|
+
*/
|
|
24
|
+
const ProcessInlineTextInternal = ({ content }) => {
|
|
25
|
+
// 마크다운이나 URL이 없으면 바로 반환
|
|
26
|
+
if (!/[*_~`<[https?:]/.test(content)) {
|
|
27
|
+
return React.createElement(Text, { color: theme.text.primary }, content);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const elements = [];
|
|
31
|
+
let currentPosition = 0;
|
|
32
|
+
const patternRegex = /(\*\*.*?\*\*|\*.*?\*|_.*?_|~~.*?~~|\[.*?\]\(.*?\)|`+.+?`+|<u>.*?<\/u>|https?:\/\/\S+)/g;
|
|
33
|
+
let matchResult;
|
|
34
|
+
|
|
35
|
+
while ((matchResult = patternRegex.exec(content)) !== null) {
|
|
36
|
+
if (matchResult.index > currentPosition) {
|
|
37
|
+
elements.push(
|
|
38
|
+
React.createElement(Text, { key: `plain-${currentPosition}` },
|
|
39
|
+
content.slice(currentPosition, matchResult.index)
|
|
40
|
+
)
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const matchedText = matchResult[0];
|
|
45
|
+
let formattedElement = null;
|
|
46
|
+
const elementKey = `fmt-${matchResult.index}`;
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
// 볼드 처리
|
|
50
|
+
if (matchedText.startsWith('**') &&
|
|
51
|
+
matchedText.endsWith('**') &&
|
|
52
|
+
matchedText.length > MARKER_LENGTHS.BOLD * 2) {
|
|
53
|
+
formattedElement = React.createElement(Text, { key: elementKey, bold: true },
|
|
54
|
+
matchedText.slice(MARKER_LENGTHS.BOLD, -MARKER_LENGTHS.BOLD)
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
// 이탤릭 처리
|
|
58
|
+
else if (matchedText.length > MARKER_LENGTHS.ITALIC * 2 &&
|
|
59
|
+
((matchedText.startsWith('*') && matchedText.endsWith('*')) ||
|
|
60
|
+
(matchedText.startsWith('_') && matchedText.endsWith('_'))) &&
|
|
61
|
+
!/\w/.test(content.substring(matchResult.index - 1, matchResult.index)) &&
|
|
62
|
+
!/\w/.test(content.substring(patternRegex.lastIndex, patternRegex.lastIndex + 1)) &&
|
|
63
|
+
!/\S[./\\]/.test(content.substring(matchResult.index - 2, matchResult.index)) &&
|
|
64
|
+
!/[./\\]\S/.test(content.substring(patternRegex.lastIndex, patternRegex.lastIndex + 2))) {
|
|
65
|
+
formattedElement = React.createElement(Text, { key: elementKey, italic: true },
|
|
66
|
+
matchedText.slice(MARKER_LENGTHS.ITALIC, -MARKER_LENGTHS.ITALIC)
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
// 취소선 처리
|
|
70
|
+
else if (matchedText.startsWith('~~') &&
|
|
71
|
+
matchedText.endsWith('~~') &&
|
|
72
|
+
matchedText.length > MARKER_LENGTHS.STRIKE * 2) {
|
|
73
|
+
formattedElement = React.createElement(Text, { key: elementKey, strikethrough: true },
|
|
74
|
+
matchedText.slice(MARKER_LENGTHS.STRIKE, -MARKER_LENGTHS.STRIKE)
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
// 인라인 코드 처리
|
|
78
|
+
else if (matchedText.startsWith('`') &&
|
|
79
|
+
matchedText.endsWith('`') &&
|
|
80
|
+
matchedText.length > MARKER_LENGTHS.CODE) {
|
|
81
|
+
const codePattern = matchedText.match(/^(`+)(.+?)\1$/s);
|
|
82
|
+
if (codePattern && codePattern[2]) {
|
|
83
|
+
formattedElement = React.createElement(Text, {
|
|
84
|
+
key: elementKey,
|
|
85
|
+
color: theme.status.warning
|
|
86
|
+
}, codePattern[2]);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// 링크 처리
|
|
90
|
+
else if (matchedText.startsWith('[') &&
|
|
91
|
+
matchedText.includes('](') &&
|
|
92
|
+
matchedText.endsWith(')')) {
|
|
93
|
+
const linkPattern = matchedText.match(/\[(.*?)\]\((.*?)\)/);
|
|
94
|
+
if (linkPattern) {
|
|
95
|
+
const linkLabel = linkPattern[1];
|
|
96
|
+
const linkUrl = linkPattern[2];
|
|
97
|
+
formattedElement = React.createElement(Text, { key: elementKey },
|
|
98
|
+
linkLabel,
|
|
99
|
+
React.createElement(Text, { color: theme.text.link }, ` (${linkUrl})`)
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// 밑줄 처리
|
|
104
|
+
else if (matchedText.startsWith('<u>') &&
|
|
105
|
+
matchedText.endsWith('</u>') &&
|
|
106
|
+
matchedText.length > MARKER_LENGTHS.UNDERLINE_START + MARKER_LENGTHS.UNDERLINE_END - 1) {
|
|
107
|
+
formattedElement = React.createElement(Text, { key: elementKey, underline: true },
|
|
108
|
+
matchedText.slice(MARKER_LENGTHS.UNDERLINE_START, -MARKER_LENGTHS.UNDERLINE_END)
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
// URL 처리
|
|
112
|
+
else if (matchedText.match(/^https?:\/\//)) {
|
|
113
|
+
formattedElement = React.createElement(Text, {
|
|
114
|
+
key: elementKey,
|
|
115
|
+
color: theme.text.link
|
|
116
|
+
}, matchedText);
|
|
117
|
+
}
|
|
118
|
+
} catch (error) {
|
|
119
|
+
// 파싱 오류 발생 시 무시
|
|
120
|
+
formattedElement = null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
elements.push(
|
|
124
|
+
formattedElement ?? React.createElement(Text, { key: elementKey }, matchedText)
|
|
125
|
+
);
|
|
126
|
+
currentPosition = patternRegex.lastIndex;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (currentPosition < content.length) {
|
|
130
|
+
elements.push(
|
|
131
|
+
React.createElement(Text, { key: `plain-${currentPosition}` },
|
|
132
|
+
content.slice(currentPosition)
|
|
133
|
+
)
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return React.createElement(React.Fragment, null, elements.filter(el => el !== null));
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
export const ProcessInlineText = React.memo(ProcessInlineTextInternal);
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* 마크다운 포맷팅을 제거하고 실제 텍스트 길이를 계산
|
|
144
|
+
* 테이블의 컬럼 너비 계산 등에 사용
|
|
145
|
+
*/
|
|
146
|
+
export function calculateTextWidth(content) {
|
|
147
|
+
const plainText = content
|
|
148
|
+
.replace(/\*\*(.*?)\*\*/g, '$1')
|
|
149
|
+
.replace(/\*(.*?)\*/g, '$1')
|
|
150
|
+
.replace(/_(.*?)_/g, '$1')
|
|
151
|
+
.replace(/~~(.*?)~~/g, '$1')
|
|
152
|
+
.replace(/`(.*?)`/g, '$1')
|
|
153
|
+
.replace(/<u>(.*?)<\/u>/g, '$1')
|
|
154
|
+
.replace(/.*\[(.*?)\]\(.*\)/g, '$1');
|
|
155
|
+
return stringWidth(plainText);
|
|
156
|
+
}
|
|
@@ -6,226 +6,372 @@
|
|
|
6
6
|
import React from 'react';
|
|
7
7
|
import { Text, Box } from 'ink';
|
|
8
8
|
import { theme } from '../design/themeColors.js';
|
|
9
|
+
import { colorizeCode } from './syntaxHighlighter.js';
|
|
10
|
+
import { GridRenderer } from './GridRenderer.js';
|
|
11
|
+
import { ProcessInlineText } from './InlineFormatter.js';
|
|
12
|
+
|
|
13
|
+
// 렌더링 상수
|
|
14
|
+
const SPACING = {
|
|
15
|
+
EMPTY_LINE: 1,
|
|
16
|
+
CODE_PADDING: 1,
|
|
17
|
+
LIST_PREFIX_PAD: 1,
|
|
18
|
+
LIST_TEXT_GROW: 1
|
|
19
|
+
};
|
|
9
20
|
|
|
10
21
|
/**
|
|
11
22
|
* 마크다운 텍스트를 파싱하여 Ink 컴포넌트로 변환
|
|
23
|
+
* @param {string} text - 마크다운 텍스트
|
|
24
|
+
* @param {Object} options - 렌더링 옵션
|
|
25
|
+
* @param {boolean} options.isPending - 스트리밍 중 여부
|
|
26
|
+
* @param {number} options.availableHeight - 사용 가능한 터미널 높이
|
|
27
|
+
* @param {number} options.terminalWidth - 터미널 너비 (기본값: 80)
|
|
28
|
+
* @returns {React.ReactNode}
|
|
12
29
|
*/
|
|
13
|
-
export function renderMarkdown(text) {
|
|
30
|
+
export function renderMarkdown(text, options = {}) {
|
|
14
31
|
if (!text) return null;
|
|
15
32
|
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
33
|
+
const {
|
|
34
|
+
isPending = false,
|
|
35
|
+
availableHeight,
|
|
36
|
+
terminalWidth = 80
|
|
37
|
+
} = options;
|
|
38
|
+
|
|
39
|
+
const lineArray = text.split(/\r?\n/);
|
|
40
|
+
|
|
41
|
+
// 정규식 패턴
|
|
42
|
+
const patterns = {
|
|
43
|
+
header: /^ *(#{1,4}) +(.*)/,
|
|
44
|
+
codeFence: /^ *(`{3,}|~{3,}) *(\w*?) *$/,
|
|
45
|
+
unorderedList: /^([ \t]*)([-*+]) +(.*)/,
|
|
46
|
+
orderedList: /^([ \t]*)(\d+)\. +(.*)/,
|
|
47
|
+
horizontalRule: /^ *([-*_] *){3,} *$/,
|
|
48
|
+
tableRow: /^\s*\|(.+)\|\s*$/,
|
|
49
|
+
tableSeparator: /^\s*\|?\s*(:?-+:?)\s*(\|\s*(:?-+:?)\s*)+\|?\s*$/
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const blocks = [];
|
|
53
|
+
let previousLineWasEmpty = true;
|
|
54
|
+
|
|
55
|
+
// 상태 변수
|
|
56
|
+
let codeBlockActive = false;
|
|
57
|
+
let codeBlockLines = [];
|
|
58
|
+
let codeBlockLanguage = null;
|
|
59
|
+
let codeBlockFence = '';
|
|
60
|
+
|
|
61
|
+
let tableActive = false;
|
|
62
|
+
let tableHeaderCells = [];
|
|
63
|
+
let tableDataRows = [];
|
|
64
|
+
|
|
65
|
+
function appendBlock(block) {
|
|
66
|
+
if (block) {
|
|
67
|
+
blocks.push(block);
|
|
68
|
+
previousLineWasEmpty = false;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
lineArray.forEach((currentLine, lineIndex) => {
|
|
73
|
+
const lineKey = `ln-${lineIndex}`;
|
|
74
|
+
|
|
75
|
+
// 코드 블록 내부 처리
|
|
76
|
+
if (codeBlockActive) {
|
|
77
|
+
const fenceMatch = currentLine.match(patterns.codeFence);
|
|
78
|
+
if (fenceMatch &&
|
|
79
|
+
fenceMatch[1].startsWith(codeBlockFence[0]) &&
|
|
80
|
+
fenceMatch[1].length >= codeBlockFence.length) {
|
|
81
|
+
appendBlock(
|
|
82
|
+
React.createElement(BuildCodeBlock, {
|
|
83
|
+
key: lineKey,
|
|
84
|
+
lines: codeBlockLines,
|
|
85
|
+
language: codeBlockLanguage,
|
|
86
|
+
isPending,
|
|
87
|
+
availableHeight,
|
|
88
|
+
terminalWidth
|
|
89
|
+
})
|
|
90
|
+
);
|
|
91
|
+
codeBlockActive = false;
|
|
92
|
+
codeBlockLines = [];
|
|
93
|
+
codeBlockLanguage = null;
|
|
94
|
+
codeBlockFence = '';
|
|
46
95
|
} else {
|
|
47
|
-
|
|
48
|
-
codeLanguage = line.trim().slice(3).trim();
|
|
49
|
-
inCodeBlock = true;
|
|
96
|
+
codeBlockLines.push(currentLine);
|
|
50
97
|
}
|
|
51
|
-
|
|
98
|
+
return;
|
|
52
99
|
}
|
|
53
100
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
101
|
+
// 패턴 매칭
|
|
102
|
+
const fenceMatch = currentLine.match(patterns.codeFence);
|
|
103
|
+
const headerMatch = currentLine.match(patterns.header);
|
|
104
|
+
const ulMatch = currentLine.match(patterns.unorderedList);
|
|
105
|
+
const olMatch = currentLine.match(patterns.orderedList);
|
|
106
|
+
const hrMatch = currentLine.match(patterns.horizontalRule);
|
|
107
|
+
const tableRowMatch = currentLine.match(patterns.tableRow);
|
|
108
|
+
const tableSepMatch = currentLine.match(patterns.tableSeparator);
|
|
58
109
|
|
|
59
|
-
//
|
|
60
|
-
if (
|
|
61
|
-
|
|
62
|
-
|
|
110
|
+
// 코드 블록 시작
|
|
111
|
+
if (fenceMatch) {
|
|
112
|
+
codeBlockActive = true;
|
|
113
|
+
codeBlockFence = fenceMatch[1];
|
|
114
|
+
codeBlockLanguage = fenceMatch[2] || null;
|
|
115
|
+
}
|
|
116
|
+
// 테이블 시작 감지
|
|
117
|
+
else if (tableRowMatch && !tableActive) {
|
|
118
|
+
if (lineIndex + 1 < lineArray.length &&
|
|
119
|
+
lineArray[lineIndex + 1].match(patterns.tableSeparator)) {
|
|
120
|
+
tableActive = true;
|
|
121
|
+
tableHeaderCells = tableRowMatch[1].split('|').map(cell => cell.trim());
|
|
122
|
+
tableDataRows = [];
|
|
123
|
+
} else {
|
|
124
|
+
appendBlock(
|
|
125
|
+
React.createElement(Box, { key: lineKey },
|
|
126
|
+
React.createElement(Text, { wrap: 'wrap' },
|
|
127
|
+
React.createElement(ProcessInlineText, { content: currentLine })
|
|
128
|
+
)
|
|
129
|
+
)
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// 테이블 구분선 스킵
|
|
134
|
+
else if (tableActive && tableSepMatch) {
|
|
135
|
+
// 구분선은 무시
|
|
136
|
+
}
|
|
137
|
+
// 테이블 데이터 행
|
|
138
|
+
else if (tableActive && tableRowMatch) {
|
|
139
|
+
const cells = tableRowMatch[1].split('|').map(cell => cell.trim());
|
|
140
|
+
while (cells.length < tableHeaderCells.length) cells.push('');
|
|
141
|
+
if (cells.length > tableHeaderCells.length) cells.length = tableHeaderCells.length;
|
|
142
|
+
tableDataRows.push(cells);
|
|
63
143
|
}
|
|
144
|
+
// 테이블 종료
|
|
145
|
+
else if (tableActive && !tableRowMatch) {
|
|
146
|
+
if (tableHeaderCells.length > 0 && tableDataRows.length > 0) {
|
|
147
|
+
appendBlock(
|
|
148
|
+
React.createElement(BuildTable, {
|
|
149
|
+
key: `table-${blocks.length}`,
|
|
150
|
+
columnHeaders: tableHeaderCells,
|
|
151
|
+
dataRows: tableDataRows,
|
|
152
|
+
maxWidth: terminalWidth
|
|
153
|
+
})
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
tableActive = false;
|
|
157
|
+
tableDataRows = [];
|
|
158
|
+
tableHeaderCells = [];
|
|
64
159
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}, renderInlineMarkdown(line.slice(4)))
|
|
76
|
-
)
|
|
77
|
-
);
|
|
78
|
-
continue;
|
|
160
|
+
// 현재 줄 처리
|
|
161
|
+
if (currentLine.trim().length > 0) {
|
|
162
|
+
appendBlock(
|
|
163
|
+
React.createElement(Box, { key: lineKey },
|
|
164
|
+
React.createElement(Text, { wrap: 'wrap' },
|
|
165
|
+
React.createElement(ProcessInlineText, { content: currentLine })
|
|
166
|
+
)
|
|
167
|
+
)
|
|
168
|
+
);
|
|
169
|
+
}
|
|
79
170
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
},
|
|
86
|
-
React.createElement(Text, {
|
|
87
|
-
color: theme.text.accent,
|
|
88
|
-
bold: true
|
|
89
|
-
}, renderInlineMarkdown(line.slice(3)))
|
|
171
|
+
// 수평선
|
|
172
|
+
else if (hrMatch) {
|
|
173
|
+
appendBlock(
|
|
174
|
+
React.createElement(Box, { key: lineKey },
|
|
175
|
+
React.createElement(Text, { dimColor: true }, '---')
|
|
90
176
|
)
|
|
91
177
|
);
|
|
92
|
-
continue;
|
|
93
178
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
179
|
+
// 헤더
|
|
180
|
+
else if (headerMatch) {
|
|
181
|
+
const level = headerMatch[1].length;
|
|
182
|
+
const headerText = headerMatch[2];
|
|
183
|
+
let headerElement = null;
|
|
184
|
+
|
|
185
|
+
switch (level) {
|
|
186
|
+
case 1:
|
|
187
|
+
headerElement = React.createElement(Text, { bold: true, color: theme.text.link },
|
|
188
|
+
React.createElement(ProcessInlineText, { content: headerText })
|
|
189
|
+
);
|
|
190
|
+
break;
|
|
191
|
+
case 2:
|
|
192
|
+
headerElement = React.createElement(Text, { bold: true, color: theme.text.link },
|
|
193
|
+
React.createElement(ProcessInlineText, { content: headerText })
|
|
194
|
+
);
|
|
195
|
+
break;
|
|
196
|
+
case 3:
|
|
197
|
+
headerElement = React.createElement(Text, { bold: true, color: theme.text.primary },
|
|
198
|
+
React.createElement(ProcessInlineText, { content: headerText })
|
|
199
|
+
);
|
|
200
|
+
break;
|
|
201
|
+
case 4:
|
|
202
|
+
headerElement = React.createElement(Text, { italic: true, color: theme.text.secondary },
|
|
203
|
+
React.createElement(ProcessInlineText, { content: headerText })
|
|
204
|
+
);
|
|
205
|
+
break;
|
|
206
|
+
default:
|
|
207
|
+
headerElement = React.createElement(Text, { color: theme.text.primary },
|
|
208
|
+
React.createElement(ProcessInlineText, { content: headerText })
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
if (headerElement) {
|
|
212
|
+
appendBlock(React.createElement(Box, { key: lineKey }, headerElement));
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
// 순서 없는 리스트
|
|
216
|
+
else if (ulMatch) {
|
|
217
|
+
const [, indent, marker, content] = ulMatch;
|
|
218
|
+
appendBlock(
|
|
219
|
+
React.createElement(BuildListItem, {
|
|
220
|
+
key: lineKey,
|
|
221
|
+
itemText: content,
|
|
222
|
+
listType: 'ul',
|
|
223
|
+
marker: marker,
|
|
224
|
+
indentation: indent
|
|
225
|
+
})
|
|
105
226
|
);
|
|
106
|
-
continue;
|
|
107
227
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
}
|
|
119
|
-
React.createElement(Text, { color: theme.text.accent }, bullet + ' '),
|
|
120
|
-
React.createElement(Text, null, renderInlineMarkdown(content))
|
|
121
|
-
)
|
|
228
|
+
// 순서 있는 리스트
|
|
229
|
+
else if (olMatch) {
|
|
230
|
+
const [, indent, marker, content] = olMatch;
|
|
231
|
+
appendBlock(
|
|
232
|
+
React.createElement(BuildListItem, {
|
|
233
|
+
key: lineKey,
|
|
234
|
+
itemText: content,
|
|
235
|
+
listType: 'ol',
|
|
236
|
+
marker: marker,
|
|
237
|
+
indentation: indent
|
|
238
|
+
})
|
|
122
239
|
);
|
|
123
|
-
continue;
|
|
124
240
|
}
|
|
241
|
+
// 빈 줄 또는 일반 텍스트
|
|
242
|
+
else {
|
|
243
|
+
if (currentLine.trim().length === 0 && !codeBlockActive) {
|
|
244
|
+
if (!previousLineWasEmpty) {
|
|
245
|
+
blocks.push(
|
|
246
|
+
React.createElement(Box, {
|
|
247
|
+
key: `space-${lineIndex}`,
|
|
248
|
+
height: SPACING.EMPTY_LINE
|
|
249
|
+
})
|
|
250
|
+
);
|
|
251
|
+
previousLineWasEmpty = true;
|
|
252
|
+
}
|
|
253
|
+
} else {
|
|
254
|
+
appendBlock(
|
|
255
|
+
React.createElement(Box, { key: lineKey },
|
|
256
|
+
React.createElement(Text, { wrap: 'wrap', color: theme.text.primary },
|
|
257
|
+
React.createElement(ProcessInlineText, { content: currentLine })
|
|
258
|
+
)
|
|
259
|
+
)
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
});
|
|
125
264
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
265
|
+
// 닫히지 않은 코드 블록 처리
|
|
266
|
+
if (codeBlockActive) {
|
|
267
|
+
appendBlock(
|
|
268
|
+
React.createElement(BuildCodeBlock, {
|
|
269
|
+
key: 'eof-code',
|
|
270
|
+
lines: codeBlockLines,
|
|
271
|
+
language: codeBlockLanguage,
|
|
272
|
+
isPending,
|
|
273
|
+
availableHeight,
|
|
274
|
+
terminalWidth
|
|
275
|
+
})
|
|
134
276
|
);
|
|
135
277
|
}
|
|
136
278
|
|
|
137
|
-
|
|
279
|
+
// 닫히지 않은 테이블 처리
|
|
280
|
+
if (tableActive && tableHeaderCells.length > 0 && tableDataRows.length > 0) {
|
|
281
|
+
appendBlock(
|
|
282
|
+
React.createElement(BuildTable, {
|
|
283
|
+
key: `table-${blocks.length}`,
|
|
284
|
+
columnHeaders: tableHeaderCells,
|
|
285
|
+
dataRows: tableDataRows,
|
|
286
|
+
maxWidth: terminalWidth
|
|
287
|
+
})
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return React.createElement(React.Fragment, null, blocks);
|
|
138
292
|
}
|
|
139
293
|
|
|
140
294
|
/**
|
|
141
|
-
*
|
|
295
|
+
* 코드 블록 렌더링 컴포넌트
|
|
142
296
|
*/
|
|
143
|
-
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
let partKey = 0;
|
|
147
|
-
|
|
148
|
-
// 모든 마크다운 패턴 찾기 (정규식 재생성하여 lastIndex 문제 방지)
|
|
149
|
-
const patterns = [];
|
|
150
|
-
|
|
151
|
-
// **bold** 패턴 찾기
|
|
152
|
-
let boldRegex = /\*\*([^*]+)\*\*/g;
|
|
153
|
-
let match;
|
|
154
|
-
while ((match = boldRegex.exec(text)) !== null) {
|
|
155
|
-
patterns.push({
|
|
156
|
-
type: 'bold',
|
|
157
|
-
start: match.index,
|
|
158
|
-
end: match.index + match[0].length,
|
|
159
|
-
content: match[1]
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
// `code` 패턴 찾기
|
|
164
|
-
let codeRegex = /`([^`]+)`/g;
|
|
165
|
-
while ((match = codeRegex.exec(text)) !== null) {
|
|
166
|
-
patterns.push({
|
|
167
|
-
type: 'code',
|
|
168
|
-
start: match.index,
|
|
169
|
-
end: match.index + match[0].length,
|
|
170
|
-
content: match[1]
|
|
171
|
-
});
|
|
172
|
-
}
|
|
297
|
+
const BuildCodeBlockInternal = ({ lines, language, isPending, availableHeight, terminalWidth }) => {
|
|
298
|
+
const MIN_LINES_BEFORE_MSG = 1;
|
|
299
|
+
const RESERVED_LINES = 2;
|
|
173
300
|
|
|
174
|
-
|
|
175
|
-
|
|
301
|
+
if (isPending && availableHeight !== undefined) {
|
|
302
|
+
const maxLines = Math.max(0, availableHeight - RESERVED_LINES);
|
|
176
303
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
lastEnd = pattern.end;
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// 패턴 적용
|
|
188
|
-
for (const pattern of filteredPatterns) {
|
|
189
|
-
// 이전 텍스트 추가
|
|
190
|
-
if (currentIndex < pattern.start) {
|
|
191
|
-
const plainText = text.slice(currentIndex, pattern.start);
|
|
192
|
-
if (plainText) {
|
|
193
|
-
parts.push(
|
|
194
|
-
React.createElement(Text, { key: `text-${partKey++}` }, plainText)
|
|
304
|
+
if (lines.length > maxLines) {
|
|
305
|
+
if (maxLines < MIN_LINES_BEFORE_MSG) {
|
|
306
|
+
return React.createElement(Box, { paddingLeft: SPACING.CODE_PADDING },
|
|
307
|
+
React.createElement(Text, { color: theme.text.secondary },
|
|
308
|
+
'... code is being written ...'
|
|
309
|
+
)
|
|
195
310
|
);
|
|
196
311
|
}
|
|
197
|
-
}
|
|
198
312
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
parts.push(
|
|
202
|
-
React.createElement(Text, {
|
|
203
|
-
key: `bold-${partKey++}`,
|
|
204
|
-
bold: true,
|
|
205
|
-
color: theme.text.primary
|
|
206
|
-
}, pattern.content)
|
|
207
|
-
);
|
|
208
|
-
} else if (pattern.type === 'code') {
|
|
209
|
-
parts.push(
|
|
210
|
-
React.createElement(Text, {
|
|
211
|
-
key: `code-${partKey++}`,
|
|
212
|
-
color: theme.status.warning
|
|
213
|
-
}, pattern.content)
|
|
214
|
-
);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
currentIndex = pattern.end;
|
|
218
|
-
}
|
|
313
|
+
const truncatedLines = lines.slice(0, maxLines);
|
|
314
|
+
const truncatedCode = colorizeCode(truncatedLines.join('\n'), language, true);
|
|
219
315
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
React.createElement(Text, {
|
|
316
|
+
return React.createElement(Box, {
|
|
317
|
+
paddingLeft: SPACING.CODE_PADDING,
|
|
318
|
+
flexDirection: 'column'
|
|
319
|
+
},
|
|
320
|
+
truncatedCode,
|
|
321
|
+
React.createElement(Text, { color: theme.text.secondary },
|
|
322
|
+
'... generating more ...'
|
|
323
|
+
)
|
|
226
324
|
);
|
|
227
325
|
}
|
|
228
326
|
}
|
|
229
327
|
|
|
230
|
-
|
|
231
|
-
|
|
328
|
+
const fullCode = lines.join('\n');
|
|
329
|
+
const highlightedCode = colorizeCode(fullCode, language, true);
|
|
330
|
+
|
|
331
|
+
return React.createElement(Box, {
|
|
332
|
+
paddingLeft: SPACING.CODE_PADDING,
|
|
333
|
+
flexDirection: 'column',
|
|
334
|
+
width: terminalWidth,
|
|
335
|
+
flexShrink: 0
|
|
336
|
+
}, highlightedCode);
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
const BuildCodeBlock = React.memo(BuildCodeBlockInternal);
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* 리스트 항목 렌더링 컴포넌트
|
|
343
|
+
*/
|
|
344
|
+
const BuildListItemInternal = ({ itemText, listType, marker, indentation = '' }) => {
|
|
345
|
+
const displayPrefix = listType === 'ol' ? `${marker}. ` : `${marker} `;
|
|
346
|
+
const prefixLength = displayPrefix.length;
|
|
347
|
+
const indentAmount = indentation.length;
|
|
348
|
+
|
|
349
|
+
return React.createElement(Box, {
|
|
350
|
+
paddingLeft: indentAmount + SPACING.LIST_PREFIX_PAD,
|
|
351
|
+
flexDirection: 'row'
|
|
352
|
+
},
|
|
353
|
+
React.createElement(Box, { width: prefixLength },
|
|
354
|
+
React.createElement(Text, { color: theme.text.primary }, displayPrefix)
|
|
355
|
+
),
|
|
356
|
+
React.createElement(Box, { flexGrow: SPACING.LIST_TEXT_GROW },
|
|
357
|
+
React.createElement(Text, { wrap: 'wrap', color: theme.text.primary },
|
|
358
|
+
React.createElement(ProcessInlineText, { content: itemText })
|
|
359
|
+
)
|
|
360
|
+
)
|
|
361
|
+
);
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
const BuildListItem = React.memo(BuildListItemInternal);
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* 테이블 렌더링 컴포넌트
|
|
368
|
+
*/
|
|
369
|
+
const BuildTableInternal = ({ columnHeaders, dataRows, maxWidth }) => {
|
|
370
|
+
return React.createElement(GridRenderer, {
|
|
371
|
+
columnHeaders,
|
|
372
|
+
dataRows,
|
|
373
|
+
maxWidth
|
|
374
|
+
});
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
const BuildTable = React.memo(BuildTableInternal);
|
package/src/system/ai_request.js
CHANGED
|
@@ -209,7 +209,20 @@ export async function request(taskName, requestPayload) {
|
|
|
209
209
|
if (type !== 'function_call_output') continue;
|
|
210
210
|
const parsedOutput = JSON.parse(output);
|
|
211
211
|
if (!isValidJSON(parsedOutput.stdout)) {
|
|
212
|
-
|
|
212
|
+
// stdout와 stderr를 모두 포함하는 형식으로 변환
|
|
213
|
+
const hasStdout = parsedOutput.stdout;
|
|
214
|
+
const hasStderr = parsedOutput.stderr;
|
|
215
|
+
|
|
216
|
+
if (hasStdout && hasStderr) {
|
|
217
|
+
// 둘 다 있으면 레이블 포함
|
|
218
|
+
msg.output = `stdout:\n${parsedOutput.stdout}\n\nstderr:\n${parsedOutput.stderr}`;
|
|
219
|
+
} else if (hasStderr) {
|
|
220
|
+
// stderr만 있으면 레이블 포함
|
|
221
|
+
msg.output = `stderr:\n${parsedOutput.stderr}`;
|
|
222
|
+
} else {
|
|
223
|
+
// stdout만 있으면 레이블 없이
|
|
224
|
+
msg.output = parsedOutput.stdout;
|
|
225
|
+
}
|
|
213
226
|
} else {
|
|
214
227
|
parsedOutput.stdout = JSON.parse(parsedOutput.stdout);
|
|
215
228
|
if (parsedOutput.original_result) {
|
|
File without changes
|
|
File without changes
|
|
File without changes
|