aiexecode 1.0.55 → 1.0.56
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/src/system/session_memory.js +7 -9
- package/src/ui/components/HistoryItemDisplay.js +3 -4
- package/src/util/debug_log.js +4 -13
- package/src/util/safe_fs.js +144 -80
- /package/payload_viewer/out/_next/static/{1q-nLEOdA4y8ThYWX4-Jg → h5BNZL0hrewfv11rqfUcZ}/_buildManifest.js +0 -0
- /package/payload_viewer/out/_next/static/{1q-nLEOdA4y8ThYWX4-Jg → h5BNZL0hrewfv11rqfUcZ}/_clientMiddlewareManifest.json +0 -0
- /package/payload_viewer/out/_next/static/{1q-nLEOdA4y8ThYWX4-Jg → h5BNZL0hrewfv11rqfUcZ}/_ssgManifest.js +0 -0
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><!--
|
|
1
|
+
<!DOCTYPE html><!--h5BNZL0hrewfv11rqfUcZ--><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\":\"h5BNZL0hrewfv11rqfUcZ\",\"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><!--h5BNZL0hrewfv11rqfUcZ--><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\":\"h5BNZL0hrewfv11rqfUcZ\",\"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><!--1q_nLEOdA4y8ThYWX4_Jg--><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\":\"1q-nLEOdA4y8ThYWX4-Jg\",\"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><!--h5BNZL0hrewfv11rqfUcZ--><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\":\"h5BNZL0hrewfv11rqfUcZ\",\"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":"h5BNZL0hrewfv11rqfUcZ","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"}]]
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// 세션별 실행 기록을 파일로 저장하고 로드하는 모듈
|
|
2
|
-
import { safeReadFile, safeWriteFile,
|
|
2
|
+
import { safeReadFile, safeWriteFile, safeExists, safeMkdir, safeUnlink } from '../util/safe_fs.js';
|
|
3
3
|
import { join, resolve } from 'path';
|
|
4
4
|
import chalk from 'chalk';
|
|
5
5
|
import { formatToolCall, formatToolResult, getToolDisplayName, getToolDisplayConfig } from './tool_registry.js';
|
|
@@ -22,9 +22,8 @@ function getHistoryFile(sessionID) {
|
|
|
22
22
|
// 디렉토리 생성 확인
|
|
23
23
|
async function ensureHistoryDir(sessionID) {
|
|
24
24
|
const sessionDir = getSessionDir(sessionID);
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
25
|
+
// recursive: true 이므로 이미 존재해도 에러 없음
|
|
26
|
+
await safeMkdir(sessionDir, { recursive: true });
|
|
28
27
|
}
|
|
29
28
|
|
|
30
29
|
function consolelog() { }
|
|
@@ -37,9 +36,8 @@ function consolelog() { }
|
|
|
37
36
|
export async function deleteHistoryFile(sessionID) {
|
|
38
37
|
try {
|
|
39
38
|
const historyFile = getHistoryFile(sessionID);
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
39
|
+
// safeUnlink 내부에서 파일 존재 여부를 체크하므로 중복 체크 불필요
|
|
40
|
+
await safeUnlink(historyFile);
|
|
43
41
|
} catch (err) {
|
|
44
42
|
}
|
|
45
43
|
}
|
|
@@ -53,7 +51,7 @@ export async function loadPreviousSessions(sessionID) {
|
|
|
53
51
|
try {
|
|
54
52
|
await ensureHistoryDir(sessionID);
|
|
55
53
|
const historyFile = getHistoryFile(sessionID);
|
|
56
|
-
if (
|
|
54
|
+
if (await safeExists(historyFile)) {
|
|
57
55
|
const content = await safeReadFile(historyFile, 'utf8');
|
|
58
56
|
const sessions = JSON.parse(content);
|
|
59
57
|
// consolelog(chalk.blue(`📚 Loaded ${sessions.length} previous sessions from history`));
|
|
@@ -81,7 +79,7 @@ export async function saveSessionToHistory(sessionData) {
|
|
|
81
79
|
debugLog(`historyFile: ${historyFile}`);
|
|
82
80
|
|
|
83
81
|
// 파일에서 이전 세션들을 로드 (메모리 누적 방지)
|
|
84
|
-
const previousSessions =
|
|
82
|
+
const previousSessions = (await safeExists(historyFile))
|
|
85
83
|
? JSON.parse(await safeReadFile(historyFile, 'utf8'))
|
|
86
84
|
: [];
|
|
87
85
|
|
|
@@ -11,7 +11,7 @@ import { renderMarkdown } from '../utils/markdownRenderer.js';
|
|
|
11
11
|
import { FileDiffViewer } from './FileDiffViewer.js';
|
|
12
12
|
import { getToolDisplayName, formatToolCall } from '../../system/tool_registry.js';
|
|
13
13
|
import { getFileSnapshot } from '../../system/file_integrity.js';
|
|
14
|
-
import {
|
|
14
|
+
import { safeMkdir, safeAppendFile } from '../../util/safe_fs.js';
|
|
15
15
|
import { resolve, join, dirname } from 'path';
|
|
16
16
|
import { DEBUG_LOG_DIR } from '../../util/config.js';
|
|
17
17
|
import { createHash } from 'crypto';
|
|
@@ -62,9 +62,8 @@ function logOldStringEvidence(evidence) {
|
|
|
62
62
|
// Convert sync operations to async (non-blocking)
|
|
63
63
|
setImmediate(async () => {
|
|
64
64
|
try {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
65
|
+
// 디렉토리가 없으면 생성 (recursive: true 이므로 이미 존재해도 에러 없음)
|
|
66
|
+
await safeMkdir(dir, { recursive: true });
|
|
68
67
|
await safeAppendFile(OLDSTRING_LOG_FILE, logEntry);
|
|
69
68
|
} catch (err) {
|
|
70
69
|
// Ignore logging errors
|
package/src/util/debug_log.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import { DEBUG_LOG_DIR } from './config.js';
|
|
7
7
|
import { join, dirname } from 'path';
|
|
8
|
-
import {
|
|
8
|
+
import { safeMkdir, safeAppendFile } from './safe_fs.js';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* 디버그 로그를 파일에 기록합니다.
|
|
@@ -19,25 +19,16 @@ export function debugLog(logFileName, context, message) {
|
|
|
19
19
|
const LOG_FILE = join(DEBUG_LOG_DIR, logFileName);
|
|
20
20
|
const logDir = dirname(LOG_FILE);
|
|
21
21
|
|
|
22
|
-
if (!safeExistsSync(logDir)) {
|
|
23
|
-
// Note: mkdirSync is replaced with async safeMkdir, but wrapped in setImmediate to avoid blocking
|
|
24
|
-
setImmediate(async () => {
|
|
25
|
-
try {
|
|
26
|
-
await safeMkdir(logDir, { recursive: true });
|
|
27
|
-
} catch (err) {
|
|
28
|
-
// Ignore errors
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
|
|
33
22
|
const timestamp = new Date().toISOString();
|
|
34
23
|
const logMessage = context
|
|
35
24
|
? `[${timestamp}] [${context}] ${message}\n`
|
|
36
25
|
: `[${timestamp}] ${message}\n`;
|
|
37
26
|
|
|
38
|
-
//
|
|
27
|
+
// 디렉토리 생성 및 로그 쓰기를 비동기로 처리
|
|
39
28
|
setImmediate(async () => {
|
|
40
29
|
try {
|
|
30
|
+
// 디렉토리가 없으면 생성 (recursive: true 이므로 이미 존재해도 에러 없음)
|
|
31
|
+
await safeMkdir(logDir, { recursive: true });
|
|
41
32
|
await safeAppendFile(LOG_FILE, logMessage);
|
|
42
33
|
} catch (err) {
|
|
43
34
|
// Ignore logging errors
|
package/src/util/safe_fs.js
CHANGED
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import fs from 'fs/promises';
|
|
9
|
-
import { existsSync } from 'fs';
|
|
10
9
|
import path from 'path';
|
|
11
10
|
import { homedir } from 'os';
|
|
12
11
|
|
|
@@ -16,11 +15,25 @@ const ALLOWED_DIRECTORIES = [
|
|
|
16
15
|
path.join(homedir(), '.aiexe') // ~/.aiexe
|
|
17
16
|
];
|
|
18
17
|
|
|
18
|
+
/**
|
|
19
|
+
* 파일/디렉토리 존재 여부 확인 (비동기)
|
|
20
|
+
* @param {string} filePath - 확인할 경로
|
|
21
|
+
* @returns {Promise<boolean>}
|
|
22
|
+
*/
|
|
23
|
+
async function exists(filePath) {
|
|
24
|
+
try {
|
|
25
|
+
await fs.access(filePath);
|
|
26
|
+
return true;
|
|
27
|
+
} catch {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
19
32
|
async function debugLog(str) {
|
|
20
33
|
const logDir = path.join(homedir(), '.aiexe', 'debuglog');
|
|
21
34
|
const logFile = path.join(logDir, 'safe_fs.log');
|
|
22
35
|
|
|
23
|
-
if (!
|
|
36
|
+
if (!(await exists(logDir))) {
|
|
24
37
|
await fs.mkdir(logDir, { recursive: true }).catch(() => {});
|
|
25
38
|
}
|
|
26
39
|
|
|
@@ -28,6 +41,25 @@ async function debugLog(str) {
|
|
|
28
41
|
}
|
|
29
42
|
|
|
30
43
|
|
|
44
|
+
/**
|
|
45
|
+
* 경로를 절대경로로 변환
|
|
46
|
+
* @param {string} filePath - 변환할 파일 경로
|
|
47
|
+
* @returns {string} 절대 경로
|
|
48
|
+
*/
|
|
49
|
+
function toAbsolutePath(filePath) {
|
|
50
|
+
if (!filePath || typeof filePath !== 'string') {
|
|
51
|
+
return filePath;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// 이미 절대 경로이면 그대로 반환
|
|
55
|
+
if (path.isAbsolute(filePath)) {
|
|
56
|
+
return path.normalize(filePath);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// 상대 경로를 절대 경로로 변환
|
|
60
|
+
return path.resolve(process.cwd(), filePath);
|
|
61
|
+
}
|
|
62
|
+
|
|
31
63
|
/**
|
|
32
64
|
* 경로 유효성 검증
|
|
33
65
|
* @param {string} filePath - 검증할 파일 경로
|
|
@@ -38,11 +70,6 @@ function validatePath(filePath) {
|
|
|
38
70
|
return false;
|
|
39
71
|
}
|
|
40
72
|
|
|
41
|
-
// 절대 경로인지 확인
|
|
42
|
-
if (!path.isAbsolute(filePath)) {
|
|
43
|
-
return false;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
73
|
return true;
|
|
47
74
|
}
|
|
48
75
|
|
|
@@ -79,22 +106,24 @@ function isProtectedPath(filePath) {
|
|
|
79
106
|
* @returns {Promise<void>}
|
|
80
107
|
*/
|
|
81
108
|
export async function safeWriteFile(filePath, content, encoding = 'utf8') {
|
|
82
|
-
|
|
109
|
+
const absolutePath = toAbsolutePath(filePath);
|
|
110
|
+
|
|
111
|
+
if (!validatePath(absolutePath)) {
|
|
83
112
|
const error = `Invalid file path: ${filePath}`;
|
|
84
113
|
await debugLog(`[ERROR] safeWriteFile: ${error}\n`);
|
|
85
114
|
throw new Error(error);
|
|
86
115
|
}
|
|
87
116
|
|
|
88
|
-
if (isProtectedPath(
|
|
89
|
-
const error = `Protected path cannot be modified: ${
|
|
117
|
+
if (isProtectedPath(absolutePath)) {
|
|
118
|
+
const error = `Protected path cannot be modified: ${absolutePath}`;
|
|
90
119
|
await debugLog(`[ERROR] safeWriteFile: ${error}\n`);
|
|
91
120
|
throw new Error(error);
|
|
92
121
|
}
|
|
93
122
|
|
|
94
123
|
try {
|
|
95
|
-
await fs.writeFile(
|
|
124
|
+
await fs.writeFile(absolutePath, content, encoding);
|
|
96
125
|
} catch (error) {
|
|
97
|
-
const errorMsg = `Failed to write file ${
|
|
126
|
+
const errorMsg = `Failed to write file ${absolutePath}: ${error.message}`;
|
|
98
127
|
await debugLog(`[ERROR] safeWriteFile: ${errorMsg}\n`);
|
|
99
128
|
throw new Error(errorMsg);
|
|
100
129
|
}
|
|
@@ -106,26 +135,28 @@ export async function safeWriteFile(filePath, content, encoding = 'utf8') {
|
|
|
106
135
|
* @returns {Promise<void>}
|
|
107
136
|
*/
|
|
108
137
|
export async function safeUnlink(filePath) {
|
|
109
|
-
|
|
138
|
+
const absolutePath = toAbsolutePath(filePath);
|
|
139
|
+
|
|
140
|
+
if (!validatePath(absolutePath)) {
|
|
110
141
|
const error = `Invalid file path: ${filePath}`;
|
|
111
142
|
await debugLog(`[ERROR] safeUnlink: ${error}\n`);
|
|
112
143
|
throw new Error(error);
|
|
113
144
|
}
|
|
114
145
|
|
|
115
|
-
if (isProtectedPath(
|
|
116
|
-
const error = `Protected path cannot be deleted: ${
|
|
146
|
+
if (isProtectedPath(absolutePath)) {
|
|
147
|
+
const error = `Protected path cannot be deleted: ${absolutePath}`;
|
|
117
148
|
await debugLog(`[ERROR] safeUnlink: ${error}\n`);
|
|
118
149
|
throw new Error(error);
|
|
119
150
|
}
|
|
120
151
|
|
|
121
152
|
try {
|
|
122
|
-
if (!
|
|
153
|
+
if (!(await exists(absolutePath))) {
|
|
123
154
|
return; // 파일이 없으면 조용히 반환
|
|
124
155
|
}
|
|
125
156
|
|
|
126
|
-
await fs.unlink(
|
|
157
|
+
await fs.unlink(absolutePath);
|
|
127
158
|
} catch (error) {
|
|
128
|
-
const errorMsg = `Failed to delete file ${
|
|
159
|
+
const errorMsg = `Failed to delete file ${absolutePath}: ${error.message}`;
|
|
129
160
|
await debugLog(`[ERROR] safeUnlink: ${errorMsg}\n`);
|
|
130
161
|
throw new Error(errorMsg);
|
|
131
162
|
}
|
|
@@ -138,28 +169,31 @@ export async function safeUnlink(filePath) {
|
|
|
138
169
|
* @returns {Promise<void>}
|
|
139
170
|
*/
|
|
140
171
|
export async function safeRename(oldPath, newPath) {
|
|
141
|
-
|
|
172
|
+
const absoluteOldPath = toAbsolutePath(oldPath);
|
|
173
|
+
const absoluteNewPath = toAbsolutePath(newPath);
|
|
174
|
+
|
|
175
|
+
if (!validatePath(absoluteOldPath) || !validatePath(absoluteNewPath)) {
|
|
142
176
|
const error = `Invalid file path: ${oldPath} -> ${newPath}`;
|
|
143
177
|
await debugLog(`[ERROR] safeRename: ${error}\n`);
|
|
144
178
|
throw new Error(error);
|
|
145
179
|
}
|
|
146
180
|
|
|
147
|
-
if (isProtectedPath(
|
|
181
|
+
if (isProtectedPath(absoluteOldPath) || isProtectedPath(absoluteNewPath)) {
|
|
148
182
|
const error = `Protected path cannot be modified`;
|
|
149
|
-
await debugLog(`[ERROR] safeRename: ${error} (${
|
|
183
|
+
await debugLog(`[ERROR] safeRename: ${error} (${absoluteOldPath} -> ${absoluteNewPath})\n`);
|
|
150
184
|
throw new Error(error);
|
|
151
185
|
}
|
|
152
186
|
|
|
153
187
|
try {
|
|
154
|
-
if (!
|
|
155
|
-
const
|
|
156
|
-
await debugLog(`[ERROR] safeRename: ${
|
|
157
|
-
throw new Error(
|
|
188
|
+
if (!(await exists(absoluteOldPath))) {
|
|
189
|
+
const errorMsg = `Source file does not exist: ${absoluteOldPath}`;
|
|
190
|
+
await debugLog(`[ERROR] safeRename: ${errorMsg}\n`);
|
|
191
|
+
throw new Error(errorMsg);
|
|
158
192
|
}
|
|
159
193
|
|
|
160
|
-
await fs.rename(
|
|
194
|
+
await fs.rename(absoluteOldPath, absoluteNewPath);
|
|
161
195
|
} catch (error) {
|
|
162
|
-
const errorMsg = `Failed to rename file ${
|
|
196
|
+
const errorMsg = `Failed to rename file ${absoluteOldPath} -> ${absoluteNewPath}: ${error.message}`;
|
|
163
197
|
await debugLog(`[ERROR] safeRename: ${errorMsg}\n`);
|
|
164
198
|
throw new Error(errorMsg);
|
|
165
199
|
}
|
|
@@ -172,28 +206,30 @@ export async function safeRename(oldPath, newPath) {
|
|
|
172
206
|
* @returns {Promise<void>}
|
|
173
207
|
*/
|
|
174
208
|
export async function safeTruncate(filePath, length = 0) {
|
|
175
|
-
|
|
209
|
+
const absolutePath = toAbsolutePath(filePath);
|
|
210
|
+
|
|
211
|
+
if (!validatePath(absolutePath)) {
|
|
176
212
|
const error = `Invalid file path: ${filePath}`;
|
|
177
213
|
await debugLog(`[ERROR] safeTruncate: ${error}\n`);
|
|
178
214
|
throw new Error(error);
|
|
179
215
|
}
|
|
180
216
|
|
|
181
|
-
if (isProtectedPath(
|
|
182
|
-
const error = `Protected path cannot be modified: ${
|
|
217
|
+
if (isProtectedPath(absolutePath)) {
|
|
218
|
+
const error = `Protected path cannot be modified: ${absolutePath}`;
|
|
183
219
|
await debugLog(`[ERROR] safeTruncate: ${error}\n`);
|
|
184
220
|
throw new Error(error);
|
|
185
221
|
}
|
|
186
222
|
|
|
187
223
|
try {
|
|
188
|
-
if (!
|
|
189
|
-
const
|
|
190
|
-
await debugLog(`[ERROR] safeTruncate: ${
|
|
191
|
-
throw new Error(
|
|
224
|
+
if (!(await exists(absolutePath))) {
|
|
225
|
+
const errorMsg = `File does not exist: ${absolutePath}`;
|
|
226
|
+
await debugLog(`[ERROR] safeTruncate: ${errorMsg}\n`);
|
|
227
|
+
throw new Error(errorMsg);
|
|
192
228
|
}
|
|
193
229
|
|
|
194
|
-
await fs.truncate(
|
|
230
|
+
await fs.truncate(absolutePath, length);
|
|
195
231
|
} catch (error) {
|
|
196
|
-
const errorMsg = `Failed to truncate file ${
|
|
232
|
+
const errorMsg = `Failed to truncate file ${absolutePath}: ${error.message}`;
|
|
197
233
|
await debugLog(`[ERROR] safeTruncate: ${errorMsg}\n`);
|
|
198
234
|
throw new Error(errorMsg);
|
|
199
235
|
}
|
|
@@ -207,26 +243,28 @@ export async function safeTruncate(filePath, length = 0) {
|
|
|
207
243
|
* @returns {Promise<void>}
|
|
208
244
|
*/
|
|
209
245
|
export async function safeRmdir(dirPath, options = {}) {
|
|
210
|
-
|
|
246
|
+
const absolutePath = toAbsolutePath(dirPath);
|
|
247
|
+
|
|
248
|
+
if (!validatePath(absolutePath)) {
|
|
211
249
|
const error = `Invalid directory path: ${dirPath}`;
|
|
212
250
|
await debugLog(`[ERROR] safeRmdir: ${error}\n`);
|
|
213
251
|
throw new Error(error);
|
|
214
252
|
}
|
|
215
253
|
|
|
216
|
-
if (isProtectedPath(
|
|
217
|
-
const error = `Protected path cannot be deleted: ${
|
|
254
|
+
if (isProtectedPath(absolutePath)) {
|
|
255
|
+
const error = `Protected path cannot be deleted: ${absolutePath}`;
|
|
218
256
|
await debugLog(`[ERROR] safeRmdir: ${error}\n`);
|
|
219
257
|
throw new Error(error);
|
|
220
258
|
}
|
|
221
259
|
|
|
222
260
|
try {
|
|
223
|
-
if (!
|
|
261
|
+
if (!(await exists(absolutePath))) {
|
|
224
262
|
return; // 디렉토리가 없으면 조용히 반환
|
|
225
263
|
}
|
|
226
264
|
|
|
227
|
-
await fs.rmdir(
|
|
265
|
+
await fs.rmdir(absolutePath, options);
|
|
228
266
|
} catch (error) {
|
|
229
|
-
const errorMsg = `Failed to delete directory ${
|
|
267
|
+
const errorMsg = `Failed to delete directory ${absolutePath}: ${error.message}`;
|
|
230
268
|
await debugLog(`[ERROR] safeRmdir: ${errorMsg}\n`);
|
|
231
269
|
throw new Error(errorMsg);
|
|
232
270
|
}
|
|
@@ -239,26 +277,28 @@ export async function safeRmdir(dirPath, options = {}) {
|
|
|
239
277
|
* @returns {Promise<void>}
|
|
240
278
|
*/
|
|
241
279
|
export async function safeRm(targetPath, options = {}) {
|
|
242
|
-
|
|
280
|
+
const absolutePath = toAbsolutePath(targetPath);
|
|
281
|
+
|
|
282
|
+
if (!validatePath(absolutePath)) {
|
|
243
283
|
const error = `Invalid path: ${targetPath}`;
|
|
244
284
|
await debugLog(`[ERROR] safeRm: ${error}\n`);
|
|
245
285
|
throw new Error(error);
|
|
246
286
|
}
|
|
247
287
|
|
|
248
|
-
if (isProtectedPath(
|
|
249
|
-
const error = `Protected path cannot be deleted: ${
|
|
288
|
+
if (isProtectedPath(absolutePath)) {
|
|
289
|
+
const error = `Protected path cannot be deleted: ${absolutePath}`;
|
|
250
290
|
await debugLog(`[ERROR] safeRm: ${error}\n`);
|
|
251
291
|
throw new Error(error);
|
|
252
292
|
}
|
|
253
293
|
|
|
254
294
|
try {
|
|
255
|
-
if (!
|
|
295
|
+
if (!(await exists(absolutePath))) {
|
|
256
296
|
return; // 경로가 없으면 조용히 반환
|
|
257
297
|
}
|
|
258
298
|
|
|
259
|
-
await fs.rm(
|
|
299
|
+
await fs.rm(absolutePath, { ...options, recursive: true, force: true });
|
|
260
300
|
} catch (error) {
|
|
261
|
-
const errorMsg = `Failed to remove ${
|
|
301
|
+
const errorMsg = `Failed to remove ${absolutePath}: ${error.message}`;
|
|
262
302
|
await debugLog(`[ERROR] safeRm: ${errorMsg}\n`);
|
|
263
303
|
throw new Error(errorMsg);
|
|
264
304
|
}
|
|
@@ -275,22 +315,25 @@ export async function safeRm(targetPath, options = {}) {
|
|
|
275
315
|
* @returns {Promise<string|Buffer>}
|
|
276
316
|
*/
|
|
277
317
|
export async function safeReadFile(filePath, encoding = 'utf8') {
|
|
318
|
+
const absolutePath = toAbsolutePath(filePath);
|
|
319
|
+
|
|
278
320
|
try {
|
|
279
|
-
return await fs.readFile(
|
|
321
|
+
return await fs.readFile(absolutePath, encoding);
|
|
280
322
|
} catch (error) {
|
|
281
|
-
const errorMsg = `Failed to read file ${
|
|
323
|
+
const errorMsg = `Failed to read file ${absolutePath}: ${error.message}`;
|
|
282
324
|
await debugLog(`[ERROR] safeReadFile: ${errorMsg}\n`);
|
|
283
325
|
throw new Error(errorMsg);
|
|
284
326
|
}
|
|
285
327
|
}
|
|
286
328
|
|
|
287
329
|
/**
|
|
288
|
-
* 파일 존재 여부 확인 (
|
|
330
|
+
* 파일 존재 여부 확인 (비동기)
|
|
289
331
|
* @param {string} filePath - 확인할 파일 경로
|
|
290
|
-
* @returns {boolean}
|
|
332
|
+
* @returns {Promise<boolean>}
|
|
291
333
|
*/
|
|
292
|
-
export function
|
|
293
|
-
|
|
334
|
+
export async function safeExists(filePath) {
|
|
335
|
+
const absolutePath = toAbsolutePath(filePath);
|
|
336
|
+
return await exists(absolutePath);
|
|
294
337
|
}
|
|
295
338
|
|
|
296
339
|
/**
|
|
@@ -300,10 +343,12 @@ export function safeExistsSync(filePath) {
|
|
|
300
343
|
* @returns {Promise<string[]>}
|
|
301
344
|
*/
|
|
302
345
|
export async function safeReaddir(dirPath, options = {}) {
|
|
346
|
+
const absolutePath = toAbsolutePath(dirPath);
|
|
347
|
+
|
|
303
348
|
try {
|
|
304
|
-
return await fs.readdir(
|
|
349
|
+
return await fs.readdir(absolutePath, options);
|
|
305
350
|
} catch (error) {
|
|
306
|
-
const errorMsg = `Failed to read directory ${
|
|
351
|
+
const errorMsg = `Failed to read directory ${absolutePath}: ${error.message}`;
|
|
307
352
|
await debugLog(`[ERROR] safeReaddir: ${errorMsg}\n`);
|
|
308
353
|
throw new Error(errorMsg);
|
|
309
354
|
}
|
|
@@ -315,10 +360,12 @@ export async function safeReaddir(dirPath, options = {}) {
|
|
|
315
360
|
* @returns {Promise<import('fs').Stats>}
|
|
316
361
|
*/
|
|
317
362
|
export async function safeStat(targetPath) {
|
|
363
|
+
const absolutePath = toAbsolutePath(targetPath);
|
|
364
|
+
|
|
318
365
|
try {
|
|
319
|
-
return await fs.stat(
|
|
366
|
+
return await fs.stat(absolutePath);
|
|
320
367
|
} catch (error) {
|
|
321
|
-
const errorMsg = `Failed to stat ${
|
|
368
|
+
const errorMsg = `Failed to stat ${absolutePath}: ${error.message}`;
|
|
322
369
|
await debugLog(`[ERROR] safeStat: ${errorMsg}\n`);
|
|
323
370
|
throw new Error(errorMsg);
|
|
324
371
|
}
|
|
@@ -330,10 +377,12 @@ export async function safeStat(targetPath) {
|
|
|
330
377
|
* @returns {Promise<import('fs').Stats>}
|
|
331
378
|
*/
|
|
332
379
|
export async function safeLstat(targetPath) {
|
|
380
|
+
const absolutePath = toAbsolutePath(targetPath);
|
|
381
|
+
|
|
333
382
|
try {
|
|
334
|
-
return await fs.lstat(
|
|
383
|
+
return await fs.lstat(absolutePath);
|
|
335
384
|
} catch (error) {
|
|
336
|
-
const errorMsg = `Failed to lstat ${
|
|
385
|
+
const errorMsg = `Failed to lstat ${absolutePath}: ${error.message}`;
|
|
337
386
|
await debugLog(`[ERROR] safeLstat: ${errorMsg}\n`);
|
|
338
387
|
throw new Error(errorMsg);
|
|
339
388
|
}
|
|
@@ -346,10 +395,12 @@ export async function safeLstat(targetPath) {
|
|
|
346
395
|
* @returns {Promise<void>}
|
|
347
396
|
*/
|
|
348
397
|
export async function safeAccess(filePath, mode) {
|
|
398
|
+
const absolutePath = toAbsolutePath(filePath);
|
|
399
|
+
|
|
349
400
|
try {
|
|
350
|
-
return await fs.access(
|
|
401
|
+
return await fs.access(absolutePath, mode);
|
|
351
402
|
} catch (error) {
|
|
352
|
-
const errorMsg = `Failed to access ${
|
|
403
|
+
const errorMsg = `Failed to access ${absolutePath}: ${error.message}`;
|
|
353
404
|
await debugLog(`[ERROR] safeAccess: ${errorMsg}\n`);
|
|
354
405
|
throw new Error(errorMsg);
|
|
355
406
|
}
|
|
@@ -363,22 +414,28 @@ export async function safeAccess(filePath, mode) {
|
|
|
363
414
|
* @returns {Promise<string|undefined>}
|
|
364
415
|
*/
|
|
365
416
|
export async function safeMkdir(dirPath, options = {}) {
|
|
366
|
-
|
|
417
|
+
const absolutePath = toAbsolutePath(dirPath);
|
|
418
|
+
|
|
419
|
+
if (!validatePath(absolutePath)) {
|
|
367
420
|
const error = `Invalid directory path: ${dirPath}`;
|
|
368
421
|
await debugLog(`[ERROR] safeMkdir: ${error}\n`);
|
|
369
422
|
throw new Error(error);
|
|
370
423
|
}
|
|
371
424
|
|
|
372
|
-
if (isProtectedPath(
|
|
373
|
-
const error = `Protected path cannot be modified: ${
|
|
425
|
+
if (isProtectedPath(absolutePath)) {
|
|
426
|
+
const error = `Protected path cannot be modified: ${absolutePath}`;
|
|
374
427
|
await debugLog(`[ERROR] safeMkdir: ${error}\n`);
|
|
375
428
|
throw new Error(error);
|
|
376
429
|
}
|
|
377
430
|
|
|
378
431
|
try {
|
|
379
|
-
return await fs.mkdir(
|
|
432
|
+
return await fs.mkdir(absolutePath, options);
|
|
380
433
|
} catch (error) {
|
|
381
|
-
|
|
434
|
+
// recursive: true 일 때 이미 존재하는 디렉토리는 에러가 아님
|
|
435
|
+
if (error.code === 'EEXIST' && options.recursive) {
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
const errorMsg = `Failed to create directory ${absolutePath}: ${error.message}`;
|
|
382
439
|
await debugLog(`[ERROR] safeMkdir: ${errorMsg}\n`);
|
|
383
440
|
throw new Error(errorMsg);
|
|
384
441
|
}
|
|
@@ -390,10 +447,12 @@ export async function safeMkdir(dirPath, options = {}) {
|
|
|
390
447
|
* @returns {Promise<string>}
|
|
391
448
|
*/
|
|
392
449
|
export async function safeRealpath(targetPath) {
|
|
450
|
+
const absolutePath = toAbsolutePath(targetPath);
|
|
451
|
+
|
|
393
452
|
try {
|
|
394
|
-
return await fs.realpath(
|
|
453
|
+
return await fs.realpath(absolutePath);
|
|
395
454
|
} catch (error) {
|
|
396
|
-
const errorMsg = `Failed to resolve realpath ${
|
|
455
|
+
const errorMsg = `Failed to resolve realpath ${absolutePath}: ${error.message}`;
|
|
397
456
|
await debugLog(`[ERROR] safeRealpath: ${errorMsg}\n`);
|
|
398
457
|
throw new Error(errorMsg);
|
|
399
458
|
}
|
|
@@ -407,22 +466,25 @@ export async function safeRealpath(targetPath) {
|
|
|
407
466
|
* @returns {Promise<void>}
|
|
408
467
|
*/
|
|
409
468
|
export async function safeCopyFile(src, dest, mode) {
|
|
410
|
-
|
|
411
|
-
|
|
469
|
+
const absoluteSrc = toAbsolutePath(src);
|
|
470
|
+
const absoluteDest = toAbsolutePath(dest);
|
|
471
|
+
|
|
472
|
+
if (!validatePath(absoluteSrc) || !validatePath(absoluteDest)) {
|
|
473
|
+
const error = `Invalid path: ${src} -> ${dest}`;
|
|
412
474
|
await debugLog(`[ERROR] safeCopyFile: ${error}\n`);
|
|
413
475
|
throw new Error(error);
|
|
414
476
|
}
|
|
415
477
|
|
|
416
|
-
if (isProtectedPath(
|
|
417
|
-
const error = `Protected path cannot be modified: ${
|
|
478
|
+
if (isProtectedPath(absoluteDest)) {
|
|
479
|
+
const error = `Protected path cannot be modified: ${absoluteDest}`;
|
|
418
480
|
await debugLog(`[ERROR] safeCopyFile: ${error}\n`);
|
|
419
481
|
throw new Error(error);
|
|
420
482
|
}
|
|
421
483
|
|
|
422
484
|
try {
|
|
423
|
-
return await fs.copyFile(
|
|
485
|
+
return await fs.copyFile(absoluteSrc, absoluteDest, mode);
|
|
424
486
|
} catch (error) {
|
|
425
|
-
const errorMsg = `Failed to copy file ${
|
|
487
|
+
const errorMsg = `Failed to copy file ${absoluteSrc} -> ${absoluteDest}: ${error.message}`;
|
|
426
488
|
await debugLog(`[ERROR] safeCopyFile: ${errorMsg}\n`);
|
|
427
489
|
throw new Error(errorMsg);
|
|
428
490
|
}
|
|
@@ -436,22 +498,24 @@ export async function safeCopyFile(src, dest, mode) {
|
|
|
436
498
|
* @returns {Promise<void>}
|
|
437
499
|
*/
|
|
438
500
|
export async function safeAppendFile(filePath, data, encoding = 'utf8') {
|
|
439
|
-
|
|
501
|
+
const absolutePath = toAbsolutePath(filePath);
|
|
502
|
+
|
|
503
|
+
if (!validatePath(absolutePath)) {
|
|
440
504
|
const error = `Invalid file path: ${filePath}`;
|
|
441
505
|
await debugLog(`[ERROR] safeAppendFile: ${error}\n`);
|
|
442
506
|
throw new Error(error);
|
|
443
507
|
}
|
|
444
508
|
|
|
445
|
-
if (isProtectedPath(
|
|
446
|
-
const error = `Protected path cannot be modified: ${
|
|
509
|
+
if (isProtectedPath(absolutePath)) {
|
|
510
|
+
const error = `Protected path cannot be modified: ${absolutePath}`;
|
|
447
511
|
await debugLog(`[ERROR] safeAppendFile: ${error}\n`);
|
|
448
512
|
throw new Error(error);
|
|
449
513
|
}
|
|
450
514
|
|
|
451
515
|
try {
|
|
452
|
-
return await fs.appendFile(
|
|
516
|
+
return await fs.appendFile(absolutePath, data, encoding);
|
|
453
517
|
} catch (error) {
|
|
454
|
-
const errorMsg = `Failed to append to file ${
|
|
518
|
+
const errorMsg = `Failed to append to file ${absolutePath}: ${error.message}`;
|
|
455
519
|
await debugLog(`[ERROR] safeAppendFile: ${errorMsg}\n`);
|
|
456
520
|
throw new Error(errorMsg);
|
|
457
521
|
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|