mirror of
https://github.com/affaan-m/ECC.git
synced 2026-08-17 21:15:40 +02:00
Make Antigravity 2.0 installs native and safely migrate legacy state. Ensure doctor, repair, status projection, repeat installs, legacy Codex sync, and uninstall converge without losing user files. Exclude Python bytecode and harden repo-scan bootstrap guidance. Gate publishing and pull-request merges on one exact packed artifact completing install, repeat, drift, repair, status, and uninstall across Linux, macOS, and Windows. Co-authored-by: lorencifernando-coder <lorenci.fernando@gmail.com> Co-authored-by: Suliman Abdulrazzaq <suliman9000a@gmail.com> Co-authored-by: Wu Shuwen <mikewushuwen@outlook.com>
212 lines
9.1 KiB
YAML
212 lines
9.1 KiB
YAML
name: Release
|
|
|
|
on:
|
|
push:
|
|
tags: ['v*']
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
verify:
|
|
name: Verify Release
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
already_published: ${{ steps.npm_publish_state.outputs.already_published }}
|
|
dist_tag: ${{ steps.npm_publish_state.outputs.dist_tag }}
|
|
package_file: ${{ steps.pack.outputs.package_file }}
|
|
package_sha256: ${{ steps.pack.outputs.package_sha256 }}
|
|
release_commit: ${{ steps.source.outputs.release_commit }}
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
with:
|
|
fetch-depth: 0
|
|
persist-credentials: false
|
|
|
|
- name: Pin release source
|
|
id: source
|
|
run: |
|
|
RELEASE_COMMIT=$(git rev-parse HEAD)
|
|
echo "release_commit=${RELEASE_COMMIT}" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
|
with:
|
|
node-version: '20.x'
|
|
registry-url: 'https://registry.npmjs.org'
|
|
|
|
- name: Install dependencies
|
|
run: npm ci --ignore-scripts
|
|
|
|
- name: Run supply-chain IOC scan
|
|
run: npm run security:ioc-scan
|
|
|
|
- name: Verify OpenCode package payload
|
|
run: node tests/scripts/build-opencode.test.js
|
|
|
|
- name: Validate version tag
|
|
run: |
|
|
if ! [[ "${REF_NAME}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then
|
|
echo "Invalid version tag format. Expected vX.Y.Z or vX.Y.Z-prerelease"
|
|
exit 1
|
|
fi
|
|
|
|
env:
|
|
REF_NAME: ${{ github.ref_name }}
|
|
- name: Verify package version matches tag
|
|
env:
|
|
TAG_NAME: ${{ github.ref_name }}
|
|
run: |
|
|
TAG_VERSION="${TAG_NAME#v}"
|
|
PACKAGE_VERSION=$(node -p "require('./package.json').version")
|
|
if [ "$TAG_VERSION" != "$PACKAGE_VERSION" ]; then
|
|
echo "::error::Tag version ($TAG_VERSION) does not match package.json version ($PACKAGE_VERSION)"
|
|
echo "Run: ./scripts/release.sh $TAG_VERSION"
|
|
exit 1
|
|
fi
|
|
|
|
- name: Verify release metadata stays in sync
|
|
run: node tests/plugin-manifest.test.js
|
|
|
|
- name: Check npm publish state
|
|
id: npm_publish_state
|
|
run: |
|
|
PACKAGE_NAME=$(node -p "require('./package.json').name")
|
|
PACKAGE_VERSION=$(node -p "require('./package.json').version")
|
|
NPM_DIST_TAG=$(node -p "require('./package.json').version.includes('-') ? 'next' : 'latest'")
|
|
if npm view "${PACKAGE_NAME}@${PACKAGE_VERSION}" version >/dev/null 2>&1; then
|
|
echo "already_published=true" >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo "already_published=false" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
echo "dist_tag=${NPM_DIST_TAG}" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Generate release highlights
|
|
id: highlights
|
|
env:
|
|
TAG_NAME: ${{ github.ref_name }}
|
|
run: |
|
|
TAG_VERSION="${TAG_NAME#v}"
|
|
cat > release_body.md <<EOF
|
|
## ECC ${TAG_VERSION}
|
|
|
|
### What This Release Focuses On
|
|
- Harness reliability and hook stability across Claude Code, Cursor, OpenCode, and Codex
|
|
- Stronger eval-driven workflows and quality gates
|
|
- Better operator UX for autonomous loop execution
|
|
|
|
### Notable Changes
|
|
- Session persistence and hook lifecycle fixes
|
|
- Expanded skills and command coverage for harness performance work
|
|
- Improved release-note generation and changelog hygiene
|
|
|
|
### Notes
|
|
- npm package: \`ecc-universal\`
|
|
- Claude marketplace/plugin identifier: \`ecc@ecc\`
|
|
- For migration tips and compatibility notes, see README and CHANGELOG.
|
|
EOF
|
|
|
|
- name: Pack npm artifact
|
|
id: pack
|
|
run: |
|
|
npm pack --json > npm-pack.json
|
|
node -e "const crypto = require('crypto'); const fs = require('fs'); const data = JSON.parse(fs.readFileSync('npm-pack.json', 'utf8')); const file = data[0]?.filename; if (!/^ecc-universal-[0-9A-Za-z.+-]+\.tgz$/.test(file || '')) throw new Error('Unexpected packed filename'); const archives = fs.readdirSync('.').filter(name => name.endsWith('.tgz')); if (archives.length !== 1 || archives[0] !== file) throw new Error('Expected exactly one packed archive'); const digest = crypto.createHash('sha256').update(fs.readFileSync(file)).digest('hex'); fs.appendFileSync(process.env.GITHUB_OUTPUT, 'package_file=' + file + '\npackage_sha256=' + digest + '\n')"
|
|
|
|
- name: Upload release artifacts
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
with:
|
|
name: ecc-release-artifacts
|
|
path: |
|
|
release_body.md
|
|
${{ steps.pack.outputs.package_file }}
|
|
if-no-files-found: error
|
|
|
|
- name: Verify existing npm artifact matches candidate
|
|
if: steps.npm_publish_state.outputs.already_published == 'true'
|
|
env:
|
|
ECC_RELEASE_PACKAGE: ${{ steps.pack.outputs.package_file }}
|
|
run: |
|
|
PACKAGE_NAME=$(node -p "require('./package.json').name")
|
|
PACKAGE_VERSION=$(node -p "require('./package.json').version")
|
|
REGISTRY_INTEGRITY=$(npm view "${PACKAGE_NAME}@${PACKAGE_VERSION}" dist.integrity)
|
|
ECC_REGISTRY_INTEGRITY="$REGISTRY_INTEGRITY" node -e "const crypto = require('crypto'); const fs = require('fs'); const expected = process.env.ECC_REGISTRY_INTEGRITY; if (!/^sha512-[A-Za-z0-9+/]+={0,2}$/.test(expected || '')) throw new Error('Invalid registry integrity'); const actual = 'sha512-' + crypto.createHash('sha512').update(fs.readFileSync(process.env.ECC_RELEASE_PACKAGE)).digest('base64'); if (actual !== expected) throw new Error('Existing npm artifact does not match tested candidate')"
|
|
|
|
lifecycle:
|
|
name: Packed Lifecycle (${{ matrix.os }})
|
|
needs: verify
|
|
permissions:
|
|
contents: read
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
runs-on: ${{ matrix.os }}
|
|
|
|
steps:
|
|
- name: Checkout lifecycle test
|
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
with:
|
|
ref: ${{ needs.verify.outputs.release_commit }}
|
|
persist-credentials: false
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
|
with:
|
|
node-version: '20.x'
|
|
|
|
- name: Download exact packed artifact
|
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
with:
|
|
name: ecc-release-artifacts
|
|
path: release-artifacts
|
|
|
|
- name: Verify packed install lifecycle
|
|
env:
|
|
ECC_RELEASE_PACKAGE: release-artifacts/${{ needs.verify.outputs.package_file }}
|
|
ECC_RELEASE_SHA256: ${{ needs.verify.outputs.package_sha256 }}
|
|
run: node tests/ci/packed-artifact-lifecycle.js
|
|
|
|
publish:
|
|
name: Publish Release
|
|
runs-on: ubuntu-latest
|
|
needs: [verify, lifecycle]
|
|
permissions:
|
|
contents: write
|
|
id-token: write
|
|
|
|
steps:
|
|
- name: Download release artifacts
|
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
with:
|
|
name: ecc-release-artifacts
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
|
with:
|
|
node-version: '20.x'
|
|
registry-url: 'https://registry.npmjs.org'
|
|
|
|
- name: Verify artifact before publish
|
|
env:
|
|
ECC_RELEASE_PACKAGE: ${{ needs.verify.outputs.package_file }}
|
|
ECC_RELEASE_SHA256: ${{ needs.verify.outputs.package_sha256 }}
|
|
run: node -e "const crypto = require('crypto'); const fs = require('fs'); const file = process.env.ECC_RELEASE_PACKAGE; const expected = process.env.ECC_RELEASE_SHA256; if (!/^ecc-universal-[0-9A-Za-z.+-]+\.tgz$/.test(file || '')) throw new Error('Unexpected packed filename'); if (!/^[a-f0-9]{64}$/.test(expected || '')) throw new Error('Invalid packed SHA-256'); const archives = fs.readdirSync('.').filter(name => name.endsWith('.tgz')); if (archives.length !== 1 || archives[0] !== file) throw new Error('Expected exactly one downloaded archive'); const actual = crypto.createHash('sha256').update(fs.readFileSync(file)).digest('hex'); if (actual !== expected) throw new Error('Downloaded publish artifact SHA-256 mismatch')"
|
|
|
|
- name: Create GitHub Release
|
|
uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2
|
|
with:
|
|
body_path: release_body.md
|
|
generate_release_notes: true
|
|
prerelease: ${{ contains(github.ref_name, '-') }}
|
|
make_latest: ${{ contains(github.ref_name, '-') && 'false' || 'true' }}
|
|
|
|
- name: Publish npm package
|
|
if: needs.verify.outputs.already_published != 'true'
|
|
env:
|
|
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
ECC_RELEASE_PACKAGE: ${{ needs.verify.outputs.package_file }}
|
|
NPM_DIST_TAG: ${{ needs.verify.outputs.dist_tag }}
|
|
run: npm publish "./${ECC_RELEASE_PACKAGE}" --access public --provenance --tag "${NPM_DIST_TAG}"
|