1234567891011import { execSync } from "child_process";12import { readFileSync, existsSync, mkdirSync, rmSync } from "fs";13import { join } from "path";1415const ROOT = process.cwd();16const CHROME_ONLY = process.argv.includes("--chrome-only");1718const BOLD = "\x1b[1m";19const DIM = "\x1b[2m";20const ACCENT = "\x1b[38;5;208m";21const GREEN = "\x1b[32m";22const RED = "\x1b[31m";23const RESET = "\x1b[0m";2425function run(cmd: string, label?: string) {26 console.log(`\n${ACCENT}▶${RESET} ${label ?? cmd}`);27 execSync(cmd, { stdio: "inherit", cwd: ROOT });28}2930function success(msg: string) {31 console.log(`${GREEN}✓ ${msg}${RESET}`);32}3334function fail(msg: string): never {35 console.error(`${RED}✗ ${msg}${RESET}`);36 process.exit(1);37}3839function check(name: string): string {40 const val = process.env[name];41 if (!val) fail(`${name} not set. Run setup-chrome-release.sh and reload your shell.`);42 return val!;43}44454647console.clear();48console.log("");49console.log(`${ACCENT}${BOLD} ░░ peach release ░░${RESET}`);50console.log("");51525354const manifest = JSON.parse(readFileSync(join(ROOT, "manifest.json"), "utf8"));55const version = manifest.version;56if (!version) fail("Could not read version from manifest.json");57const targets = CHROME_ONLY ? "Chrome" : "Chrome + Firefox";58console.log(`${BOLD}Releasing Peach v${version} to ${targets}${RESET}`);59console.log(`${DIM}Stores update automatically for existing users.${RESET}`);60616263console.log(`\n${BOLD}Checking credentials…${RESET}`);6465const CWS_CLIENT_ID = check("CWS_CLIENT_ID");66const CWS_CLIENT_SECRET = check("CWS_CLIENT_SECRET");67const CWS_REFRESH_TOKEN = check("CWS_REFRESH_TOKEN");68const CWS_EXTENSION_ID = check("CWS_EXTENSION_ID");69const CWS_PUBLISHER_ID = check("PUBLISHER_ID");7071let AMO_JWT_ISSUER = "";72let AMO_JWT_SECRET = "";73if (!CHROME_ONLY) {74 AMO_JWT_ISSUER = check("AMO_JWT_ISSUER");75 AMO_JWT_SECRET = check("AMO_JWT_SECRET");76}7778success("All credentials present");79808182run("npm run ci", "Running CI gate");83success("All tests pass");84858687if (CHROME_ONLY) {88 run("npm run build:chrome", "Building Chrome target");89} else {90 run("npm run build", "Building all targets (Chrome + Firefox + Mobile)");91}92success("Build complete");93949596if (!existsSync(join(ROOT, "artifacts"))) {97 mkdirSync(join(ROOT, "artifacts"));98}99100101102console.log(`\n${ACCENT}${BOLD}Chrome Web Store${RESET}`);103104const chromeZip = join(ROOT, "artifacts", `peach-chrome-${version}.zip`);105if (existsSync(chromeZip)) rmSync(chromeZip);106107run(108 `cd dist-chrome && zip -r "${chromeZip}" . --exclude '*.map' --exclude '.DS_Store' --exclude '__MACOSX/*'`,109 `Packaging Chrome extension → peach-chrome-${version}.zip`,110);111112run(113 [114 `CLIENT_ID="${CWS_CLIENT_ID}"`,115 `CLIENT_SECRET="${CWS_CLIENT_SECRET}"`,116 `REFRESH_TOKEN="${CWS_REFRESH_TOKEN}"`,117 `PUBLISHER_ID="${CWS_PUBLISHER_ID}"`,118 "npx chrome-webstore-upload-cli upload",119 `--source "${chromeZip}"`,120 `--extension-id "${CWS_EXTENSION_ID}"`,121 "--auto-publish",122 ].join(" "),123 "Uploading and publishing to Chrome Web Store",124);125126success(`Chrome v${version} submitted — review typically takes minutes to hours`);127128129130if (!CHROME_ONLY) {131 console.log(`\n${ACCENT}${BOLD}Firefox Add-ons (AMO)${RESET}`);132133 const sourceZip = `peach-source-${version}.zip`;134 run(135 [136 "zip -r",137 sourceZip,138 "src",139 "scripts",140 "public",141 "manifest.json",142 "manifest.firefox.json",143 "package.json",144 "bun.lock",145 "tsconfig.json",146 "vite.config.ts",147 "vite.config.firefox.ts",148 "vite.config.chrome.ts",149 "vite.config.mobile.ts",150 "--exclude 'node_modules/*'",151 "--exclude 'dist-*/*'",152 "--exclude '*.zip'",153 "--exclude '.DS_Store'",154 "--exclude '__MACOSX/*'",155 ].join(" "),156 "Packaging source archive for AMO",157 );158159 run(160 [161 "npx web-ext sign",162 "--source-dir dist-firefox",163 "--artifacts-dir artifacts",164 `--api-key="${AMO_JWT_ISSUER}"`,165 `--api-secret="${AMO_JWT_SECRET}"`,166 "--channel=listed",167 ].join(" "),168 "Signing and submitting to Firefox AMO",169 );170171 rmSync(join(ROOT, sourceZip), { force: true });172173 success(`Firefox v${version} submitted — review typically takes minutes`);174}175176177178console.log("");179console.log(`${ACCENT}${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}`);180console.log(`${ACCENT}${BOLD} Peach v${version} released to ${targets}.${RESET}`);181console.log(`${ACCENT}${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}`);182console.log("");183184if (!CHROME_ONLY) {185 console.log(` Chrome: under review — existing users update automatically`);186 console.log(` Firefox: under review — existing users update automatically`);187} else {188 console.log(` Chrome: under review — existing users update automatically`);189}190191console.log("");192console.log(`${DIM}Check status:${RESET}`);193console.log(` Chrome: https://chrome.google.com/webstore/devconsole`);194if (!CHROME_ONLY) {195 console.log(` Firefox: https://addons.mozilla.org/developers/`);196}197console.log("");