diff --git a/packages/app/index.html b/packages/app/index.html
index 6035771a0f8..e07a15b4121 100644
--- a/packages/app/index.html
+++ b/packages/app/index.html
@@ -7,10 +7,8 @@
content="width=device-width, initial-scale=1, interactive-widget=resizes-content, viewport-fit=cover"
/>
OpenCode
-
-
-
-
+
+
diff --git a/packages/app/manifest.json b/packages/app/manifest.json
new file mode 100644
index 00000000000..91bba66009a
--- /dev/null
+++ b/packages/app/manifest.json
@@ -0,0 +1,24 @@
+{
+ "name": "OpenCode",
+ "short_name": "OpenCode",
+ "id": "/",
+ "start_url": "/",
+ "scope": "/",
+ "icons": [
+ {
+ "src": "/web-app-manifest-192x192.png",
+ "sizes": "192x192",
+ "type": "image/png",
+ "purpose": "any"
+ },
+ {
+ "src": "/web-app-manifest-512x512.png",
+ "sizes": "512x512",
+ "type": "image/png",
+ "purpose": "any"
+ }
+ ],
+ "theme_color": "#080808",
+ "background_color": "#080808",
+ "display": "standalone"
+}
diff --git a/packages/app/public/site.webmanifest b/packages/app/public/site.webmanifest
deleted file mode 120000
index a116d787962..00000000000
--- a/packages/app/public/site.webmanifest
+++ /dev/null
@@ -1 +0,0 @@
-../../ui/src/assets/favicon/site.webmanifest
\ No newline at end of file
diff --git a/packages/app/vite.config.ts b/packages/app/vite.config.ts
index a06a8fa4077..e7be5f9b397 100644
--- a/packages/app/vite.config.ts
+++ b/packages/app/vite.config.ts
@@ -1,7 +1,8 @@
import { sentryVitePlugin } from "@sentry/vite-plugin"
import { fileURLToPath } from "node:url"
import { defineConfig } from "vite"
-import desktopPlugin from "./vite.js"
+import desktopPlugin, { channel } from "./vite.js"
+import { icons } from "./vite.icons"
import { serviceWorker } from "./vite.pwa"
const sentry =
@@ -22,7 +23,12 @@ const sentry =
: false
export default defineConfig({
- plugins: [desktopPlugin, serviceWorker(fileURLToPath(new URL("./dist", import.meta.url))), sentry] as any,
+ plugins: [
+ desktopPlugin,
+ icons(channel),
+ serviceWorker(fileURLToPath(new URL("./dist", import.meta.url))),
+ sentry,
+ ] as any,
server: {
host: "0.0.0.0",
allowedHosts: true,
diff --git a/packages/app/vite.icons.test.ts b/packages/app/vite.icons.test.ts
new file mode 100644
index 00000000000..e55dad870ce
--- /dev/null
+++ b/packages/app/vite.icons.test.ts
@@ -0,0 +1,86 @@
+import { expect, test } from "bun:test"
+import { fetch } from "bun"
+import { build, createServer } from "vite"
+import { icons } from "./vite.icons"
+import manifest from "./manifest.json" with { type: "json" }
+
+test.each(["dev", "beta", "prod", "local"])("bundles %s app icons", async (channel) => {
+ const result = await build({
+ root: import.meta.dirname,
+ configFile: false,
+ logLevel: "silent",
+ plugins: [
+ icons(channel),
+ {
+ name: "icons-only-fixture",
+ transformIndexHtml: {
+ order: "pre",
+ handler: (html) => html.replace(/