diff --git a/apps/wrapper/assets/icon.icns b/apps/wrapper/assets/icon.icns
new file mode 100644
index 00000000..8a9d4aac
Binary files /dev/null and b/apps/wrapper/assets/icon.icns differ
diff --git a/apps/wrapper/package.json b/apps/wrapper/package.json
index 807f88ee..a0efe756 100644
--- a/apps/wrapper/package.json
+++ b/apps/wrapper/package.json
@@ -54,6 +54,9 @@
"dependencies": {
"electron-log": "^5.0.0"
},
+ "optionalDependencies": {
+ "@electron/rcedit": "^4.0.0"
+ },
"devDependencies": {
"electron": "^30.0.0",
"electron-builder": "^24.0.0"
diff --git a/apps/wrapper/src/main.js b/apps/wrapper/src/main.js
index 04ecb891..e1b84b66 100644
--- a/apps/wrapper/src/main.js
+++ b/apps/wrapper/src/main.js
@@ -54,6 +54,10 @@ async function bootstrap() {
}
binary = getVSCodiumBinary(VSCODE_DIR);
+ sendStatus('Customizing appearance…');
+ const { rebrandVSCodium } = require('./rebrand');
+ await rebrandVSCodium(VSCODE_DIR);
+
const os = require('os');
if (process.platform !== 'win32') {
const p = getPlatformInfo();
diff --git a/apps/wrapper/src/rebrand.js b/apps/wrapper/src/rebrand.js
new file mode 100644
index 00000000..d77bf455
--- /dev/null
+++ b/apps/wrapper/src/rebrand.js
@@ -0,0 +1,211 @@
+/**
+ * rebrand.js – Replace VSCodium icons and product names with OCcode branding.
+ *
+ * All operations are non-fatal: failures are logged but never throw.
+ */
+
+const fs = require('fs');
+const path = require('path');
+const { execSync } = require('child_process');
+
+const ASSETS_DIR = path.join(__dirname, '..', 'assets');
+
+/**
+ * Rebrand extracted VSCodium at `vscodeDir` with OCcode icons and names.
+ */
+async function rebrandVSCodium(vscodeDir) {
+ const platform = process.platform; // win32 | darwin | linux
+ console.log(`[rebrand] Rebranding VSCodium for ${platform}…`);
+
+ try {
+ if (platform === 'win32') {
+ await rebrandWindows(vscodeDir);
+ } else if (platform === 'darwin') {
+ await rebrandMacOS(vscodeDir);
+ } else {
+ await rebrandLinux(vscodeDir);
+ }
+ } catch (err) {
+ console.warn('[rebrand] Icon replacement failed (non-fatal):', err.message);
+ }
+
+ try {
+ patchProductJson(vscodeDir);
+ } catch (err) {
+ console.warn('[rebrand] product.json patch failed (non-fatal):', err.message);
+ }
+}
+
+// ── Windows ──────────────────────────────────────────────────────────────────
+
+async function rebrandWindows(vscodeDir) {
+ const root = path.join(vscodeDir, 'VSCodium-win32-x64');
+ const dir = fs.existsSync(root) ? root
+ : findSubdir(vscodeDir, 'win32')
+ || (fs.existsSync(path.join(vscodeDir, 'codium.exe')) ? vscodeDir : null);
+ if (!dir) { console.warn('[rebrand] Windows VSCodium dir not found'); return; }
+
+ // 1. Replace code.ico for file associations
+ const codeIco = path.join(dir, 'resources', 'app', 'resources', 'win32', 'code.ico');
+ const srcIco = path.join(ASSETS_DIR, 'icon.ico');
+ safeCopy(srcIco, codeIco);
+
+ // 2. Patch codium.exe icon via rcedit
+ const exePath = path.join(dir, 'codium.exe');
+ if (fs.existsSync(exePath) && fs.existsSync(srcIco)) {
+ try {
+ const rcedit = require('@electron/rcedit');
+ await rcedit(exePath, { icon: srcIco });
+ console.log('[rebrand] Patched codium.exe icon via rcedit');
+ } catch (err) {
+ console.warn('[rebrand] rcedit patch skipped:', err.message);
+ }
+ }
+}
+
+// ── macOS ────────────────────────────────────────────────────────────────────
+
+async function rebrandMacOS(vscodeDir) {
+ const appBundle = path.join(vscodeDir, 'VSCodium.app');
+ if (!fs.existsSync(appBundle)) {
+ console.warn('[rebrand] VSCodium.app not found'); return;
+ }
+
+ const resourcesDir = path.join(appBundle, 'Contents', 'Resources');
+
+ // Try pre-built .icns first, then generate at runtime
+ const prebuiltIcns = path.join(ASSETS_DIR, 'icon.icns');
+ const targetIcns = path.join(resourcesDir, 'VSCodium.icns');
+
+ if (fs.existsSync(prebuiltIcns)) {
+ safeCopy(prebuiltIcns, targetIcns);
+ } else {
+ // Generate using sips (macOS built-in)
+ const srcPng = path.join(ASSETS_DIR, 'icon.png');
+ try {
+ const tmpIcns = path.join(resourcesDir, 'OCcode.icns');
+ execSync(`sips -s format icns "${srcPng}" --out "${tmpIcns}"`, { stdio: 'pipe' });
+ safeCopy(tmpIcns, targetIcns);
+ console.log('[rebrand] Generated .icns via sips');
+ } catch (err) {
+ console.warn('[rebrand] .icns generation failed:', err.message);
+ }
+ }
+
+ // Update Info.plist icon reference if we renamed
+ const plistPath = path.join(appBundle, 'Contents', 'Info.plist');
+ if (fs.existsSync(plistPath)) {
+ try {
+ let plist = fs.readFileSync(plistPath, 'utf8');
+ // The icon key points to the .icns filename (without extension)
+ // We're replacing VSCodium.icns in-place, so no plist change needed
+ // But update display name
+ plist = plist.replace(/