feat/beta-release (#190)

* chore: update README version to 2.7.1

Updated the version badge and download links in the README to reflect the new release version 2.7.1, ensuring users have the correct information for downloading the latest builds.

* feat(releases): add beta release system with user opt-in

Implements a complete beta release workflow that allows users to opt-in
to receiving pre-release versions. This enables testing new features
before they're included in stable releases.

Changes:
- Add beta-release.yml workflow for creating beta releases from develop
- Add betaUpdates setting with UI toggle in Settings > Updates
- Add update channel support to electron-updater (beta vs latest)
- Extract shared settings-utils.ts to reduce code duplication
- Add prepare-release.yml workflow for automated release preparation
- Document beta release process in CONTRIBUTING.md and RELEASE.md

Users can enable beta updates in Settings > Updates, and maintainers
can trigger beta releases via the GitHub Actions workflow.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* workflow update

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Andy
2025-12-23 14:28:09 +01:00
committed by GitHub
parent ced2ad479f
commit 8f766ad16e
24 changed files with 1253 additions and 250 deletions
+50 -77
View File
@@ -1,75 +1,27 @@
name: Bug Report
description: Report a bug or unexpected behavior
labels: ["bug", "triage"]
name: 🐛 Bug Report
description: Something isn't working
labels: ["bug", "needs-triage"]
body:
- type: markdown
- type: checkboxes
id: checklist
attributes:
value: |
Thanks for taking the time to report a bug! Please fill out the sections below.
- type: textarea
id: description
attributes:
label: Bug Description
description: A clear and concise description of the bug.
placeholder: What happened?
validations:
required: true
- type: textarea
id: expected
attributes:
label: Expected Behavior
description: What did you expect to happen?
placeholder: What should have happened?
validations:
required: true
- type: textarea
id: reproduce
attributes:
label: Steps to Reproduce
description: Steps to reproduce the behavior.
placeholder: |
1. Run command '...'
2. Click on '...'
3. See error
validations:
required: true
- type: textarea
id: logs
attributes:
label: Error Messages / Logs
description: If applicable, paste any error messages or logs.
render: shell
- type: textarea
id: screenshots
attributes:
label: Screenshots
description: If applicable, add screenshots to help explain the problem.
label: Checklist
options:
- label: I searched existing issues and this hasn't been reported
required: true
- type: dropdown
id: component
id: area
attributes:
label: Component
description: Which part of Auto Claude is affected?
label: Area
options:
- Python Backend (apps/backend/)
- Electron UI (apps/frontend/)
- Both
- Frontend
- Backend
- Fullstack
- Not sure
validations:
required: true
- type: input
id: version
attributes:
label: Auto Claude Version
description: What version are you running? (check package.json or git tag)
placeholder: "v2.0.1"
- type: dropdown
id: os
attributes:
@@ -78,26 +30,47 @@ body:
- macOS
- Windows
- Linux
- Other
validations:
required: true
- type: input
id: python-version
id: version
attributes:
label: Python Version
description: Output of `python --version`
placeholder: "3.12.0"
- type: input
id: node-version
attributes:
label: Node.js Version (for UI issues)
description: Output of `node --version`
placeholder: "20.10.0"
label: Version
placeholder: "e.g., 2.5.5"
validations:
required: true
- type: textarea
id: additional
id: description
attributes:
label: Additional Context
description: Any other context about the problem.
label: What happened?
placeholder: Describe the bug clearly and concisely. Include any error messages you encountered.
validations:
required: true
- type: textarea
id: steps
attributes:
label: Steps to reproduce
placeholder: |
1. Run command '...' or click on '...'
2. Observe behavior '...'
3. See error or unexpected result
validations:
required: true
- type: textarea
id: expected
attributes:
label: Expected behavior
placeholder: What did you expect to happen instead? Describe the correct behavior.
validations:
required: true
- type: textarea
id: logs
attributes:
label: Logs / Screenshots
description: Required for UI bugs. Attach relevant logs, screenshots, or error output.
render: shell
+6 -6
View File
@@ -1,8 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: Questions & Discussions
url: https://github.com/AndyMik90/Auto-Claude/discussions
about: Ask questions and discuss ideas with the community
- name: Documentation
url: https://github.com/AndyMik90/Auto-Claude#readme
about: Check the documentation before opening an issue
- name: 💡 Feature Request
url: https://github.com/AndyMik90/Auto-Claude/discussions/new?category=ideas
about: Suggest new features in GitHub Discussions
- name: 💬 Discord Community
url: https://discord.gg/KCXaPBr4Dj
about: Questions and discussions - join our Discord!
+37
View File
@@ -0,0 +1,37 @@
name: 📚 Documentation
description: Improvements or additions to documentation
labels: ["documentation", "needs-triage", "help wanted"]
body:
- type: dropdown
id: type
attributes:
label: Type
options:
- Missing documentation
- Incorrect/outdated info
- Improvement suggestion
- Typo/grammar fix
validations:
required: true
- type: input
id: location
attributes:
label: Location
description: Which file or page?
placeholder: "e.g., README.md or guides/setup.md"
- type: textarea
id: description
attributes:
label: Description
description: What needs to change?
validations:
required: true
- type: checkboxes
id: contribute
attributes:
label: Contribution
options:
- label: I'm willing to submit a PR for this
@@ -1,70 +0,0 @@
name: Feature Request
description: Suggest a new feature or enhancement
labels: ["enhancement", "triage"]
body:
- type: markdown
attributes:
value: |
Thanks for suggesting a feature! Please describe your idea below.
- type: textarea
id: problem
attributes:
label: Problem Statement
description: What problem does this feature solve? Is this related to a frustration?
placeholder: I'm always frustrated when...
validations:
required: true
- type: textarea
id: solution
attributes:
label: Proposed Solution
description: Describe the solution you'd like to see.
placeholder: I would like Auto Claude to...
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Alternatives Considered
description: Have you considered any alternative solutions or workarounds?
placeholder: I've tried...
- type: dropdown
id: component
attributes:
label: Component
description: Which part of Auto Claude would this affect?
options:
- Python Backend (apps/backend/)
- Electron UI (apps/frontend/)
- Both
- New component
- Not sure
validations:
required: true
- type: dropdown
id: priority
attributes:
label: How important is this feature to you?
options:
- Nice to have
- Important for my workflow
- Critical / Blocking my use
- type: checkboxes
id: contribution
attributes:
label: Contribution
description: Would you be willing to help implement this?
options:
- label: I'm willing to submit a PR for this feature
- type: textarea
id: additional
attributes:
label: Additional Context
description: Add any other context, mockups, or screenshots about the feature request.
+61
View File
@@ -0,0 +1,61 @@
name: ❓ Question
description: Needs clarification
labels: ["question", "needs-triage"]
body:
- type: markdown
attributes:
value: |
**Before asking:** Check [Discord](https://discord.gg/KCXaPBr4Dj) - your question may already be answered there!
- type: checkboxes
id: checklist
attributes:
label: Checklist
options:
- label: I searched existing issues and Discord for similar questions
required: true
- type: dropdown
id: area
attributes:
label: Area
options:
- Setup/Installation
- Frontend
- Backend
- Configuration
- Other
validations:
required: true
- type: input
id: version
attributes:
label: Version
description: Which version are you using?
placeholder: "e.g., 2.7.1"
validations:
required: true
- type: textarea
id: question
attributes:
label: Question
placeholder: "Describe your question in detail..."
validations:
required: true
- type: textarea
id: context
attributes:
label: Context
description: What are you trying to achieve?
validations:
required: true
- type: textarea
id: attempts
attributes:
label: What have you already tried?
description: What steps have you taken to resolve this?
placeholder: "e.g., I tried reading the docs, searched for..."
+59 -27
View File
@@ -1,44 +1,76 @@
## Summary
## Base Branch
<!-- Brief description of what this PR does -->
- [ ] This PR targets the `develop` branch (required for all feature/fix PRs)
- [ ] This PR targets `main` (hotfix only - maintainers)
## Description
<!-- What does this PR do? 2-3 sentences -->
## Related Issue
Closes #
## Type of Change
- [ ] Bug fix (non-breaking change that fixes an issue)
- [ ] New feature (non-breaking change that adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
- [ ] Documentation update
- [ ] Refactoring (no functional changes)
- [ ] Tests (adding or updating tests)
- [ ] 🐛 Bug fix
- [ ] New feature
- [ ] 📚 Documentation
- [ ] ♻️ Refactor
- [ ] 🧪 Test
## Related Issues
## Area
<!-- Link any related issues: Fixes #123, Closes #456 -->
- [ ] Frontend
- [ ] Backend
- [ ] Fullstack
## Changes Made
## Commit Message Format
<!-- List the main changes in this PR -->
Follow conventional commits: `<type>: <subject>`
-
-
-
**Types:** feat, fix, docs, style, refactor, test, chore
## Screenshots
<!-- If applicable, add screenshots for UI changes -->
**Example:** `feat: add user authentication system`
## Checklist
- [ ] I have run `pre-commit run --all-files` and fixed any issues
- [ ] I have added tests for my changes (if applicable)
- [ ] All existing tests pass locally
- [ ] I have updated documentation (if applicable)
- [ ] My code follows the project's code style
- [ ] I've synced with `develop` branch
- [ ] I've tested my changes locally
- [ ] I've followed the code principles (SOLID, DRY, KISS)
- [ ] My PR is small and focused (< 400 lines ideally)
## Testing
## CI/Testing Requirements
<!-- Describe how you tested these changes -->
- [ ] All CI checks pass
- [ ] All existing tests pass
- [ ] New features include test coverage
- [ ] Bug fixes include regression tests
## Additional Notes
## Screenshots
<!-- Any additional context or notes for reviewers -->
<!-- Required for UI changes. Delete if not applicable. -->
| Before | After |
|--------|-------|
| | |
## Feature Toggle
<!-- If feature is incomplete or experimental, how is it hidden from users? -->
<!-- This ensures incomplete work can be merged without affecting production. -->
- [ ] Behind localStorage flag: `use_feature_name`
- [ ] Behind settings toggle
- [ ] Behind environment variable/config
- [ ] N/A - Feature is complete and ready for all users
## Breaking Changes
<!-- Does this PR introduce breaking changes? If yes, describe what breaks and migration steps. -->
<!-- Delete this section if not applicable. -->
**Breaking:** Yes / No
**Details:**
<!-- What breaks? What do users/developers need to change? -->
+53
View File
@@ -0,0 +1,53 @@
name: Auto Label
on:
issues:
types: [opened]
jobs:
label-area:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Add area label from form
uses: actions/github-script@v7
with:
script: |
const issue = context.payload.issue;
const body = issue.body || '';
console.log(`Processing issue #${issue.number}: ${issue.title}`);
// Map form selection to label
const areaMap = {
'Frontend': 'area/frontend',
'Backend': 'area/backend',
'Fullstack': 'area/fullstack'
};
const labels = [];
for (const [key, label] of Object.entries(areaMap)) {
if (body.includes(key)) {
console.log(`Found area: ${key}, adding label: ${label}`);
labels.push(label);
break;
}
}
if (labels.length > 0) {
try {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
labels: labels
});
console.log(`Successfully added labels: ${labels.join(', ')}`);
} catch (error) {
core.setFailed(`Failed to add labels: ${error.message}`);
}
} else {
console.log('No matching area found in issue body');
}
+389
View File
@@ -0,0 +1,389 @@
name: Beta Release
# Manual trigger for beta releases from develop branch
on:
workflow_dispatch:
inputs:
version:
description: 'Beta version (e.g., 2.8.0-beta.1)'
required: true
type: string
dry_run:
description: 'Test build without creating release'
required: false
default: false
type: boolean
jobs:
validate-version:
name: Validate beta version format
runs-on: ubuntu-latest
steps:
- name: Validate version format
run: |
VERSION="${{ github.event.inputs.version }}"
# Check if version matches beta semver pattern
if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+-(beta|alpha|rc)\.[0-9]+$ ]]; then
echo "::error::Invalid version format: $VERSION"
echo "Version must match pattern: X.Y.Z-beta.N (e.g., 2.8.0-beta.1)"
exit 1
fi
echo "Valid beta version: $VERSION"
update-version:
name: Update package.json version
needs: validate-version
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
steps:
- uses: actions/checkout@v4
with:
ref: develop
token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '24'
- name: Update package.json version
id: version
run: |
VERSION="${{ github.event.inputs.version }}"
# Update frontend package.json
cd apps/frontend
npm version "$VERSION" --no-git-tag-version
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Updated package.json to version $VERSION"
- name: Commit version bump
if: ${{ github.event.inputs.dry_run != 'true' }}
run: |
VERSION="${{ github.event.inputs.version }}"
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
# Stage all changed files in frontend directory (handles package-lock.json if it exists)
git add -A apps/frontend/
git commit -m "chore: bump version to $VERSION for beta release"
git push origin develop
- name: Create and push tag
if: ${{ github.event.inputs.dry_run != 'true' }}
run: |
VERSION="${{ github.event.inputs.version }}"
git tag -a "v$VERSION" -m "Beta release v$VERSION"
git push origin "v$VERSION"
echo "Created tag v$VERSION"
# Intel build on Intel runner for native compilation
build-macos-intel:
needs: update-version
runs-on: macos-15-intel
steps:
- uses: actions/checkout@v4
with:
ref: v${{ needs.update-version.outputs.version }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '24'
- name: Get npm cache directory
id: npm-cache
run: echo "dir=$(npm config get cache)" >> $GITHUB_OUTPUT
- uses: actions/cache@v4
with:
path: ${{ steps.npm-cache.outputs.dir }}
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
restore-keys: ${{ runner.os }}-npm-
- name: Install dependencies
run: cd apps/frontend && npm ci
- name: Build application
run: cd apps/frontend && npm run build
- name: Package macOS (Intel)
run: cd apps/frontend && npm run package:mac -- --arch=x64
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CSC_LINK: ${{ secrets.MAC_CERTIFICATE }}
CSC_KEY_PASSWORD: ${{ secrets.MAC_CERTIFICATE_PASSWORD }}
- name: Notarize macOS Intel app
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
run: |
if [ -z "$APPLE_ID" ]; then
echo "Skipping notarization: APPLE_ID not configured"
exit 0
fi
cd apps/frontend
for dmg in dist/*.dmg; do
echo "Notarizing $dmg..."
xcrun notarytool submit "$dmg" \
--apple-id "$APPLE_ID" \
--password "$APPLE_APP_SPECIFIC_PASSWORD" \
--team-id "$APPLE_TEAM_ID" \
--wait
xcrun stapler staple "$dmg"
echo "Successfully notarized and stapled $dmg"
done
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: macos-intel-builds
path: |
apps/frontend/dist/*.dmg
apps/frontend/dist/*.zip
# Apple Silicon build on ARM64 runner for native compilation
build-macos-arm64:
needs: update-version
runs-on: macos-15
steps:
- uses: actions/checkout@v4
with:
ref: v${{ needs.update-version.outputs.version }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '24'
- name: Get npm cache directory
id: npm-cache
run: echo "dir=$(npm config get cache)" >> $GITHUB_OUTPUT
- uses: actions/cache@v4
with:
path: ${{ steps.npm-cache.outputs.dir }}
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
restore-keys: ${{ runner.os }}-npm-
- name: Install dependencies
run: cd apps/frontend && npm ci
- name: Build application
run: cd apps/frontend && npm run build
- name: Package macOS (Apple Silicon)
run: cd apps/frontend && npm run package:mac -- --arch=arm64
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CSC_LINK: ${{ secrets.MAC_CERTIFICATE }}
CSC_KEY_PASSWORD: ${{ secrets.MAC_CERTIFICATE_PASSWORD }}
- name: Notarize macOS ARM64 app
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
run: |
if [ -z "$APPLE_ID" ]; then
echo "Skipping notarization: APPLE_ID not configured"
exit 0
fi
cd apps/frontend
for dmg in dist/*.dmg; do
echo "Notarizing $dmg..."
xcrun notarytool submit "$dmg" \
--apple-id "$APPLE_ID" \
--password "$APPLE_APP_SPECIFIC_PASSWORD" \
--team-id "$APPLE_TEAM_ID" \
--wait
xcrun stapler staple "$dmg"
echo "Successfully notarized and stapled $dmg"
done
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: macos-arm64-builds
path: |
apps/frontend/dist/*.dmg
apps/frontend/dist/*.zip
build-windows:
needs: update-version
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
with:
ref: v${{ needs.update-version.outputs.version }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '24'
- name: Get npm cache directory
id: npm-cache
shell: bash
run: echo "dir=$(npm config get cache)" >> $GITHUB_OUTPUT
- uses: actions/cache@v4
with:
path: ${{ steps.npm-cache.outputs.dir }}
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
restore-keys: ${{ runner.os }}-npm-
- name: Install dependencies
run: cd apps/frontend && npm ci
- name: Build application
run: cd apps/frontend && npm run build
- name: Package Windows
run: cd apps/frontend && npm run package:win
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CSC_LINK: ${{ secrets.WIN_CERTIFICATE }}
CSC_KEY_PASSWORD: ${{ secrets.WIN_CERTIFICATE_PASSWORD }}
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: windows-builds
path: |
apps/frontend/dist/*.exe
build-linux:
needs: update-version
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: v${{ needs.update-version.outputs.version }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '24'
- name: Get npm cache directory
id: npm-cache
run: echo "dir=$(npm config get cache)" >> $GITHUB_OUTPUT
- uses: actions/cache@v4
with:
path: ${{ steps.npm-cache.outputs.dir }}
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
restore-keys: ${{ runner.os }}-npm-
- name: Install dependencies
run: cd apps/frontend && npm ci
- name: Build application
run: cd apps/frontend && npm run build
- name: Package Linux
run: cd apps/frontend && npm run package:linux
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: linux-builds
path: |
apps/frontend/dist/*.AppImage
apps/frontend/dist/*.deb
create-release:
needs: [update-version, build-macos-intel, build-macos-arm64, build-windows, build-linux]
runs-on: ubuntu-latest
if: ${{ github.event.inputs.dry_run != 'true' }}
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
ref: v${{ needs.update-version.outputs.version }}
fetch-depth: 0
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: dist
- name: Flatten and validate artifacts
run: |
mkdir -p release-assets
find dist -type f \( -name "*.dmg" -o -name "*.zip" -o -name "*.exe" -o -name "*.AppImage" -o -name "*.deb" \) -exec cp {} release-assets/ \;
# Validate that at least one artifact was copied
artifact_count=$(find release-assets -type f \( -name "*.dmg" -o -name "*.zip" -o -name "*.exe" -o -name "*.AppImage" -o -name "*.deb" \) | wc -l)
if [ "$artifact_count" -eq 0 ]; then
echo "::error::No build artifacts found! Expected .dmg, .zip, .exe, .AppImage, or .deb files."
exit 1
fi
echo "Found $artifact_count artifact(s):"
ls -la release-assets/
- name: Generate checksums
run: |
cd release-assets
sha256sum ./* > checksums.sha256
cat checksums.sha256
- name: Create Beta Release
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ needs.update-version.outputs.version }}
name: v${{ needs.update-version.outputs.version }} (Beta)
body: |
## Beta Release v${{ needs.update-version.outputs.version }}
This is a **beta release** for testing new features. It may contain bugs or incomplete functionality.
### How to opt-in to beta updates
1. Open Auto Claude
2. Go to Settings > Updates
3. Enable "Beta Updates" toggle
### Reporting Issues
Please report any issues at https://github.com/AndyMik90/Auto-Claude/issues
---
**Full Changelog**: https://github.com/${{ github.repository }}/compare/main...v${{ needs.update-version.outputs.version }}
files: release-assets/*
draft: false
prerelease: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
dry-run-summary:
needs: [update-version, build-macos-intel, build-macos-arm64, build-windows, build-linux]
runs-on: ubuntu-latest
if: ${{ github.event.inputs.dry_run == 'true' }}
steps:
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: dist
- name: Dry run summary
run: |
echo "## Beta Release Dry Run Complete" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Version:** ${{ needs.update-version.outputs.version }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Build artifacts created successfully:" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
find dist -type f \( -name "*.dmg" -o -name "*.zip" -o -name "*.exe" -o -name "*.AppImage" -o -name "*.deb" \) >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "To create a real release, run this workflow again with dry_run unchecked." >> $GITHUB_STEP_SUMMARY
+109
View File
@@ -0,0 +1,109 @@
name: Prepare Release
# Triggers when code is pushed to main (e.g., merging develop → main)
# If package.json version is newer than the latest tag, creates a new tag
# which then triggers the release.yml workflow
on:
push:
branches: [main]
paths:
- 'apps/frontend/package.json'
- 'package.json'
jobs:
check-and-tag:
runs-on: ubuntu-latest
permissions:
contents: write
outputs:
should_release: ${{ steps.check.outputs.should_release }}
new_version: ${{ steps.check.outputs.new_version }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Get package version
id: package
run: |
VERSION=$(node -p "require('./apps/frontend/package.json').version")
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Package version: $VERSION"
- name: Get latest tag version
id: latest_tag
run: |
# Get the latest version tag (v*)
LATEST_TAG=$(git tag -l 'v*' --sort=-version:refname | head -n1)
if [ -z "$LATEST_TAG" ]; then
echo "No existing tags found"
echo "version=0.0.0" >> $GITHUB_OUTPUT
else
# Remove 'v' prefix
LATEST_VERSION=${LATEST_TAG#v}
echo "version=$LATEST_VERSION" >> $GITHUB_OUTPUT
echo "Latest tag: $LATEST_TAG (version: $LATEST_VERSION)"
fi
- name: Check if release needed
id: check
run: |
PACKAGE_VERSION="${{ steps.package.outputs.version }}"
LATEST_VERSION="${{ steps.latest_tag.outputs.version }}"
echo "Comparing: package=$PACKAGE_VERSION vs latest_tag=$LATEST_VERSION"
# Use sort -V for version comparison
HIGHER=$(printf '%s\n%s' "$PACKAGE_VERSION" "$LATEST_VERSION" | sort -V | tail -n1)
if [ "$HIGHER" = "$PACKAGE_VERSION" ] && [ "$PACKAGE_VERSION" != "$LATEST_VERSION" ]; then
echo "should_release=true" >> $GITHUB_OUTPUT
echo "new_version=$PACKAGE_VERSION" >> $GITHUB_OUTPUT
echo "✅ New release needed: v$PACKAGE_VERSION"
else
echo "should_release=false" >> $GITHUB_OUTPUT
echo "⏭️ No release needed (package version not newer than latest tag)"
fi
- name: Create and push tag
if: steps.check.outputs.should_release == 'true'
run: |
VERSION="${{ steps.check.outputs.new_version }}"
TAG="v$VERSION"
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
echo "Creating tag: $TAG"
git tag -a "$TAG" -m "Release $TAG"
git push origin "$TAG"
echo "✅ Tag $TAG created and pushed"
echo "🚀 This will trigger the release workflow"
- name: Summary
run: |
if [ "${{ steps.check.outputs.should_release }}" = "true" ]; then
echo "## 🚀 Release Triggered" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Version:** v${{ steps.check.outputs.new_version }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "The release workflow has been triggered and will:" >> $GITHUB_STEP_SUMMARY
echo "1. Build binaries for all platforms" >> $GITHUB_STEP_SUMMARY
echo "2. Generate changelog from PRs" >> $GITHUB_STEP_SUMMARY
echo "3. Create GitHub release" >> $GITHUB_STEP_SUMMARY
echo "4. Update README with new version" >> $GITHUB_STEP_SUMMARY
else
echo "## ⏭️ No Release Needed" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Package version:** ${{ steps.package.outputs.version }}" >> $GITHUB_STEP_SUMMARY
echo "**Latest tag:** v${{ steps.latest_tag.outputs.version }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "The package version is not newer than the latest tag." >> $GITHUB_STEP_SUMMARY
echo "To trigger a release, bump the version using:" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`bash" >> $GITHUB_STEP_SUMMARY
echo "node scripts/bump-version.js patch # or minor/major" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
fi
+49
View File
@@ -431,3 +431,52 @@ jobs:
prerelease: ${{ contains(github.ref, 'beta') || contains(github.ref, 'alpha') }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Update README with new version after successful release
update-readme:
needs: [create-release]
runs-on: ubuntu-latest
if: ${{ github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.dry_run != true) }}
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
ref: main
token: ${{ secrets.GITHUB_TOKEN }}
- name: Extract version from tag
id: version
run: |
# Extract version from tag (v2.7.2 -> 2.7.2)
VERSION=${GITHUB_REF_NAME#v}
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Updating README to version: $VERSION"
- name: Update README.md
run: |
VERSION="${{ steps.version.outputs.version }}"
# Update version badge: version-X.Y.Z-blue
sed -i "s/version-[0-9]*\.[0-9]*\.[0-9]*-blue/version-${VERSION}-blue/g" README.md
# Update download links: Auto-Claude-X.Y.Z
sed -i "s/Auto-Claude-[0-9]*\.[0-9]*\.[0-9]*/Auto-Claude-${VERSION}/g" README.md
echo "README.md updated to version $VERSION"
grep -E "(version-|Auto-Claude-)" README.md | head -10
- name: Commit and push README update
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
# Check if there are changes to commit
if git diff --quiet README.md; then
echo "No changes to README.md, skipping commit"
exit 0
fi
git add README.md
git commit -m "docs: update README to v${{ steps.version.outputs.version }} [skip ci]"
git push origin main
+25
View File
@@ -0,0 +1,25 @@
name: Stale Issues
on:
schedule:
- cron: '0 0 * * 0' # Every Sunday
workflow_dispatch:
jobs:
stale:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- uses: actions/stale@v9
with:
stale-issue-message: |
This issue has been inactive for 60 days. It will be closed in 14 days if there's no activity.
- If this is still relevant, please comment or update the issue
- If you're working on this, add the `in-progress` label
close-issue-message: 'Closed due to inactivity. Feel free to reopen if still relevant.'
stale-issue-label: 'stale'
days-before-stale: 60
days-before-close: 14
exempt-issue-labels: 'priority/critical,priority/high,in-progress,blocked'
+33
View File
@@ -0,0 +1,33 @@
name: Welcome
on:
pull_request_target:
types: [opened]
issues:
types: [opened]
jobs:
welcome:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/first-interaction@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
issue-message: |
👋 Thanks for opening your first issue!
A maintainer will triage this soon. In the meantime:
- Make sure you've provided all the requested info
- Join our [Discord](https://discord.gg/KCXaPBr4Dj) for faster help
pr-message: |
🎉 Thanks for your first PR!
A maintainer will review it soon. Please make sure:
- Your branch is synced with `main`
- CI checks pass
- You've followed our [contribution guide](CONTRIBUTING.md)
Welcome to the Auto-Claude community!
+10 -5
View File
@@ -103,15 +103,20 @@ python apps/backend/validate_spec.py --spec-dir apps/backend/specs/001-feature -
### Releases
```bash
# Automated version bump and release (recommended)
# 1. Bump version on your branch (creates commit, no tag)
node scripts/bump-version.js patch # 2.8.0 -> 2.8.1
node scripts/bump-version.js minor # 2.8.0 -> 2.9.0
node scripts/bump-version.js major # 2.8.0 -> 3.0.0
node scripts/bump-version.js 2.9.0 # Set specific version
# Then push to trigger GitHub release workflows
git push origin main
git push origin v2.9.0
# 2. Push and create PR to main
git push origin your-branch
gh pr create --base main
# 3. Merge PR → GitHub Actions automatically:
# - Creates tag
# - Builds all platforms
# - Creates release with changelog
# - Updates README
```
See [RELEASE.md](RELEASE.md) for detailed release process documentation.
+29
View File
@@ -491,6 +491,35 @@ git branch -d release/v2.8.0
git push origin --delete release/v2.8.0
```
### Beta Release Process (Maintainers)
Beta releases allow users to test new features before they're included in a stable release. Beta releases are published from the `develop` branch.
**Creating a Beta Release:**
1. Go to **Actions****Beta Release** workflow in GitHub
2. Click **Run workflow**
3. Enter the beta version (e.g., `2.8.0-beta.1`)
4. Optionally enable dry run to test without publishing
5. Click **Run workflow**
The workflow will:
- Validate the version format
- Update `package.json` on develop
- Create and push a tag (e.g., `v2.8.0-beta.1`)
- Build installers for all platforms
- Create a GitHub pre-release
**Version Format:**
```
X.Y.Z-beta.N (e.g., 2.8.0-beta.1, 2.8.0-beta.2)
X.Y.Z-alpha.N (e.g., 2.8.0-alpha.1)
X.Y.Z-rc.N (e.g., 2.8.0-rc.1)
```
**For Users:**
Users can opt into beta updates in Settings → Updates → "Beta Updates" toggle. When enabled, the app will check for and install beta versions. Users can switch back to stable at any time.
### Hotfix Workflow
For urgent production fixes that can't wait for the normal release cycle:
+6 -6
View File
@@ -4,7 +4,7 @@
![Auto Claude Kanban Board](.github/assets/Auto-Claude-Kanban.png)
[![Version](https://img.shields.io/badge/version-2.7.2-blue?style=flat-square)](https://github.com/AndyMik90/Auto-Claude/releases/latest)
[![Version](https://img.shields.io/badge/version-2.7.1-blue?style=flat-square)](https://github.com/AndyMik90/Auto-Claude/releases/latest)
[![License](https://img.shields.io/badge/license-AGPL--3.0-green?style=flat-square)](./agpl-3.0.txt)
[![Discord](https://img.shields.io/badge/Discord-Join%20Community-5865F2?style=flat-square&logo=discord&logoColor=white)](https://discord.gg/KCXaPBr4Dj)
[![CI](https://img.shields.io/github/actions/workflow/status/AndyMik90/Auto-Claude/ci.yml?branch=main&style=flat-square&label=CI)](https://github.com/AndyMik90/Auto-Claude/actions)
@@ -17,11 +17,11 @@ Get the latest pre-built release for your platform:
| Platform | Download | Notes |
|----------|----------|-------|
| **Windows** | [Auto-Claude-2.7.2.exe](https://github.com/AndyMik90/Auto-Claude/releases/latest) | Installer (NSIS) |
| **macOS (Apple Silicon)** | [Auto-Claude-2.7.2-arm64.dmg](https://github.com/AndyMik90/Auto-Claude/releases/latest) | M1/M2/M3 Macs |
| **macOS (Intel)** | [Auto-Claude-2.7.2-x64.dmg](https://github.com/AndyMik90/Auto-Claude/releases/latest) | Intel Macs |
| **Linux** | [Auto-Claude-2.7.2.AppImage](https://github.com/AndyMik90/Auto-Claude/releases/latest) | Universal |
| **Linux (Debian)** | [Auto-Claude-2.7.2.deb](https://github.com/AndyMik90/Auto-Claude/releases/latest) | Ubuntu/Debian |
| **Windows** | [Auto-Claude-2.7.1.exe](https://github.com/AndyMik90/Auto-Claude/releases/latest) | Installer (NSIS) |
| **macOS (Apple Silicon)** | [Auto-Claude-2.7.1-arm64.dmg](https://github.com/AndyMik90/Auto-Claude/releases/latest) | M1/M2/M3 Macs |
| **macOS (Intel)** | [Auto-Claude-2.7.1-x64.dmg](https://github.com/AndyMik90/Auto-Claude/releases/latest) | Intel Macs |
| **Linux** | [Auto-Claude-2.7.1.AppImage](https://github.com/AndyMik90/Auto-Claude/releases/latest) | Universal |
| **Linux (Debian)** | [Auto-Claude-2.7.1.deb](https://github.com/AndyMik90/Auto-Claude/releases/latest) | Ubuntu/Debian |
> All releases include SHA256 checksums and VirusTotal scan results for security verification.
+188
View File
@@ -0,0 +1,188 @@
# Release Process
This document describes how releases are created for Auto Claude.
## Overview
Auto Claude uses an automated release pipeline that ensures releases are only published after all builds succeed. This prevents version mismatches between documentation and actual releases.
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ RELEASE FLOW │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ develop branch main branch │
│ ────────────── ─────────── │
│ │ │ │
│ │ 1. bump-version.js │ │
│ │ (creates commit) │ │
│ │ │ │
│ ▼ │ │
│ ┌─────────┐ │ │
│ │ v2.8.0 │ 2. Create PR │ │
│ │ commit │ ────────────────────► │ │
│ └─────────┘ │ │
│ │ │
│ 3. Merge PR ▼ │
│ ┌──────────┐ │
│ │ v2.8.0 │ │
│ │ on main │ │
│ └────┬─────┘ │
│ │ │
│ ┌───────────────────┴───────────────────┐ │
│ │ GitHub Actions (automatic) │ │
│ ├───────────────────────────────────────┤ │
│ │ 4. prepare-release.yml │ │
│ │ - Detects version > latest tag │ │
│ │ - Creates tag v2.8.0 │ │
│ │ │ │
│ │ 5. release.yml (triggered by tag) │ │
│ │ - Builds macOS (Intel + ARM) │ │
│ │ - Builds Windows │ │
│ │ - Builds Linux │ │
│ │ - Generates changelog │ │
│ │ - Creates GitHub release │ │
│ │ - Updates README │ │
│ └───────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
```
## For Maintainers: Creating a Release
### Step 1: Bump the Version
On your development branch (typically `develop` or a feature branch):
```bash
# Navigate to project root
cd /path/to/auto-claude
# Bump version (choose one)
node scripts/bump-version.js patch # 2.7.1 -> 2.7.2 (bug fixes)
node scripts/bump-version.js minor # 2.7.1 -> 2.8.0 (new features)
node scripts/bump-version.js major # 2.7.1 -> 3.0.0 (breaking changes)
node scripts/bump-version.js 2.8.0 # Set specific version
```
This will:
- Update `apps/frontend/package.json`
- Update `package.json` (root)
- Update `apps/backend/__init__.py`
- Create a commit with message `chore: bump version to X.Y.Z`
### Step 2: Push and Create PR
```bash
# Push your branch
git push origin your-branch
# Create PR to main (via GitHub UI or gh CLI)
gh pr create --base main --title "Release v2.8.0"
```
### Step 3: Merge to Main
Once the PR is approved and merged to `main`, GitHub Actions will automatically:
1. **Detect the version bump** (`prepare-release.yml`)
2. **Create a git tag** (e.g., `v2.8.0`)
3. **Trigger the release workflow** (`release.yml`)
4. **Build binaries** for all platforms:
- macOS Intel (x64) - code signed & notarized
- macOS Apple Silicon (arm64) - code signed & notarized
- Windows (NSIS installer) - code signed
- Linux (AppImage + .deb)
5. **Generate changelog** from merged PRs (using release-drafter)
6. **Scan binaries** with VirusTotal
7. **Create GitHub release** with all artifacts
8. **Update README** with new version badge and download links
### Step 4: Verify
After merging, check:
- [GitHub Actions](https://github.com/AndyMik90/Auto-Claude/actions) - ensure all workflows pass
- [Releases](https://github.com/AndyMik90/Auto-Claude/releases) - verify release was created
- [README](https://github.com/AndyMik90/Auto-Claude#download) - confirm version updated
## Version Numbering
We follow [Semantic Versioning](https://semver.org/):
- **MAJOR** (X.0.0): Breaking changes, incompatible API changes
- **MINOR** (0.X.0): New features, backwards compatible
- **PATCH** (0.0.X): Bug fixes, backwards compatible
## Changelog Generation
Changelogs are automatically generated from merged PRs using [Release Drafter](https://github.com/release-drafter/release-drafter).
### PR Labels for Changelog Categories
| Label | Category |
|-------|----------|
| `feature`, `enhancement` | New Features |
| `bug`, `fix` | Bug Fixes |
| `improvement`, `refactor` | Improvements |
| `documentation` | Documentation |
| (any other) | Other Changes |
**Tip:** Add appropriate labels to your PRs for better changelog organization.
## Workflows
| Workflow | Trigger | Purpose |
|----------|---------|---------|
| `prepare-release.yml` | Push to `main` | Detects version bump, creates tag |
| `release.yml` | Tag `v*` pushed | Builds binaries, creates release |
| `validate-version.yml` | Tag `v*` pushed | Validates tag matches package.json |
| `update-readme` (in release.yml) | After release | Updates README with new version |
## Troubleshooting
### Release didn't trigger after merge
1. Check if version in `package.json` is greater than latest tag:
```bash
git tag -l 'v*' --sort=-version:refname | head -1
cat apps/frontend/package.json | grep version
```
2. Ensure the merge commit touched `package.json`:
```bash
git diff HEAD~1 --name-only | grep package.json
```
### Build failed after tag was created
- The release won't be published if builds fail
- Fix the issue and create a new patch version
- Don't reuse failed version numbers
### README shows wrong version
- README is only updated after successful release
- If release failed, README keeps the previous version (this is intentional)
- Once you successfully release, README will update automatically
## Manual Release (Emergency Only)
In rare cases where you need to bypass the automated flow:
```bash
# Create tag manually (NOT RECOMMENDED)
git tag -a v2.8.0 -m "Release v2.8.0"
git push origin v2.8.0
# This will trigger release.yml directly
```
**Warning:** Only do this if you're certain the version in package.json matches the tag.
## Security
- All macOS binaries are code signed with Apple Developer certificate
- All macOS binaries are notarized by Apple
- Windows binaries are code signed
- All binaries are scanned with VirusTotal
- SHA256 checksums are generated for all artifacts
+22 -1
View File
@@ -30,6 +30,21 @@ const DEBUG_UPDATER = process.env.DEBUG_UPDATER === 'true' || process.env.NODE_E
autoUpdater.autoDownload = true; // Automatically download updates when available
autoUpdater.autoInstallOnAppQuit = true; // Automatically install on app quit
// Update channels: 'latest' for stable, 'beta' for pre-release
type UpdateChannel = 'latest' | 'beta';
/**
* Set the update channel for electron-updater.
* - 'latest': Only receive stable releases (default)
* - 'beta': Receive pre-release/beta versions
*
* @param channel - The update channel to use
*/
export function setUpdateChannel(channel: UpdateChannel): void {
autoUpdater.channel = channel;
console.warn(`[app-updater] Update channel set to: ${channel}`);
}
// Enable more verbose logging in debug mode
if (DEBUG_UPDATER) {
autoUpdater.logger = {
@@ -49,15 +64,21 @@ let mainWindow: BrowserWindow | null = null;
* Should only be called in production (app.isPackaged).
*
* @param window - The main BrowserWindow for sending update events
* @param betaUpdates - Whether to receive beta/pre-release updates
*/
export function initializeAppUpdater(window: BrowserWindow): void {
export function initializeAppUpdater(window: BrowserWindow, betaUpdates = false): void {
mainWindow = window;
// Set update channel based on user preference
const channel = betaUpdates ? 'beta' : 'latest';
setUpdateChannel(channel);
// Log updater configuration
console.warn('[app-updater] ========================================');
console.warn('[app-updater] Initializing app auto-updater');
console.warn('[app-updater] App packaged:', app.isPackaged);
console.warn('[app-updater] Current version:', autoUpdater.currentVersion.version);
console.warn('[app-updater] Update channel:', channel);
console.warn('[app-updater] Auto-download enabled:', autoUpdater.autoDownload);
console.warn('[app-updater] Debug mode:', DEBUG_UPDATER);
console.warn('[app-updater] ========================================');
+18 -1
View File
@@ -9,6 +9,18 @@ import { pythonEnvManager } from './python-env-manager';
import { getUsageMonitor } from './claude-profile/usage-monitor';
import { initializeUsageMonitorForwarding } from './ipc-handlers/terminal-handlers';
import { initializeAppUpdater } from './app-updater';
import { DEFAULT_APP_SETTINGS } from '../shared/constants';
import { readSettingsFile } from './settings-utils';
import type { AppSettings } from '../shared/types';
/**
* Load app settings synchronously (for use during startup).
* This is a simple merge with defaults - no migrations or auto-detection.
*/
function loadSettingsSync(): AppSettings {
const savedSettings = readSettingsFile();
return { ...DEFAULT_APP_SETTINGS, ...savedSettings } as AppSettings;
}
// Get icon path based on platform
function getIconPath(): string {
@@ -168,8 +180,13 @@ app.whenReady().then(() => {
// Initialize app auto-updater (only in production, or when DEBUG_UPDATER is set)
const forceUpdater = process.env.DEBUG_UPDATER === 'true';
if (app.isPackaged || forceUpdater) {
initializeAppUpdater(mainWindow);
// Load settings to get beta updates preference
const settings = loadSettingsSync();
const betaUpdates = settings.betaUpdates ?? false;
initializeAppUpdater(mainWindow, betaUpdates);
console.warn('[main] App auto-updater initialized');
console.warn(`[main] Beta updates: ${betaUpdates ? 'enabled' : 'disabled'}`);
if (forceUpdater && !app.isPackaged) {
console.warn('[main] Updater forced in dev mode via DEBUG_UPDATER=true');
console.warn('[main] Note: Updates won\'t actually work in dev mode');
@@ -1,5 +1,5 @@
import { ipcMain, dialog, app, shell } from 'electron';
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
import { existsSync, writeFileSync, mkdirSync } from 'fs';
import { execSync } from 'child_process';
import path from 'path';
import { is } from '@electron-toolkit/utils';
@@ -11,8 +11,10 @@ import type {
import { AgentManager } from '../agent';
import type { BrowserWindow } from 'electron';
import { getEffectiveVersion } from '../auto-claude-updater';
import { setUpdateChannel } from '../app-updater';
import { getSettingsPath, readSettingsFile } from '../settings-utils';
const settingsPath = path.join(app.getPath('userData'), 'settings.json');
const settingsPath = getSettingsPath();
/**
* Auto-detect the auto-claude source path relative to the app location.
@@ -101,18 +103,11 @@ export function registerSettingsHandlers(
ipcMain.handle(
IPC_CHANNELS.SETTINGS_GET,
async (): Promise<IPCResult<AppSettings>> => {
let settings: AppSettings = { ...DEFAULT_APP_SETTINGS };
// Load settings using shared helper and merge with defaults
const savedSettings = readSettingsFile();
const settings: AppSettings = { ...DEFAULT_APP_SETTINGS, ...savedSettings };
let needsSave = false;
if (existsSync(settingsPath)) {
try {
const content = readFileSync(settingsPath, 'utf-8');
settings = { ...settings, ...JSON.parse(content) };
} catch {
// Use defaults
}
}
// Migration: Set agent profile to 'auto' for users who haven't made a selection (one-time)
// This ensures new users get the optimized 'auto' profile as the default
// while preserving existing user preferences
@@ -151,12 +146,9 @@ export function registerSettingsHandlers(
IPC_CHANNELS.SETTINGS_SAVE,
async (_, settings: Partial<AppSettings>): Promise<IPCResult> => {
try {
let currentSettings = DEFAULT_APP_SETTINGS;
if (existsSync(settingsPath)) {
const content = readFileSync(settingsPath, 'utf-8');
currentSettings = { ...currentSettings, ...JSON.parse(content) };
}
// Load current settings using shared helper
const savedSettings = readSettingsFile();
const currentSettings = { ...DEFAULT_APP_SETTINGS, ...savedSettings };
const newSettings = { ...currentSettings, ...settings };
writeFileSync(settingsPath, JSON.stringify(newSettings, null, 2));
@@ -165,6 +157,12 @@ export function registerSettingsHandlers(
agentManager.configure(settings.pythonPath, settings.autoBuildPath);
}
// Update auto-updater channel if betaUpdates setting changed
if (settings.betaUpdates !== undefined) {
const channel = settings.betaUpdates ? 'beta' : 'latest';
setUpdateChannel(channel);
}
return { success: true };
} catch (error) {
return {
+43
View File
@@ -0,0 +1,43 @@
/**
* Shared settings utilities for main process
*
* This module provides low-level settings file operations used by both
* the main process startup (index.ts) and the IPC handlers (settings-handlers.ts).
*
* NOTE: This module intentionally does NOT perform migrations or auto-detection.
* Those are handled by the IPC handlers where they have full context.
*/
import { app } from 'electron';
import { existsSync, readFileSync } from 'fs';
import path from 'path';
/**
* Get the path to the settings file
*/
export function getSettingsPath(): string {
return path.join(app.getPath('userData'), 'settings.json');
}
/**
* Read and parse settings from disk.
* Returns the raw parsed settings object, or undefined if the file doesn't exist or fails to parse.
*
* This function does NOT merge with defaults or perform any migrations.
* Callers are responsible for merging with DEFAULT_APP_SETTINGS.
*/
export function readSettingsFile(): Record<string, unknown> | undefined {
const settingsPath = getSettingsPath();
if (!existsSync(settingsPath)) {
return undefined;
}
try {
const content = readFileSync(settingsPath, 'utf-8');
return JSON.parse(content);
} catch {
// Return undefined on parse error - caller will use defaults
return undefined;
}
}
@@ -419,6 +419,21 @@ export function AdvancedSettings({ settings, onSettingsChange, section, version
}
/>
</div>
<div className="flex items-center justify-between p-4 rounded-lg border border-border">
<div className="space-y-1">
<Label className="font-medium text-foreground">Beta Updates</Label>
<p className="text-sm text-muted-foreground">
Receive pre-release beta versions with new features (may be less stable)
</p>
</div>
<Switch
checked={settings.betaUpdates ?? false}
onCheckedChange={(checked) =>
onSettingsChange({ ...settings, betaUpdates: checked })
}
/>
</div>
</div>
</SettingsSection>
);
+3 -1
View File
@@ -42,7 +42,9 @@ export const DEFAULT_APP_SETTINGS = {
changelogAudience: 'user-facing' as const,
changelogEmojiLevel: 'none' as const,
// UI Scale (default 100% - standard size)
uiScale: UI_SCALE_DEFAULT
uiScale: UI_SCALE_DEFAULT,
// Beta updates opt-in (receive pre-release versions)
betaUpdates: false
};
// ============================================
@@ -108,6 +108,8 @@ export interface AppSettings {
changelogEmojiLevel?: ChangelogEmojiLevel;
// UI Scale setting (75-200%, default 100)
uiScale?: number;
// Beta updates opt-in (receive pre-release updates)
betaUpdates?: boolean;
// Migration flags (internal use)
_migratedAgentProfileToAuto?: boolean;
}
+30 -38
View File
@@ -3,8 +3,8 @@
/**
* Version Bump Script
*
* Automatically bumps the version in package.json and creates a git tag.
* This ensures version consistency between package.json and git tags.
* Bumps the version in package.json files. When this commit is merged to main,
* GitHub Actions will automatically create the tag and trigger the release.
*
* Usage:
* node scripts/bump-version.js <major|minor|patch|x.y.z>
@@ -14,6 +14,17 @@
* node scripts/bump-version.js minor # 2.5.5 -> 2.6.0
* node scripts/bump-version.js major # 2.5.5 -> 3.0.0
* node scripts/bump-version.js 2.6.0 # Set to specific version
*
* Release Flow:
* 1. Run this script on develop branch
* 2. Push to develop
* 3. Create PR: develop → main
* 4. Merge PR
* 5. GitHub Actions automatically:
* - Creates git tag
* - Builds binaries
* - Creates GitHub release
* - Updates README
*/
const fs = require('fs');
@@ -138,27 +149,6 @@ function updateBackendInit(newVersion) {
return true;
}
// Update README.md version references
function updateReadme(newVersion, oldVersion) {
const readmePath = path.join(__dirname, '..', 'README.md');
if (!fs.existsSync(readmePath)) {
warning(`README.md not found at ${readmePath}, skipping`);
return false;
}
let content = fs.readFileSync(readmePath, 'utf8');
// Update version badge: version-X.Y.Z-blue
content = content.replace(/version-[\d.]+(-\w+)?-blue/g, `version-${newVersion}-blue`);
// Update download links: Auto-Claude-X.Y.Z
content = content.replace(/Auto-Claude-[\d.]+/g, `Auto-Claude-${newVersion}`);
fs.writeFileSync(readmePath, content);
return true;
}
// Main function
function main() {
const bumpType = process.argv[2];
@@ -204,31 +194,33 @@ function main() {
success('Updated apps/backend/__init__.py');
}
info('Updating README.md...');
if (updateReadme(newVersion, currentVersion)) {
success('Updated README.md');
}
// Note: README.md is NOT updated here - it gets updated by the release workflow
// after the GitHub release is successfully published. This prevents version
// mismatches where README shows a version that doesn't exist yet.
// 6. Create git commit
info('Creating git commit...');
exec('git add apps/frontend/package.json package.json apps/backend/__init__.py README.md');
exec('git add apps/frontend/package.json package.json apps/backend/__init__.py');
exec(`git commit -m "chore: bump version to ${newVersion}"`);
success(`Created commit: "chore: bump version to ${newVersion}"`);
// 7. Create git tag
info('Creating git tag...');
exec(`git tag -a v${newVersion} -m "Release v${newVersion}"`);
success(`Created tag: v${newVersion}`);
// Note: Tags are NOT created here anymore. GitHub Actions will create the tag
// when this commit is merged to main, ensuring releases only happen after
// successful builds.
// 8. Instructions
// 7. Instructions
log('\n📋 Next steps:', colors.yellow);
log(` 1. Review the changes: git log -1`, colors.yellow);
log(` 2. Push the commit: git push origin <branch-name>`, colors.yellow);
log(` 3. Push the tag: git push origin v${newVersion}`, colors.yellow);
log(` 4. Create a GitHub release from the tag\n`, colors.yellow);
log(` 2. Push to your branch: git push origin <branch-name>`, colors.yellow);
log(` 3. Create PR to main (or merge develop → main)`, colors.yellow);
log(` 4. When merged, GitHub Actions will automatically:`, colors.yellow);
log(` - Create tag v${newVersion}`, colors.yellow);
log(` - Build binaries for all platforms`, colors.yellow);
log(` - Create GitHub release with changelog`, colors.yellow);
log(` - Update README with new version\n`, colors.yellow);
warning('Note: The commit and tag have been created locally but NOT pushed.');
warning('Please review and push manually when ready.');
warning('Note: The commit has been created locally but NOT pushed.');
info('Tags are created automatically by GitHub Actions when merged to main.');
log('\n✨ Version bump complete!\n', colors.green);
}