diff --git a/public/run-mac.sh b/public/run-mac.sh index 056e4ef..641d263 100644 --- a/public/run-mac.sh +++ b/public/run-mac.sh @@ -6,7 +6,10 @@ if [ -z "${DEV_SETUP_SCRIPT_B64:-}" ]; then exit 1 fi -tmp="${TMPDIR:-/tmp}/dev-setup-builder-$$.command" +tmp="$(mktemp "${TMPDIR:-/tmp}/dev-setup-builder.XXXXXX")" +cleanup() { rm -f "$tmp"; } +trap cleanup EXIT + if ! printf "%s" "$DEV_SETUP_SCRIPT_B64" | base64 -D > "$tmp" 2>/dev/null; then printf "%s" "$DEV_SETUP_SCRIPT_B64" | base64 --decode > "$tmp" fi diff --git a/public/run-windows.ps1 b/public/run-windows.ps1 index cfe2f82..907ec42 100644 --- a/public/run-windows.ps1 +++ b/public/run-windows.ps1 @@ -4,9 +4,16 @@ if (-not $env:DEV_SETUP_SCRIPT_B64) { throw 'DEV_SETUP_SCRIPT_B64 is missing.' } -$path = Join-Path $env:TEMP "dev-setup-builder-$PID.bat" -$bytes = [Convert]::FromBase64String($env:DEV_SETUP_SCRIPT_B64) -[IO.File]::WriteAllBytes($path, $bytes) +$path = Join-Path $env:TEMP ("dev-setup-builder-{0}.bat" -f [Guid]::NewGuid().ToString('N')) +try { + $bytes = [Convert]::FromBase64String($env:DEV_SETUP_SCRIPT_B64) + [IO.File]::WriteAllBytes($path, $bytes) -cmd.exe /c $path -exit $LASTEXITCODE + cmd.exe /c $path + $exitCode = $LASTEXITCODE +} +finally { + Remove-Item -LiteralPath $path -Force -ErrorAction SilentlyContinue +} + +exit $exitCode diff --git a/src/App.jsx b/src/App.jsx index 36b265e..d1dfdc6 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -105,7 +105,7 @@ const RAW_BODY_OPTIONS = [ const STATUS_TEXT = { ready: "준비됨", - noTools: "선택된 도구 없음", + noTools: "도구를 하나 이상 선택하세요.", copied: "복사 완료", copyFailed: "복사 실패" }; @@ -140,7 +140,7 @@ const PACKAGE_TEXT = { gh: { note: "GitHub 작업용 gh 명령을 설치합니다." }, "github-auth": { label: "GitHub CLI 로그인", note: "GitHub CLI 로그인 상태를 확인하고 필요한 명령을 안내합니다." }, glab: { note: "GitLab 작업용 glab 명령을 설치합니다." }, - "git-config": { label: "Git 사용자 정보 기본값", note: "Git 이름과 이메일이 없을 때만 기본값을 설정합니다." } + "git-config": { label: "Git 사용자 정보 기본값", note: "Git 정보가 없을 때 Claude Code / noreply@anthropic.com을 사용합니다." } }; const PACKAGE_ICONS = { @@ -169,9 +169,7 @@ const PACKAGE_ICONS = { const ADVANCED_PACKAGE_IDS = new Set(["claude-code-telemetry", "codex-telemetry"]); const PACKAGE_IDS = new Set(PACKAGES.map((item) => item.id)); -// Keep secrets (the OTLP header value is typically an API token) out of the shareable URL. -const URL_SECRET_KEYS = new Set(["otelHeaderValue"]); -const URL_SETTING_KEYS = Object.keys(DEFAULT_SETTINGS).filter((key) => !URL_SECRET_KEYS.has(key)); +const URL_SETTING_KEYS = Object.keys(DEFAULT_SETTINGS); const PERMISSION_HELP = { mac: [ @@ -390,6 +388,8 @@ function App() { const tools = visibleResolved(resolved); const currentFileName = fileName(os); const showTelemetryDefaults = resolved.has("claude-code-telemetry") || resolved.has("codex-telemetry"); + const outputBlockReason = tools.length === 0 ? STATUS_TEXT.noTools : ""; + const canExport = !outputBlockReason; useEffect(() => { window.history.replaceState(null, "", `${window.location.pathname}?${urlSearch(os, selected, settings)}`); @@ -533,6 +533,7 @@ function App() { } async function copyCurrentScript() { + if (!canExport) return; await copyText(script, STATUS_TEXT.copied, "copy"); } @@ -556,6 +557,7 @@ function App() { } function downloadCurrentScript() { + if (!canExport) return; const blob = new Blob([script], { type: "text/plain;charset=utf-8" }); const url = URL.createObjectURL(blob); const link = document.createElement("a"); @@ -586,6 +588,7 @@ function App() { label={lastAction === "copy" ? "복사됨" : "복사"} icon={lastAction === "copy" ? : } onClick={copyCurrentScript} + isDisabled={!canExport} variant="secondary" />