From 1ad75b589654e741d87ddc11fcb7b974cc52830f Mon Sep 17 00:00:00 2001 From: lacvet Date: Mon, 6 Apr 2026 16:09:00 +0900 Subject: [PATCH] =?UTF-8?q?=EB=B0=B0=ED=8F=AC=ED=8C=90=20=EB=B3=B4?= =?UTF-8?q?=ED=98=B8=20=EC=88=98=EC=A4=80=20=EA=B0=95=ED=99=94=20=EB=B0=8F?= =?UTF-8?q?=20single-file=20=ED=98=B8=ED=99=98=20=EB=B3=B4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 배포 스크립트와 앱 Release 설정에 single-file, ReadyToRun, 압축 번들, 최적화 옵션을 추가해 릴리즈 배포 출력의 보호 수준을 한 단계 높였습니다. WebSearchHandler와 SettingsWindow는 single-file 환경에서 Assembly.Location 경고가 발생하지 않도록 AppContext.BaseDirectory 및 AssemblyInformationalVersionAttribute 기반으로 수정했습니다. README와 DEVELOPMENT 문서를 갱신했고, dotnet build 검증에서 경고 0 오류 0을 다시 확인했습니다. --- README.md | 7 + build.bat | 235 +++++++++++++++------ docs/DEVELOPMENT.md | 4 + src/AxCopilot/AxCopilot.csproj | 6 + src/AxCopilot/Handlers/WebSearchHandler.cs | 2 +- src/AxCopilot/Views/SettingsWindow.xaml.cs | 8 +- 6 files changed, 195 insertions(+), 67 deletions(-) diff --git a/README.md b/README.md index 5e5965e..0734890 100644 --- a/README.md +++ b/README.md @@ -1266,3 +1266,10 @@ MIT License - 코워크 문서 생성이 항상 비슷한 HTML로 수렴하던 원인을 줄이기 위해 [DocumentPlannerTool.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/Agent/DocumentPlannerTool.cs), [DocumentAssemblerTool.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/Agent/DocumentAssemblerTool.cs)의 기본 포맷/무드 선택 로직을 재정리했다. - 이제 인자 없이 문서 생성 도구를 호출해도 무조건 `html + professional`로 고정되지 않고, `DefaultOutputFormat`, `DefaultMood`, 문서 유형(`proposal`, `analysis`, `manual`, `minutes` 등), 요청 주제 키워드를 함께 보고 `docx/html/markdown` 및 `corporate/dashboard/minimal/creative/professional`을 자동 선택한다. - 이 변경으로 AX의 문서 생성 체인이 `claw-code`처럼 요청 기반 자유 작성 흐름에 더 가까워졌고, 코워크 결과물이 항상 비슷한 보고서형 HTML로 반복되던 현상을 줄일 기반을 마련했다. +- 업데이트: 2026-04-06 16:14 (KST) + - 배포판 보호 수준을 점검한 뒤 [AxCopilot.csproj](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/AxCopilot.csproj) Release 설정에 `Optimize`, `PublishSingleFile`, `EnableCompressionInSingleFile`, `IncludeNativeLibrariesForSelfExtract`, `PublishReadyToRun`을 추가했다. + - [build.bat](/E:/AX%20Copilot%20-%20Codex/build.bat) 도 같은 publish 속성을 명시적으로 넘기도록 갱신해, 배치 파일로 배포판을 만들 때 실제로 `Release + self-contained + single-file + ReadyToRun` 조합이 적용되도록 맞췄다. + - 현재 저장소에는 외부 난독화기(`tools\\obfuscator`)가 없어서 완전한 디컴파일 방지는 아니지만, 심볼 제거 수준에서 한 단계 더 강화된 배포 출력이 나오도록 정리했다. +- 업데이트: 2026-04-06 16:20 (KST) + - single-file 배포를 켜면서 생긴 호환 경고도 함께 정리했다. [WebSearchHandler.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Handlers/WebSearchHandler.cs)는 `Assembly.Location` 대신 `AppContext.BaseDirectory`를 사용하게 바꿨고, [SettingsWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/SettingsWindow.xaml.cs)는 버전 표시를 `AssemblyInformationalVersionAttribute` 기준으로 읽도록 수정했다. + - 이 수정까지 반영한 뒤 `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify\\ -p:IntermediateOutputPath=obj\\verify\\` 기준 경고 0 / 오류 0을 다시 확인했다. diff --git a/build.bat b/build.bat index 5d45109..e0ddc32 100644 --- a/build.bat +++ b/build.bat @@ -1,90 +1,199 @@ @echo off +setlocal EnableExtensions chcp 65001 >nul + +set "ROOT=%~dp0" +pushd "%ROOT%" >nul + echo. echo ======================================== echo AX Copilot - Build Script echo ======================================== echo. -set APP=src\AxCopilot\AxCopilot.csproj -set ENCRYPTOR=src\AxKeyEncryptor\AxKeyEncryptor.csproj -set OFFLINE=src\AxCopilot.Installer\AxCopilot.Installer.csproj -set OUT=dist +set "APP=%ROOT%src\AxCopilot\AxCopilot.csproj" +set "ENCRYPTOR=%ROOT%src\AxKeyEncryptor\AxKeyEncryptor.csproj" +set "INSTALLER=%ROOT%src\AxCopilot.Installer\AxCopilot.Installer.csproj" +set "INSTALLER_DIR=%ROOT%src\AxCopilot.Installer" +set "OUT=%ROOT%dist" +set "APP_OUT=%OUT%\AxCopilot" +set "ENCRYPTOR_OUT=%OUT%\AxKeyEncryptor" +set "PAYLOAD_ZIP=%INSTALLER_DIR%\payload.zip" +set "INSTALLER_EXE=%INSTALLER_DIR%\bin\Release\net48\AxCopilot_Setup.exe" +set "RUNTIME=win-x64" +set "OBFUSCATOR_EXE=%ROOT%tools\obfuscator\obfuscator.exe" +set "OBFUSCATOR_CONFIG=%ROOT%tools\obfuscator\AxCopilot.obfuscation.xml" -:: Kill running app -tasklist /FI "IMAGENAME eq AxCopilot.exe" 2>nul | find /i "AxCopilot.exe" >nul -if %ERRORLEVEL%==0 ( - echo [0] Stopping AxCopilot... - taskkill /IM AxCopilot.exe /F >nul 2>nul - timeout /t 2 /nobreak >nul -) -:: Kill legacy process -tasklist /FI "IMAGENAME eq AxCommander.exe" 2>nul | find /i "AxCommander.exe" >nul -if %ERRORLEVEL%==0 ( - echo [0] Stopping legacy AxCommander... - taskkill /IM AxCommander.exe /F >nul 2>nul - timeout /t 2 /nobreak >nul -) +call :stop_process "AxCopilot" "AX Copilot" +if errorlevel 1 goto :fail_running +call :stop_process "AxCommander" "legacy AxCommander" +if errorlevel 1 goto :fail_running if exist "%OUT%" rd /s /q "%OUT%" 2>nul -mkdir "%OUT%" -mkdir "%OUT%\AxCopilot" +mkdir "%OUT%" || goto :fail_dist +mkdir "%APP_OUT%" || goto :fail_dist +mkdir "%ENCRYPTOR_OUT%" || goto :fail_dist -:: ======================================== -:: 1. Main app (self-contained, folder) -:: ======================================== -echo [1/4] Building main app (self-contained)... -dotnet publish "%APP%" -c Release -o "%OUT%\AxCopilot" --self-contained true --nologo -v quiet -if %ERRORLEVEL% NEQ 0 ( echo [FAILED] Main app build & pause & exit /b 1 ) -echo OK - dist\AxCopilot\ +if exist "%PAYLOAD_ZIP%" del /q "%PAYLOAD_ZIP%" 2>nul + +echo [1/5] Building main app (self-contained %RUNTIME%)... +dotnet publish "%APP%" ^ + -c Release ^ + -r %RUNTIME% ^ + --self-contained true ^ + -o "%APP_OUT%" ^ + --nologo ^ + -v minimal ^ + -p:DebugType=None ^ + -p:DebugSymbols=false ^ + -p:CopyOutputSymbolsToPublishDirectory=false ^ + -p:EnableSourceLink=false ^ + -p:PublishSingleFile=true ^ + -p:EnableCompressionInSingleFile=true ^ + -p:IncludeNativeLibrariesForSelfExtract=true ^ + -p:PublishReadyToRun=true +if errorlevel 1 goto :fail_app +echo OK - %APP_OUT% echo. -:: ======================================== -:: 2. AxKeyEncryptor (developer tool) -:: ======================================== -echo [2/4] Building AxKeyEncryptor (WinForms)... -mkdir "%OUT%\AxKeyEncryptor" 2>nul -dotnet publish "%ENCRYPTOR%" -c Release -o "%OUT%\AxKeyEncryptor" --self-contained false --nologo -v quiet -if %ERRORLEVEL% NEQ 0 ( echo [FAILED] AxKeyEncryptor build & pause & exit /b 1 ) -del /q "%OUT%\AxKeyEncryptor\*.pdb" 2>nul -echo OK - dist\AxKeyEncryptor\ +echo [2/5] Checking obfuscation / anti-decompile status... +if exist "%OBFUSCATOR_EXE%" ( +if exist "%OBFUSCATOR_CONFIG%" ( + echo Optional obfuscator found. + echo Running: "%OBFUSCATOR_EXE%" + "%OBFUSCATOR_EXE%" "%OBFUSCATOR_CONFIG%" "%APP_OUT%" + if errorlevel 1 goto :fail_obfuscation + echo OK - obfuscation step completed +) else ( + echo WARNING - no external obfuscator configured. + echo Current protection is limited to symbol/source metadata removal only. +) +) else ( + echo WARNING - no external obfuscator configured. + echo Current protection is limited to symbol/source metadata removal only. +) echo. -:: ======================================== -:: 3. Create payload ZIP for installer -:: ======================================== -echo [3/4] Creating installer payload ZIP... -powershell -NoProfile -Command "Compress-Archive -Path '%OUT%\AxCopilot\*' -DestinationPath 'src\AxCopilot.Installer\payload.zip' -Force" -echo OK - payload.zip +echo [3/5] Building AxKeyEncryptor... +dotnet publish "%ENCRYPTOR%" ^ + -c Release ^ + -o "%ENCRYPTOR_OUT%" ^ + --self-contained false ^ + --nologo ^ + -v minimal ^ + -p:DebugType=None ^ + -p:DebugSymbols=false +if errorlevel 1 goto :fail_encryptor +echo OK - %ENCRYPTOR_OUT% echo. -:: ======================================== -:: 4. Build installer (.NET Framework 4.8) -:: ======================================== -echo [4/4] Building installer (.NET Framework 4.8)... -dotnet build "%OFFLINE%" -c Release --nologo -v quiet -if %ERRORLEVEL% NEQ 0 ( echo [FAILED] Installer build & pause & exit /b 1 ) -copy /Y "src\AxCopilot.Installer\bin\Release\net48\AxCopilot_Setup.exe" "%OUT%\" >nul +echo [4/5] Creating installer payload ZIP... +powershell -NoProfile -Command "Compress-Archive -Path '%APP_OUT%\*' -DestinationPath '%PAYLOAD_ZIP%' -Force" +if errorlevel 1 goto :fail_payload +if not exist "%PAYLOAD_ZIP%" goto :fail_payload +echo OK - %PAYLOAD_ZIP% +echo. + +echo [5/5] Building installer (.NET Framework 4.8)... +dotnet build "%INSTALLER%" -c Release --nologo -v minimal +if errorlevel 1 goto :fail_installer +if not exist "%INSTALLER_EXE%" goto :fail_installer_copy +copy /Y "%INSTALLER_EXE%" "%OUT%\" >nul +if errorlevel 1 goto :fail_installer_copy for %%F in ("%OUT%\AxCopilot_Setup.exe") do echo OK - AxCopilot_Setup.exe (%%~zF bytes) echo. -:: ======================================== -:: Cleanup -:: ======================================== -:: Remove debug symbols and metadata (anti-decompile) -del /q "%OUT%\*.pdb" 2>nul -del /q "%OUT%\AxCopilot\*.pdb" 2>nul -del /q "%OUT%\AxCopilot\*.xml" 2>nul -del /q "%OUT%\*.deps.json" 2>nul -del /q "%OUT%\*.runtimeconfig.json" 2>nul -del /q "src\AxCopilot.Installer\payload.zip" 2>nul +echo [Cleanup] Removing debug and metadata files from dist... +call :clean_publish_artifacts "%OUT%" +call :clean_publish_artifacts "%APP_OUT%" +call :clean_publish_artifacts "%ENCRYPTOR_OUT%" +if exist "%PAYLOAD_ZIP%" del /q "%PAYLOAD_ZIP%" 2>nul +echo OK - cleaned +echo. echo ======================================== echo Build Complete! echo ======================================== echo. -echo dist\AxCopilot\ Main app (EXE + DLL) -echo dist\AxKeyEncryptor\ Settings Encryptor (dev tool) -echo dist\AxCopilot_Setup.exe Installer (offline, .NET 4.8) +echo %APP_OUT% Main app +echo %ENCRYPTOR_OUT% Settings Encryptor +echo %OUT%\AxCopilot_Setup.exe Installer echo. -pause +echo Note: +echo - Release/self-contained single-file publish applied +echo - ReadyToRun + compressed single-file bundle enabled +echo - PDB/XML/debug metadata removed from dist output +echo - External obfuscator is only applied when tools\obfuscator is configured +echo. +popd >nul +exit /b 0 + +:stop_process +set "PROC_NAME=%~1" +set "DISPLAY_NAME=%~2" +powershell -NoProfile -ExecutionPolicy Bypass -Command ^ + "$name='%PROC_NAME%';" ^ + "$display='%DISPLAY_NAME%';" ^ + "$procs = Get-Process -Name $name -ErrorAction SilentlyContinue;" ^ + "if (-not $procs) { exit 0 }" ^ + "Write-Host ('[0] Stopping ' + $display + '...');" ^ + "$imageName = $name + '.exe';" ^ + "foreach ($proc in $procs) {" ^ + " try { if ($proc.MainWindowHandle -ne 0) { [void]$proc.CloseMainWindow() } } catch { }" ^ + "}" ^ + "Start-Sleep -Seconds 2;" ^ + "& taskkill /IM $imageName /T /F > $null 2> $null;" ^ + "Start-Sleep -Seconds 2;" ^ + "$stillRunning = Get-Process -Name $name -ErrorAction SilentlyContinue;" ^ + "if ($stillRunning) {" ^ + " Write-Host ('[FAILED] Could not stop ' + $display + '. Access may be denied or the app may be running with higher privileges.') -ForegroundColor Red;" ^ + " exit 1" ^ + "}" ^ + "exit 0" +if errorlevel 1 exit /b 1 +exit /b 0 + +:clean_publish_artifacts +if not exist "%~1" exit /b 0 +del /q "%~1\*.pdb" 2>nul +del /q "%~1\*.xml" 2>nul +del /q "%~1\*.deps.json" 2>nul +del /q "%~1\*.runtimeconfig.json" 2>nul +exit /b 0 + +:fail_dist +echo [FAILED] dist ??€????밴쉐 ??쎈솭 +goto :end_fail + +:fail_app +echo [FAILED] main app publish ??쎈솭 +goto :end_fail + +:fail_obfuscation +echo [FAILED] obfuscation ??m€???쎈솭 +goto :end_fail + +:fail_encryptor +echo [FAILED] AxKeyEncryptor publish ??쎈솭 +goto :end_fail + +:fail_payload +echo [FAILED] payload.zip ??밴쉐 ??쎈솭 +goto :end_fail + +:fail_installer +echo [FAILED] installer build ??쎈솭 +goto :end_fail + +:fail_installer_copy +echo [FAILED] installer exe 癰귣벊沅???쎈솭 +goto :end_fail + +:fail_running +echo [FAILED] running AX Copilot process could not be stopped cleanly +goto :end_fail + +:end_fail +if exist "%PAYLOAD_ZIP%" del /q "%PAYLOAD_ZIP%" 2>nul +popd >nul +exit /b 1 diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md index 13f5c47..111449c 100644 --- a/docs/DEVELOPMENT.md +++ b/docs/DEVELOPMENT.md @@ -4969,3 +4969,7 @@ ow + toggle ?쒓컖 ?몄뼱濡??ㅼ떆 ?뺣젹?덈떎. - Document update: 2026-04-06 15:48 (KST) - The countdown bar still updates through `DispatcherTimer`, but the actual close action is now guaranteed by the background delay path. This reduces cases where encouragement popups remain visible after the configured display duration. - Document update: 2026-04-06 16:02 (KST) - Relaxed AX Cowork document-generation defaults so the planner/assembler path no longer collapses to `html + professional` whenever explicit arguments are omitted. `DocumentPlannerTool.cs` now resolves output format and mood from `Llm.DefaultOutputFormat`, `Llm.DefaultMood`, document type, and request keywords instead of hardcoding HTML/professional defaults. - Document update: 2026-04-06 16:02 (KST) - `DocumentAssemblerTool.cs` now mirrors that resolution logic at assembly time, supporting `auto` as a first-class format input and inferring `docx/html/markdown` plus `corporate/dashboard/minimal/creative/professional` mood variants from title/section intent. This reduces repetitive HTML-style outputs and brings AX closer to the more request-driven document flow seen in `claw-code`. +- Document update: 2026-04-06 16:14 (KST) - Strengthened the default deployment hardening profile in `AxCopilot.csproj` Release settings by enabling `Optimize`, `PublishSingleFile`, `EnableCompressionInSingleFile`, `IncludeNativeLibrariesForSelfExtract`, and `PublishReadyToRun`. +- Document update: 2026-04-06 16:14 (KST) - Updated `build.bat` to pass the same publish properties explicitly, so installer/distribution builds made through the batch script now run as Release self-contained single-file ReadyToRun publishes by default. There is still no external obfuscator in the repo, so protection is improved but not equivalent to full obfuscation. +- Document update: 2026-04-06 16:20 (KST) - Fixed single-file compatibility warnings introduced by the hardened publish profile. `WebSearchHandler.cs` now uses `AppContext.BaseDirectory` instead of `Assembly.Location` for bundled asset lookup, and `SettingsWindow.xaml.cs` now reads the displayed version from `AssemblyInformationalVersionAttribute` rather than `FileVersionInfo.GetVersionInfo(asm.Location)`. +- Document update: 2026-04-06 16:20 (KST) - Re-ran the standard verification build after those fixes and restored the zero-warning requirement: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\verify\ -p:IntermediateOutputPath=obj\verify\` now completes with 0 warnings and 0 errors. diff --git a/src/AxCopilot/AxCopilot.csproj b/src/AxCopilot/AxCopilot.csproj index 179d5d2..d636b77 100644 --- a/src/AxCopilot/AxCopilot.csproj +++ b/src/AxCopilot/AxCopilot.csproj @@ -40,10 +40,16 @@ + true false false + + true + true + true + true