mirror of
https://github.com/cexll/myclaude.git
synced 2026-02-05 02:30:26 +08:00
13
.github/workflows/release.yml
vendored
13
.github/workflows/release.yml
vendored
@@ -47,6 +47,10 @@ jobs:
|
||||
goarch: amd64
|
||||
- goos: darwin
|
||||
goarch: arm64
|
||||
- goos: windows
|
||||
goarch: amd64
|
||||
- goos: windows
|
||||
goarch: arm64
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
@@ -58,6 +62,7 @@ jobs:
|
||||
go-version: '1.21'
|
||||
|
||||
- name: Build binary
|
||||
id: build
|
||||
working-directory: codex-wrapper
|
||||
env:
|
||||
GOOS: ${{ matrix.goos }}
|
||||
@@ -66,14 +71,18 @@ jobs:
|
||||
run: |
|
||||
VERSION=${GITHUB_REF#refs/tags/}
|
||||
OUTPUT_NAME=codex-wrapper-${{ matrix.goos }}-${{ matrix.goarch }}
|
||||
if [ "${{ matrix.goos }}" = "windows" ]; then
|
||||
OUTPUT_NAME="${OUTPUT_NAME}.exe"
|
||||
fi
|
||||
go build -ldflags="-s -w -X main.version=${VERSION}" -o ${OUTPUT_NAME} .
|
||||
chmod +x ${OUTPUT_NAME}
|
||||
echo "artifact_path=codex-wrapper/${OUTPUT_NAME}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: codex-wrapper-${{ matrix.goos }}-${{ matrix.goarch }}
|
||||
path: codex-wrapper/codex-wrapper-${{ matrix.goos }}-${{ matrix.goarch }}
|
||||
path: ${{ steps.build.outputs.artifact_path }}
|
||||
|
||||
release:
|
||||
name: Create Release
|
||||
@@ -92,7 +101,7 @@ jobs:
|
||||
run: |
|
||||
mkdir -p release
|
||||
find artifacts -type f -name "codex-wrapper-*" -exec mv {} release/ \;
|
||||
cp install.sh release/
|
||||
cp install.sh install.ps1 install.bat release/
|
||||
ls -la release/
|
||||
|
||||
- name: Create Release
|
||||
|
||||
27
README.md
27
README.md
@@ -238,6 +238,33 @@ python3 install.py --module dev
|
||||
bash install.sh
|
||||
```
|
||||
|
||||
#### Windows
|
||||
|
||||
Windows installs place `codex-wrapper.exe` in `%USERPROFILE%\bin`.
|
||||
|
||||
```powershell
|
||||
# PowerShell (recommended)
|
||||
powershell -ExecutionPolicy Bypass -File install.ps1
|
||||
|
||||
# Batch (cmd)
|
||||
install.bat
|
||||
```
|
||||
|
||||
**Add to PATH** (if installer doesn't detect it):
|
||||
|
||||
```powershell
|
||||
# PowerShell - persistent for current user
|
||||
[Environment]::SetEnvironmentVariable('PATH', "$HOME\bin;" + [Environment]::GetEnvironmentVariable('PATH','User'), 'User')
|
||||
|
||||
# PowerShell - current session only
|
||||
$Env:PATH = "$HOME\bin;$Env:PATH"
|
||||
```
|
||||
|
||||
```batch
|
||||
REM cmd.exe - persistent for current user
|
||||
setx PATH "%USERPROFILE%\bin;%PATH%"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Workflow Selection Guide
|
||||
|
||||
27
README_CN.md
27
README_CN.md
@@ -235,6 +235,33 @@ python3 install.py --module dev
|
||||
bash install.sh
|
||||
```
|
||||
|
||||
#### Windows 系统
|
||||
|
||||
Windows 系统会将 `codex-wrapper.exe` 安装到 `%USERPROFILE%\bin`。
|
||||
|
||||
```powershell
|
||||
# PowerShell(推荐)
|
||||
powershell -ExecutionPolicy Bypass -File install.ps1
|
||||
|
||||
# 批处理(cmd)
|
||||
install.bat
|
||||
```
|
||||
|
||||
**添加到 PATH**(如果安装程序未自动检测):
|
||||
|
||||
```powershell
|
||||
# PowerShell - 永久添加(当前用户)
|
||||
[Environment]::SetEnvironmentVariable('PATH', "$HOME\bin;" + [Environment]::GetEnvironmentVariable('PATH','User'), 'User')
|
||||
|
||||
# PowerShell - 仅当前会话
|
||||
$Env:PATH = "$HOME\bin;$Env:PATH"
|
||||
```
|
||||
|
||||
```batch
|
||||
REM cmd.exe - 永久添加(当前用户)
|
||||
setx PATH "%USERPROFILE%\bin;%PATH%"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 工作流选择指南
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -925,21 +926,30 @@ func (b *tailBuffer) String() string {
|
||||
|
||||
func forwardSignals(ctx context.Context, cmd *exec.Cmd, logErrorFn func(string)) {
|
||||
sigCh := make(chan os.Signal, 1)
|
||||
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
|
||||
signals := []os.Signal{syscall.SIGINT}
|
||||
if runtime.GOOS != "windows" {
|
||||
signals = append(signals, syscall.SIGTERM)
|
||||
}
|
||||
signal.Notify(sigCh, signals...)
|
||||
|
||||
go func() {
|
||||
defer signal.Stop(sigCh)
|
||||
select {
|
||||
case sig := <-sigCh:
|
||||
logErrorFn(fmt.Sprintf("Received signal: %v", sig))
|
||||
if cmd.Process != nil {
|
||||
cmd.Process.Signal(syscall.SIGTERM)
|
||||
time.AfterFunc(time.Duration(forceKillDelay)*time.Second, func() {
|
||||
if cmd.Process != nil {
|
||||
cmd.Process.Kill()
|
||||
}
|
||||
})
|
||||
if cmd.Process == nil {
|
||||
return
|
||||
}
|
||||
if runtime.GOOS == "windows" {
|
||||
_ = cmd.Process.Kill()
|
||||
return
|
||||
}
|
||||
_ = cmd.Process.Signal(syscall.SIGTERM)
|
||||
time.AfterFunc(time.Duration(forceKillDelay)*time.Second, func() {
|
||||
if cmd.Process != nil {
|
||||
_ = cmd.Process.Kill()
|
||||
}
|
||||
})
|
||||
case <-ctx.Done():
|
||||
}
|
||||
}()
|
||||
@@ -962,6 +972,11 @@ func terminateProcess(cmd *exec.Cmd) *time.Timer {
|
||||
return nil
|
||||
}
|
||||
|
||||
if runtime.GOOS == "windows" {
|
||||
_ = cmd.Process.Kill()
|
||||
return nil
|
||||
}
|
||||
|
||||
_ = cmd.Process.Signal(syscall.SIGTERM)
|
||||
|
||||
return time.AfterFunc(time.Duration(forceKillDelay)*time.Second, func() {
|
||||
|
||||
114
install.bat
Normal file
114
install.bat
Normal file
@@ -0,0 +1,114 @@
|
||||
@echo off
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
set "EXIT_CODE=0"
|
||||
set "REPO=cexll/myclaude"
|
||||
set "VERSION=latest"
|
||||
set "OS=windows"
|
||||
|
||||
call :detect_arch
|
||||
if errorlevel 1 goto :fail
|
||||
|
||||
set "BINARY_NAME=codex-wrapper-%OS%-%ARCH%.exe"
|
||||
set "URL=https://github.com/%REPO%/releases/%VERSION%/download/%BINARY_NAME%"
|
||||
set "TEMP_FILE=%TEMP%\codex-wrapper-%ARCH%-%RANDOM%.exe"
|
||||
set "DEST_DIR=%USERPROFILE%\bin"
|
||||
set "DEST=%DEST_DIR%\codex-wrapper.exe"
|
||||
|
||||
echo Downloading codex-wrapper for %ARCH% ...
|
||||
echo %URL%
|
||||
call :download
|
||||
if errorlevel 1 goto :fail
|
||||
|
||||
if not exist "%TEMP_FILE%" (
|
||||
echo ERROR: download failed to produce "%TEMP_FILE%".
|
||||
goto :fail
|
||||
)
|
||||
|
||||
echo Installing to "%DEST%" ...
|
||||
if not exist "%DEST_DIR%" (
|
||||
mkdir "%DEST_DIR%" >nul 2>nul || goto :fail
|
||||
)
|
||||
|
||||
move /y "%TEMP_FILE%" "%DEST%" >nul 2>nul
|
||||
if errorlevel 1 (
|
||||
echo ERROR: unable to place file in "%DEST%".
|
||||
goto :fail
|
||||
)
|
||||
|
||||
"%DEST%" --version >nul 2>nul
|
||||
if errorlevel 1 (
|
||||
echo ERROR: installation verification failed.
|
||||
goto :fail
|
||||
)
|
||||
|
||||
echo.
|
||||
echo codex-wrapper installed successfully at:
|
||||
echo %DEST%
|
||||
|
||||
set "PATH_CHECK=;%PATH%;"
|
||||
echo !PATH_CHECK! | findstr /I /C:";%DEST_DIR%;" >nul
|
||||
if errorlevel 1 (
|
||||
echo.
|
||||
echo %DEST_DIR% is not in your PATH.
|
||||
echo Add it for the current user with:
|
||||
echo setx PATH "%%USERPROFILE%%\bin;%%PATH%%"
|
||||
echo Then restart your terminal to use codex-wrapper globally.
|
||||
)
|
||||
|
||||
goto :cleanup
|
||||
|
||||
:detect_arch
|
||||
set "ARCH=%PROCESSOR_ARCHITECTURE%"
|
||||
if defined PROCESSOR_ARCHITEW6432 set "ARCH=%PROCESSOR_ARCHITEW6432%"
|
||||
|
||||
if /I "%ARCH%"=="AMD64" (
|
||||
set "ARCH=amd64"
|
||||
exit /b 0
|
||||
) else if /I "%ARCH%"=="ARM64" (
|
||||
set "ARCH=arm64"
|
||||
exit /b 0
|
||||
) else (
|
||||
echo ERROR: unsupported architecture "%ARCH%". 64-bit Windows on AMD64 or ARM64 is required.
|
||||
set "EXIT_CODE=1"
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
:download
|
||||
where curl >nul 2>nul
|
||||
if %errorlevel%==0 (
|
||||
echo Using curl ...
|
||||
curl -fL --retry 3 --connect-timeout 10 "%URL%" -o "%TEMP_FILE%"
|
||||
if errorlevel 1 (
|
||||
echo ERROR: curl download failed.
|
||||
set "EXIT_CODE=1"
|
||||
exit /b 1
|
||||
)
|
||||
exit /b 0
|
||||
)
|
||||
|
||||
where powershell >nul 2>nul
|
||||
if %errorlevel%==0 (
|
||||
echo Using PowerShell ...
|
||||
powershell -NoLogo -NoProfile -Command " $ErrorActionPreference='Stop'; try { [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor 3072 -bor 768 -bor 192 } catch {} ; $wc = New-Object System.Net.WebClient; $wc.DownloadFile('%URL%','%TEMP_FILE%') "
|
||||
if errorlevel 1 (
|
||||
echo ERROR: PowerShell download failed.
|
||||
set "EXIT_CODE=1"
|
||||
exit /b 1
|
||||
)
|
||||
exit /b 0
|
||||
)
|
||||
|
||||
echo ERROR: neither curl nor PowerShell is available to download the installer.
|
||||
set "EXIT_CODE=1"
|
||||
exit /b 1
|
||||
|
||||
:fail
|
||||
echo Installation failed.
|
||||
set "EXIT_CODE=1"
|
||||
goto :cleanup
|
||||
|
||||
:cleanup
|
||||
if exist "%TEMP_FILE%" del /f /q "%TEMP_FILE%" >nul 2>nul
|
||||
set "CODE=%EXIT_CODE%"
|
||||
endlocal & exit /b %CODE%
|
||||
66
install.ps1
Normal file
66
install.ps1
Normal file
@@ -0,0 +1,66 @@
|
||||
[CmdletBinding()]
|
||||
param()
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$ProgressPreference = 'Continue'
|
||||
$tempFile = $null
|
||||
|
||||
function Get-Architecture {
|
||||
$arch = if ($env:PROCESSOR_ARCHITEW6432) { $env:PROCESSOR_ARCHITEW6432 } else { $env:PROCESSOR_ARCHITECTURE }
|
||||
switch ($arch.ToLower()) {
|
||||
'amd64' { 'amd64' }
|
||||
'x86' { throw 'Unsupported architecture: x86 (64-bit Windows is required).' }
|
||||
'arm64' { 'arm64' }
|
||||
'aarch64' { 'arm64' }
|
||||
default { throw "Unsupported architecture: $arch" }
|
||||
}
|
||||
}
|
||||
|
||||
function Write-Step {
|
||||
param([string] $Status, [int] $Percent)
|
||||
Write-Progress -Activity 'Installing codex-wrapper' -Status $Status -PercentComplete $Percent
|
||||
Write-Host $Status
|
||||
}
|
||||
|
||||
try {
|
||||
Write-Step 'Detecting CPU architecture...' 5
|
||||
$arch = Get-Architecture
|
||||
$url = "https://github.com/cexll/myclaude/releases/latest/download/codex-wrapper-windows-$arch.exe"
|
||||
|
||||
$tempFile = Join-Path ([IO.Path]::GetTempPath()) "codex-wrapper-$arch.exe"
|
||||
$homeBin = Join-Path $HOME 'bin'
|
||||
$destination = Join-Path $homeBin 'codex-wrapper.exe'
|
||||
|
||||
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
|
||||
|
||||
Write-Step "Downloading codex-wrapper from $url ..." 25
|
||||
Invoke-WebRequest -Uri $url -OutFile $tempFile -UseBasicParsing -ErrorAction Stop
|
||||
|
||||
Write-Step "Installing to $destination ..." 65
|
||||
New-Item -ItemType Directory -Path $homeBin -Force | Out-Null
|
||||
Move-Item -LiteralPath $tempFile -Destination $destination -Force
|
||||
|
||||
Write-Step 'Verifying installation...' 90
|
||||
& $destination --version | Out-Null
|
||||
|
||||
Write-Step 'codex-wrapper installed successfully.' 100
|
||||
Write-Progress -Activity 'Installing codex-wrapper' -Completed -Status 'Done'
|
||||
Write-Host "Installed to $destination"
|
||||
|
||||
$normalizedBin = ($homeBin.TrimEnd('\') -replace '/','\').ToLower()
|
||||
$pathEntries = ($env:PATH -split ';') | Where-Object { $_ } | ForEach-Object { ($_ -replace '/','\').TrimEnd('\').ToLower() }
|
||||
if (-not ($pathEntries -contains $normalizedBin)) {
|
||||
Write-Warning "$homeBin is not in your PATH."
|
||||
Write-Host 'Add it permanently with:'
|
||||
Write-Host " [Environment]::SetEnvironmentVariable('PATH', '$homeBin;' + [Environment]::GetEnvironmentVariable('PATH','User'), 'User')"
|
||||
Write-Host 'Then restart your shell to pick up the updated PATH.'
|
||||
}
|
||||
} catch {
|
||||
Write-Progress -Activity 'Installing codex-wrapper' -Completed -Status 'Failed'
|
||||
Write-Error "Installation failed: $($_.Exception.Message)"
|
||||
exit 1
|
||||
} finally {
|
||||
if ($tempFile -and (Test-Path $tempFile)) {
|
||||
Remove-Item -LiteralPath $tempFile -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user