initial commit

This commit is contained in:
Sreeram Sreedhar 2026-06-21 22:13:57 -07:00
parent cf47d73126
commit 6a4d59ccf5
17 changed files with 367 additions and 0 deletions

13
apps/desktop/.gitignore vendored Normal file
View file

@ -0,0 +1,13 @@
# dependencies
/node_modules
# next.js
/.next/
/out/
# typescript
next-env.d.ts
*.tsbuildinfo
# misc
.DS_Store

28
apps/desktop/README.md Normal file
View file

@ -0,0 +1,28 @@
# @repo/desktop
Supermemory desktop app — a [Tauri v2](https://v2.tauri.app) shell around the
Supermemory web UI (Next.js static export), talking to `api.supermemory.ai`.
Design docs live in `/.context/desktop-app-*.md` (spec, roadmap, architecture).
## Develop
```sh
# from this directory — launches the native window and spawns `next dev` on :3001
bun run tauri dev
```
`bun run dev` on its own just starts the Next dev server on :3001 (no native window).
## Build
```sh
bun run build # Next static export -> ./out (no Rust needed)
bun run tauri build # native .app / .dmg (requires the Rust toolchain)
```
## Prerequisites for the native build
- Rust toolchain (`rustup`) + Xcode Command Line Tools.
- App icons in `src-tauri/icons/` — generate once with
`bun run tauri icon <path-to-1024px.png>`.

View file

@ -0,0 +1,71 @@
:root {
color-scheme: light dark;
font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
sans-serif;
}
* {
box-sizing: border-box;
}
html,
body {
height: 100%;
margin: 0;
}
.screen {
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
background: radial-gradient(125% 125% at 50% 0%, #1b1b2f 0%, #0c0c12 60%);
color: #ececf1;
}
.card {
width: 360px;
padding: 2rem;
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 1rem;
background: rgba(255, 255, 255, 0.04);
text-align: center;
}
.title {
margin: 0;
font-size: 1.5rem;
font-weight: 600;
}
.muted {
margin: 0.25rem 0 1.5rem;
color: #9a9ab0;
font-size: 0.875rem;
}
.info {
display: grid;
gap: 0.5rem;
margin: 0;
}
.row {
display: flex;
justify-content: space-between;
font-size: 0.875rem;
}
.row dt {
color: #9a9ab0;
}
.row dd {
margin: 0;
font-variant-numeric: tabular-nums;
}
.error {
color: #ff6b6b;
font-size: 0.875rem;
}

View file

@ -0,0 +1,15 @@
import type { ReactNode } from "react"
import "./globals.css"
export const metadata = {
title: "Supermemory",
description: "Supermemory Desktop",
}
export default function RootLayout({ children }: { children: ReactNode }) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}

53
apps/desktop/app/page.tsx Normal file
View file

@ -0,0 +1,53 @@
"use client"
import { invoke } from "@tauri-apps/api/core"
import { useEffect, useState } from "react"
type AppInfo = {
name: string
version: string
platform: string
}
export default function Home() {
const [info, setInfo] = useState<AppInfo | null>(null)
const [error, setError] = useState<string | null>(null)
useEffect(() => {
// Call into the Rust core over Tauri's IPC bridge. If this resolves, the
// native layer is alive and wired to the webview — the Phase 0 goal.
invoke<AppInfo>("app_info")
.then(setInfo)
.catch((err) => setError(String(err)))
}, [])
return (
<main className="screen">
<section className="card">
<h1 className="title">Supermemory</h1>
<p className="muted">Desktop · Phase 0</p>
{info ? (
<dl className="info">
<div className="row">
<dt>App</dt>
<dd>{info.name}</dd>
</div>
<div className="row">
<dt>Version</dt>
<dd>{info.version}</dd>
</div>
<div className="row">
<dt>Platform</dt>
<dd>{info.platform}</dd>
</div>
</dl>
) : error ? (
<p className="error">Native bridge error: {error}</p>
) : (
<p className="muted">Connecting to the native core…</p>
)}
</section>
</main>
)
}

5
apps/desktop/biome.json Normal file
View file

@ -0,0 +1,5 @@
{
"root": false,
"extends": "//",
"$schema": "https://biomejs.dev/schemas/2.4.6/schema.json"
}

View file

@ -0,0 +1,14 @@
import type { NextConfig } from "next"
const nextConfig: NextConfig = {
// Tauri serves a static bundle from disk — there is no Node server at runtime,
// so the app is exported to plain HTML/JS/CSS in ./out.
output: "export",
// The static export has no server-side image optimizer.
images: { unoptimized: true },
// Emit `route/index.html` files so the webview can resolve nested routes
// (e.g. /spotlight) directly from the bundled filesystem.
trailingSlash: true,
}
export default nextConfig

24
apps/desktop/package.json Normal file
View file

@ -0,0 +1,24 @@
{
"name": "@repo/desktop",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev --port 3001",
"build": "next build",
"check-types": "tsc --noEmit",
"tauri": "tauri"
},
"dependencies": {
"@tauri-apps/api": "^2",
"next": "^16.0.11",
"react": "^19.2.4",
"react-dom": "^19.2.4"
},
"devDependencies": {
"@tauri-apps/cli": "^2",
"@types/node": "^24.0.4",
"@types/react": "^19.2.9",
"@types/react-dom": "^19.2.3",
"typescript": "^5.8.3"
}
}

5
apps/desktop/src-tauri/.gitignore vendored Normal file
View file

@ -0,0 +1,5 @@
# Rust build output
/target
# Tauri-generated schemas / artifacts
/gen/schemas

View file

@ -0,0 +1,19 @@
[package]
name = "supermemory-desktop"
version = "0.1.0"
description = "Supermemory Desktop"
edition = "2021"
rust-version = "1.77.2"
[lib]
# The app logic lives in a library crate so it can be shared with a future
# mobile target; `main.rs` is a thin binary that calls into it.
name = "supermemory_desktop_lib"
crate-type = ["staticlib", "cdylib", "rlib"]
[build-dependencies]
tauri-build = { version = "2", features = [] }
[dependencies]
tauri = { version = "2", features = [] }
serde = { version = "1", features = ["derive"] }

View file

@ -0,0 +1,3 @@
fn main() {
tauri_build::build()
}

View file

@ -0,0 +1,7 @@
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "default",
"description": "Core capabilities granted to the main window.",
"windows": ["main"],
"permissions": ["core:default"]
}

View file

@ -0,0 +1,32 @@
use serde::Serialize;
/// Identity of the native app, surfaced to the webview over IPC.
/// `rename_all = "camelCase"` makes the JSON keys match the TypeScript `AppInfo`.
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
struct AppInfo {
name: String,
version: String,
platform: String,
}
/// First proof that the webview <-> Rust IPC bridge is wired: the placeholder
/// page calls `invoke("app_info")` on mount and renders the result.
#[tauri::command]
fn app_info() -> AppInfo {
AppInfo {
name: "Supermemory".to_string(),
version: env!("CARGO_PKG_VERSION").to_string(),
platform: std::env::consts::OS.to_string(),
}
}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![app_info])
// Bootstrap failure is unrecoverable (no window, no app), so we abort
// loudly here. This is the one sanctioned `expect` — see roadmap quality bar.
.run(tauri::generate_context!())
.expect("error while running tauri application");
}

View file

@ -0,0 +1,7 @@
// On Windows release builds, prevent a console window from opening alongside
// the app. No-op on macOS/Linux. Kept now so the entry point is cross-platform.
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
fn main() {
supermemory_desktop_lib::run()
}

View file

@ -0,0 +1,40 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "Supermemory",
"version": "0.1.0",
"identifier": "ai.supermemory.desktop",
"build": {
"beforeDevCommand": "bun run dev",
"devUrl": "http://localhost:3001",
"beforeBuildCommand": "bun run build",
"frontendDist": "../out"
},
"app": {
"windows": [
{
"label": "main",
"title": "Supermemory",
"width": 1100,
"height": 720,
"minWidth": 720,
"minHeight": 480,
"titleBarStyle": "Overlay",
"hiddenTitle": true
}
],
"security": {
"csp": null
}
},
"bundle": {
"active": true,
"targets": ["app", "dmg"],
"icon": [
"icons/32x32.png",
"icons/128x128.png",
"icons/128x128@2x.png",
"icons/icon.icns",
"icons/icon.ico"
]
}
}

View file

@ -0,0 +1,17 @@
{
"compilerOptions": {
"incremental": true,
"jsx": "preserve",
"paths": {
"@/*": ["./*"],
"@ui/*": ["../../packages/ui/*"],
"@repo/ui/*": ["../../packages/ui/*"],
"@lib/*": ["../../packages/lib/*"],
"@hooks/*": ["../../packages/hooks/*"]
},
"plugins": [{ "name": "next" }]
},
"exclude": ["node_modules"],
"extends": "@total-typescript/tsconfig/bundler/dom/app",
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"]
}

14
apps/desktop/turbo.json Normal file
View file

@ -0,0 +1,14 @@
{
"$schema": "https://turborepo.com/schema.json",
"extends": ["//"],
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": ["out/**"]
},
"dev": {
"cache": false,
"persistent": true
}
}
}