Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,10 @@
"build:ext": "tsc -b --force && vite build --mode extension && node scripts/zip.mjs",
"lint": "eslint .",
"preview": "vite preview",
"release": "npm run release:patch",
"release:patch": "npm version patch -m \"chore: release v%s\"",
"release:minor": "npm version minor -m \"chore: release v%s\"",
"release:major": "npm version major -m \"chore: release v%s\"",
"version": "node scripts/sync-manifest-version.mjs",
"postversion": "git push --follow-tags"
"release": "node scripts/release.mjs patch",
"release:patch": "node scripts/release.mjs patch",
"release:minor": "node scripts/release.mjs minor",
"release:major": "node scripts/release.mjs major"
},
"dependencies": {
"@ai-sdk/mcp": "^1.0.36",
Expand Down
63 changes: 63 additions & 0 deletions frontend/scripts/release.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import fs from 'fs';
import path from 'path';
import { execSync } from 'child_process';
import { fileURLToPath } from 'url';

// Cuts a release: bump version -> sync manifest -> commit -> tag -> push.
//
// We drive git ourselves instead of letting `npm version` do it, because this
// package lives in a subdirectory (frontend/) of the git repo. In that layout
// `npm version` decides it is "not a git repository" and silently skips the
// commit/tag while still running the version lifecycle scripts — leaving the
// bump uncommitted and untagged. Doing it explicitly here is reliable.
//
// Usage: node scripts/release.mjs [patch|minor|major] (default: patch)

const __dirname = path.dirname(fileURLToPath(import.meta.url));
const rootDir = path.resolve(__dirname, '..');

const type = process.argv[2] || 'patch';
if (!['patch', 'minor', 'major'].includes(type)) {
console.error(`Unknown release type "${type}". Use: patch | minor | major.`);
process.exit(1);
}

const run = (cmd) => execSync(cmd, { cwd: rootDir, stdio: 'inherit' });
const capture = (cmd) => execSync(cmd, { cwd: rootDir }).toString().trim();

// 1. Require a clean working tree so the release commit contains exactly the
// version bump and nothing else (and so we never half-release again).
const dirty = capture('git status --porcelain');
if (dirty) {
console.error('Working tree is not clean. Commit or stash your changes first:\n' + dirty);
process.exit(1);
}

// 2. Bump package.json + package-lock.json only (no git — we handle git below).
run(`npm version ${type} --no-git-tag-version`);

const pkg = JSON.parse(fs.readFileSync(path.join(rootDir, 'package.json'), 'utf8'));
const version = pkg.version;
const tag = `v${version}`;

// 3. Mirror the version into manifest.json.
const manifestPath = path.join(rootDir, 'public', 'manifest.json');
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
manifest.version = version;
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\n');

// 4. Heads-up if no changelog entry exists — the GitHub release notes would
// otherwise fall back to auto-generated commit notes.
const changelog = JSON.parse(fs.readFileSync(path.join(rootDir, 'src', 'changelog.json'), 'utf8'));
if (!changelog.some((e) => e.version === version)) {
console.warn(`\n⚠️ changelog.json has no entry for ${version}. Add one before releasing for proper release notes.`);
}

// 5. Commit, tag, and push (pushing the tag triggers CI to build + release).
console.log(`\n🚀 Releasing ${tag}\n`);
run('git add package.json package-lock.json public/manifest.json');
run(`git commit -m "chore: release ${tag}"`);
run(`git tag -a ${tag} -m "chore: release ${tag}"`);
run('git push --follow-tags');

console.log(`\n🎉 Pushed ${tag}. CI will build the zip and create the GitHub Release.`);
28 changes: 0 additions & 28 deletions frontend/scripts/sync-manifest-version.mjs

This file was deleted.

Loading