ci: migrate binaries to GitHub Release + Actions CI

- Add .github/workflows/build-binaries.yml (Go cross-compile → preset release)
- installer.ts: download from GitHub Release, fallback to local bin/
- package.json: exclude binaries from npm (16.3MB → 161KB)
- .gitignore: stop tracking bin/codeagent-wrapper-*
- git rm --cached 6 pre-compiled binaries
This commit is contained in:
li committed 2026-03-10 22:26:14 +08:00
1 parent 5769a1dbe6
commit 968cbedb8a
4 files changed
+130 -12

No files matched your search

+74
View File
@@ -0,0 +1,74 @@
name: Build codeagent-wrapper binaries
on:
push:
paths:
- 'codeagent-wrapper/**'
workflow_dispatch:
permissions:
contents: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '1.21'
- name: Cross-compile binaries
working-directory: codeagent-wrapper
run: |
set -e
mkdir -p ../artifacts
declare -a targets=(
"darwin:amd64:"
"darwin:arm64:"
"linux:amd64:"
"linux:arm64:"
"windows:amd64:.exe"
"windows:arm64:.exe"
)
for target in "${targets[@]}"; do
IFS=':' read -r os arch ext <<< "$target"
output="codeagent-wrapper-${os}-${arch}${ext}"
echo "::group::Building ${output}"
GOOS=$os GOARCH=$arch go build -ldflags="-s -w" -o "../artifacts/${output}" .
echo "::endgroup::"
done
echo "### Build artifacts" >> $GITHUB_STEP_SUMMARY
ls -lh ../artifacts/ | awk 'NR>1{printf "- `%s` (%s)\n", $NF, $5}' >> $GITHUB_STEP_SUMMARY
- name: Delete existing preset release
run: gh release delete preset --yes --cleanup-tag 2>/dev/null || true
env:
GH_TOKEN: ${{ github.token }}
- name: Create preset release
uses: softprops/action-gh-release@v2
with:
tag_name: preset
name: "Pre-built Binaries (codeagent-wrapper)"
body: |
Pre-compiled `codeagent-wrapper` binaries for all supported platforms.
Automatically downloaded during `npx ccg-workflow` installation.
| File | Platform | Architecture |
|------|----------|-------------|
| `codeagent-wrapper-darwin-amd64` | macOS | Intel x64 |
| `codeagent-wrapper-darwin-arm64` | macOS | Apple Silicon |
| `codeagent-wrapper-linux-amd64` | Linux | x64 |
| `codeagent-wrapper-linux-arm64` | Linux | ARM64 |
| `codeagent-wrapper-windows-amd64.exe` | Windows | x64 |
| `codeagent-wrapper-windows-arm64.exe` | Windows | ARM64 |
> This release is automatically updated when `codeagent-wrapper/` source changes.
files: artifacts/*
prerelease: true
make_latest: false
+3 -3
View File
@@ -2,10 +2,10 @@
codeagent-wrapper/codeagent-wrapper
codeagent-wrapper/*.exe
*.exe
# 但是允许 bin/ 目录下的预编译二进制文件
!bin/*.exe
dist/
# Pre-compiled binaries (hosted on GitHub Release, not tracked in git)
bin/codeagent-wrapper-*
node_modules/
# Python
+1 -1
View File
@@ -25,7 +25,7 @@
"module": "dist/index.mjs",
"types": "dist/index.d.mts",
"files": [
"bin",
"bin/ccg.mjs",
"dist",
"templates/commands/analyze.md",
"templates/commands/backend.md",
+52 -8
View File
@@ -7,6 +7,11 @@ import { parse as parseToml, stringify as stringifyToml } from 'smol-toml'
import { backupClaudeCodeConfig, buildMcpServerConfig, fixWindowsMcpConfig, mergeMcpServers, readClaudeCodeConfig, writeClaudeCodeConfig } from './mcp'
import { isWindows } from './platform'
// GitHub Release download config
const GITHUB_REPO = 'fengshao1227/ccg-workflow'
const RELEASE_TAG = 'preset'
const BINARY_DOWNLOAD_URL = `https://github.com/${GITHUB_REPO}/releases/download/${RELEASE_TAG}`
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
@@ -24,6 +29,31 @@ function findPackageRoot(startDir: string): string {
const PACKAGE_ROOT = findPackageRoot(__dirname)
/**
* Download codeagent-wrapper binary from GitHub Release.
* Uses the fixed `preset` tag release for pre-compiled binaries.
* Supports redirect-following (GitHub releases redirect to CDN).
*/
async function downloadBinaryFromRelease(binaryName: string, destPath: string): Promise<boolean> {
const url = `${BINARY_DOWNLOAD_URL}/${binaryName}`
// Use dynamic import for https to follow redirects manually (Node.js fetch follows automatically)
const response = await fetch(url, { redirect: 'follow' })
if (!response.ok) {
return false
}
const buffer = Buffer.from(await response.arrayBuffer())
await fs.writeFile(destPath, buffer)
// Set executable permission on Unix-like systems
if (process.platform !== 'win32') {
await fs.chmod(destPath, 0o755)
}
return true
}
// All available commands (20 total after adding spec commands)
const ALL_COMMANDS = [
'workflow', // 完整6阶段开发工作流
@@ -813,16 +843,30 @@ ${workflow.description}
return result
}
const srcBinary = join(PACKAGE_ROOT, 'bin', binaryName)
const destBinary = join(binDir, platform === 'win32' ? 'codeagent-wrapper.exe' : 'codeagent-wrapper')
if (await fs.pathExists(srcBinary)) {
await fs.copy(srcBinary, destBinary)
// Set executable permission on Unix-like systems
if (platform !== 'win32') {
await fs.chmod(destBinary, 0o755)
}
// Strategy 1: Download from GitHub Release (preferred)
let installed = false
try {
installed = await downloadBinaryFromRelease(binaryName, destBinary)
}
catch {
// Download failed, will try fallback
}
// Strategy 2: Fallback to local bin/ (development or offline)
if (!installed) {
const srcBinary = join(PACKAGE_ROOT, 'bin', binaryName)
if (await fs.pathExists(srcBinary)) {
await fs.copy(srcBinary, destBinary)
if (platform !== 'win32') {
await fs.chmod(destBinary, 0o755)
}
installed = true
}
}
if (installed) {
// Verify installation by running --version
try {
const { execSync } = await import('node:child_process')
@@ -836,7 +880,7 @@ ${workflow.description}
}
}
else {
result.errors.push(`Binary not found in package: ${binaryName}`)
result.errors.push(`Failed to obtain binary: ${binaryName} (download failed, no local fallback)`)
result.success = false
}
}