Conversation
- Updated the build script in package.json to target browser for preload script. - Removed the getTitlebarStyles function and integrated its logic directly into the createWindow function for better readability. - Enhanced the preload script to set the titlebar height CSS variable more reliably during document loading.
- Added suppressHydrationWarning to the body element in layout.tsx for better hydration management. - Removed the titlebar height setting logic from preload.ts, streamlining the script and improving performance.
- Implemented OAuth callback handling in Electron with new routes for token creation and verification. - Created `electron-callback` and `electron-exchange` API routes to manage session tokens. - Developed `ElectronAuth` page to initiate OAuth flow in the user's browser. - Enhanced `SocialAuthProviders` component to support deep linking for OAuth in Electron. - Configured Electron to handle custom URL protocols for deep link authentication. - Updated Electron main process to manage deep link callbacks and session token injection.
- Added entitlements.mac.plist for macOS app security settings. - Updated electron-builder.yml to include entitlements file and adjusted paths. - Introduced icon.png and a script to generate necessary icon files for macOS. - Added new scripts in package.json for icon generation during the build process.
- Standardized formatting and indentation for better consistency. - Ensured uniformity in the structure of feature and authentication prompts. - Enhanced clarity in the prompt functions by maintaining consistent spacing and alignment.
- Changed GET function in `electron-callback` and `electron-exchange` routes to remove async keyword for improved performance. - Improved code readability by adding braces for conditional statements in `verifySignedToken`. - Updated `social-auth-providers.tsx` for better formatting and clarity. - Added detailed instructions for customizing the Electron app icon in the documentation. - Created a new README file for the Electron app with development and customization guidelines. - Removed `icon.png` from the sync template exclusion list to ensure proper file handling.
- Refactored `ElectronAuth` to handle session checks and redirect users upon authentication. - Introduced `ElectronAuthSuccessClient` for managing successful sign-in and app launching. - Created `SocialAuthProviders` component for streamlined social login options. - Updated `login-form` and `signup-form` to use the new `SocialAuthProviders` component. - Added documentation for the Electron desktop app integration, including setup and authentication details.
- Created a new workflow file `electron-release.yml` to automate the build and release process for macOS, Windows, and Linux. - Configured jobs for each platform to install dependencies using Bun, build the application, and publish it to GitHub. - Set up caching for Bun and node_modules to optimize build times. - Triggered the workflow on tag pushes matching the pattern "electron-v*".
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Reviewer's GuideAdds a first-class Electron desktop app wrapper for the ChatJS Next.js app, including OAuth deep-link auth flow, titlebar-height-aware layout integration, CLI scaffolding support, docs, and CI release automation, plus minor UI copy and prompt helper refactors. Sequence diagram for Electron OAuth deep-link authentication flowsequenceDiagram
actor User
participant ElectronApp as Electron_app
participant Browser as Default_browser
participant Web as Nextjs_web_app
participant OAuth as OAuth_provider
participant ApiCb as api_auth_electron_callback
participant ApiEx as api_auth_electron_exchange
User->>ElectronApp: Click Sign in via browser
ElectronApp->>Browser: open /electron-auth in default browser
Browser->>Web: GET /electron-auth
Web-->>Browser: Render ElectronAuth page with SocialAuthProviders
User->>Browser: Choose provider and sign in
Browser->>OAuth: OAuth login flow
OAuth-->>Browser: Redirect back to web app
Browser->>Web: OAuth callback endpoint
Web-->>Browser: Set better-auth.session_token cookie
Browser->>ApiCb: GET /api/auth/electron-callback
ApiCb->>ApiCb: Read better-auth.session_token cookie
ApiCb->>ApiCb: createSignedToken(sessionToken)
ApiCb-->>Browser: 302 redirect to /electron-auth/success?token=...
Browser->>Web: GET /electron-auth/success?token=...
Web-->>Browser: Render ElectronAuthSuccessClient
Browser->>Browser: window.location = appScheme:///auth/callback?token=...
Browser->>ElectronApp: OS delivers deep link appScheme:///auth/callback?token=...
ElectronApp->>ElectronApp: handleDeepLink(url)
ElectronApp->>ApiEx: GET /api/auth/electron-exchange?token=...
ApiEx->>ApiEx: verifySignedToken(token)
ApiEx-->>ElectronApp: { sessionToken }
ElectronApp->>ElectronApp: Set better-auth.session_token cookie in Electron session
ElectronApp->>Web: Reload BrowserWindow at APP_URL
Web-->>ElectronApp: Authenticated app UI
ElectronApp-->>User: Signed-in desktop experience
Sequence diagram for Electron titlebar height integrationsequenceDiagram
participant Main as Electron_main
participant Preload as Preload_script
participant Renderer as Nextjs_renderer
Main->>Renderer: Create BrowserWindow with titleBarStyle hiddenInset
Main->>Renderer: Inject CSS setting --electron-titlebar-height and body padding
Preload->>Renderer: Expose electronAPI with titlebarHeight
Renderer->>Renderer: ElectronTitlebarOffset useEffect runs
Renderer->>Renderer: Read window.electronAPI.titlebarHeight
Renderer->>Renderer: Set CSS variable --electron-titlebar-height on documentElement
Renderer->>Renderer: RootLayout body style padding-top uses --electron-titlebar-height
Renderer->>Renderer: ElectronTitlebarOffset renders draggable region
Renderer->>Renderer: Sidebar component uses top and height based on --electron-titlebar-height
Flow diagram for CLI create command with optional Electron scaffoldingflowchart TD
U[User runs
npx @chat-js/cli create] --> C[create command]
C --> PName[promptProjectName]
PName --> PGateway[promptGateway]
PGateway --> PFeatures[promptFeatures]
PFeatures --> PAuth[promptAuth]
PAuth --> PElectron[promptElectron
Include Electron desktop app?]
PElectron --> PInstall[promptInstall]
PInstall -->|use template repo| SRepo[scaffoldFromGit]
PInstall -->|use local template| SLocal[scaffoldFromTemplate]
SRepo --> AfterScaffold[Project scaffolding complete]
SLocal --> AfterScaffold
AfterScaffold -->|if withElectron = true| SElec[scaffoldElectron
create electron/ subfolder]
AfterScaffold -->|if withElectron = false| SkipElec[no electron/ folder]
SElec --> Done[Show next steps
including Electron dev instructions]
SkipElec --> Done
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
- Simplified conditional rendering in `ElectronAuthSuccessClient` for better clarity. - Enhanced formatting in `SocialAuthProviders` to maintain consistent code style. - Added braces in `PureUserMessage` to improve readability of conditional logic. - Reformatted `TextMessagePart` for better alignment and consistency in JSX structure.
There was a problem hiding this comment.
Hey - I've found 2 issues, and left some high level feedback:
- There are now multiple places controlling the Electron titlebar offset (inserted CSS in
apps/electron/src/main.ts,ElectronTitlebarOffset,layout.tsx, and the sidebar styles); centralizing this in a single CSS variable/source of truth would reduce the risk of these getting out of sync over time. - In
apps/electron/src/main.ts,app.setAsDefaultProtocolClient(APP_SCHEME)is called unconditionally; consider guarding this for development/portable runs (or checking the return value) to avoid unexpected behavior or errors on platforms where protocol handlers can’t be registered.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- There are now multiple places controlling the Electron titlebar offset (inserted CSS in `apps/electron/src/main.ts`, `ElectronTitlebarOffset`, `layout.tsx`, and the sidebar styles); centralizing this in a single CSS variable/source of truth would reduce the risk of these getting out of sync over time.
- In `apps/electron/src/main.ts`, `app.setAsDefaultProtocolClient(APP_SCHEME)` is called unconditionally; consider guarding this for development/portable runs (or checking the return value) to avoid unexpected behavior or errors on platforms where protocol handlers can’t be registered.
## Individual Comments
### Comment 1
<location path="apps/chat/app/api/auth/electron-callback/route.ts" line_range="19-27" />
<code_context>
+}
+
+export function GET(request: NextRequest) {
+ const sessionToken = request.cookies.get("better-auth.session_token")?.value;
+
+ if (!sessionToken) {
+ return new NextResponse("No active session found after OAuth.", {
+ status: 400,
+ });
+ }
+
+ const token = createSignedToken(sessionToken);
+ const successUrl = new URL("/electron-auth/success", request.url);
+ successUrl.searchParams.set("token", token);
</code_context>
<issue_to_address>
**suggestion:** The cookie name and token-expiry logic are duplicated and could easily drift from the exchange route.
`electron-callback` and `electron-exchange` each hardcode `better-auth.session_token` and separately implement the `{ s, exp }` structure and 60s expiry. A change on one side could silently break Electron auth. Consider extracting the cookie name and signing/verification into a shared helper (e.g. `lib/electron-auth-token.ts`) so the logic stays in sync and the expiry window is easy to adjust.
Suggested implementation:
```typescript
const sessionToken = request.cookies.get(ELECTRON_AUTH_COOKIE_NAME)?.value;
```
```typescript
return signElectronAuthToken(sessionToken);
}
```
To fully implement the suggestion and remove duplication:
1. Create a shared helper at e.g. `apps/chat/lib/electron-auth-token.ts`:
```ts
import crypto from "node:crypto";
import { env } from "@/env.mjs";
export const ELECTRON_AUTH_COOKIE_NAME = "better-auth.session_token";
const ELECTRON_AUTH_TOKEN_TTL_MS = 60_000;
export type ElectronAuthTokenPayload = {
s: string; // session token
exp: number; // expiry timestamp (ms)
};
export function signElectronAuthToken(sessionToken: string): string {
const payload = Buffer.from(
JSON.stringify({ s: sessionToken, exp: Date.now() + ELECTRON_AUTH_TOKEN_TTL_MS } satisfies ElectronAuthTokenPayload)
).toString("base64url");
const sig = crypto
.createHmac("sha256", env.AUTH_SECRET)
.update(payload)
.digest("base64url");
return `${payload}.${sig}`;
}
export function verifyElectronAuthToken(token: string): ElectronAuthTokenPayload | null {
const [payload, sig] = token.split(".");
if (!payload || !sig) return null;
const expectedSig = crypto
.createHmac("sha256", env.AUTH_SECRET)
.update(payload)
.digest("base64url");
if (!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expectedSig))) {
return null;
}
let decoded: ElectronAuthTokenPayload;
try {
decoded = JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
} catch {
return null;
}
if (typeof decoded.exp !== "number" || decoded.exp < Date.now()) {
return null;
}
if (!decoded.s || typeof decoded.s !== "string") {
return null;
}
return decoded;
}
```
2. In `apps/chat/app/api/auth/electron-callback/route.ts`, add an import near the other imports:
```ts
import { ELECTRON_AUTH_COOKIE_NAME, signElectronAuthToken } from "@/lib/electron-auth-token";
```
(Adjust the import path if your alias for `@` differs.)
3. In the corresponding `electron-exchange` route file, replace:
- Mentions of `"better-auth.session_token"` with `ELECTRON_AUTH_COOKIE_NAME`.
- Any inline `{ s, exp }` + HMAC signing logic with `signElectronAuthToken`.
- Any inline verification/expiry logic with `verifyElectronAuthToken`.
4. Remove the now-unused local implementations of signing/verification (and any duplicated TTL constants) from both routes so that all Electron auth token behavior flows through `lib/electron-auth-token.ts`.
</issue_to_address>
### Comment 2
<location path="apps/chat/app/electron-auth/success/client.tsx" line_range="15-21" />
<code_context>
+ const searchParams = useSearchParams();
+ const [launched, setLaunched] = useState(false);
+
+ const openApp = useCallback(() => {
+ const token = searchParams.get("token");
+ if (!token) {
+ return;
+ }
+ window.location.href = `${appScheme}:///auth/callback?token=${encodeURIComponent(token)}`;
+ setLaunched(true);
+ }, [searchParams, appScheme]);
+
</code_context>
<issue_to_address>
**suggestion:** Short token lifetime combined with retry button can lead to opaque failures when the token expires.
With the current 60s token expiry, clicking “Open app again” after waiting on the success page will try to reuse an expired token, and the Electron app only logs an error. This looks like a silent failure to users. Consider either extending the expiry, showing a clear user-facing error when the exchange fails (e.g., an error page), or regenerating a fresh token in this flow (e.g., by re-hitting `electron-callback` instead of reusing the original token).
Suggested implementation:
```typescript
import { useSearchParams } from "next/navigation";
import { useCallback, useEffect, useState } from "react";
import { Button } from "@/components/ui/button";
export function ElectronAuthSuccessClient({
appScheme,
}: {
appScheme: string;
}) {
const searchParams = useSearchParams();
const [launched, setLaunched] = useState(false);
const [tokenExpired, setTokenExpired] = useState(false);
const openApp = useCallback(() => {
const token = searchParams.get("token");
// If there is no token or it has expired, do not attempt to launch the app.
if (!token || tokenExpired) {
return;
}
window.location.href = `${appScheme}:///auth/callback?token=${encodeURIComponent(
token,
)}`;
setLaunched(true);
}, [searchParams, appScheme, tokenExpired]);
useEffect(() => {
// The Electron token currently expires after ~60 seconds.
// To avoid opaque failures when retrying, mark it as expired slightly earlier
// and rely on the UI to inform the user that they need to retry from the app.
const timeoutId = window.setTimeout(() => {
setTokenExpired(true);
}, 55_000);
return () => window.clearTimeout(timeoutId);
}, []);
```
To fully implement the behavior described in your comment, you should also:
1. Ensure the “Open app again” (or equivalent) button uses the new callback:
- Add `onClick={openApp}` to that button.
- Disable it once the token is used or has expired, e.g. `disabled={launched || tokenExpired}`.
2. Provide a clear user-facing message when the token is expired, for example just below the button:
```tsx
{tokenExpired && !launched && (
<p className="mt-2 text-sm text-muted-foreground">
This sign-in link has expired. Please restart sign-in from the Electron app.
</p>
)}
```
3. If you have tests or stories for this component, update them to cover:
- Initial state (button enabled).
- Post-expiry state (button disabled and message visible).
- That `openApp` is a no-op when `tokenExpired` is `true`.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
- Introduced scaffolding for packaging ChatJS apps as native desktop applications for macOS, Windows, and Linux using Electron. - Updated the CLI to prompt users during project creation to include an Electron app, copying a pre-configured `electron/` subfolder with essential files for main process, preload script, system tray, deep-link OAuth flow, and auto-updater. - Enhanced documentation to reflect the new Electron integration and quickstart instructions.
There was a problem hiding this comment.
18 issues found across 36 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/electron/package.json">
<violation number="1" location="apps/electron/package.json:7">
P2: Use a cross-platform icon generation command here. Every build now shells out to Bash, so the documented Windows packaging flow depends on Git Bash before `electron-builder` even runs.</violation>
</file>
<file name="apps/electron/scripts/generate-icons.sh">
<violation number="1" location="apps/electron/scripts/generate-icons.sh:26">
P2: The generated `.icns` is missing the `icon_512x512@2x.png` Retina asset, so the macOS app icon will be lower quality on high-DPI displays.</violation>
</file>
<file name="apps/chat/app/api/auth/electron-exchange/route.ts">
<violation number="1" location="apps/chat/app/api/auth/electron-exchange/route.ts:34">
P1: Tokens with a missing `exp` field bypass the expiration check. `undefined < Date.now()` evaluates to `false`, so the guard never triggers and the token is treated as valid indefinitely. Add an explicit check that `exp` is a number.</violation>
</file>
<file name="apps/electron/src/main.ts">
<violation number="1" location="apps/electron/src/main.ts:64">
P2: Sensitive token is passed as a GET query parameter. Tokens in URLs are commonly captured in server access logs and intermediary proxy logs. Use a POST request with the token in the body to avoid this exposure.</violation>
</file>
<file name="apps/electron/electron-builder.yml">
<violation number="1" location="apps/electron/electron-builder.yml:17">
P1: The publish config points at `chat-js-1`, so release publishing and auto-update checks will hit the wrong GitHub repository.</violation>
</file>
<file name="apps/electron/entitlements.mac.plist">
<violation number="1" location="apps/electron/entitlements.mac.plist:7">
P1: `allow-unsigned-executable-memory` is an unnecessarily broad hardened-runtime exception here. Since `allow-jit` is already enabled above, this extra entitlement only weakens the app’s macOS memory protections.</violation>
</file>
<file name="apps/docs/desktop/electron.mdx">
<violation number="1" location="apps/docs/desktop/electron.mdx:26">
P3: This tree points readers at `build/icon.png`, but the editable source icon is `electron/icon.png`. Following the current layout will have people modifying a generated file that gets overwritten by `generate-icons`.</violation>
<violation number="2" location="apps/docs/desktop/electron.mdx:69">
P2: The auth flow diagram shows the callback route as POST, but the implementation only exposes GET. This will send readers to the wrong endpoint shape when they debug or reimplement the Electron auth flow.</violation>
</file>
<file name="turbo.json">
<violation number="1" location="turbo.json:71">
P2: Include the icon-generation files in this task's inputs so icon changes cannot be skipped by the Turbo cache.</violation>
<violation number="2" location="turbo.json:72">
P2: Add `build/**` to this task's outputs so Turbo restores the generated icon artifacts on cache hits.</violation>
</file>
<file name="apps/chat/components/auth-providers.tsx">
<violation number="1" location="apps/chat/components/auth-providers.tsx:45">
P1: Don't default to the web OAuth buttons before Electron detection completes. In Electron this briefly exposes the exact in-app sign-in flow the new code is trying to avoid, so users can still hit the `state_mismatch` path before the effect runs.</violation>
</file>
<file name=".github/workflows/electron-release.yml">
<violation number="1" location=".github/workflows/electron-release.yml:6">
P2: Validate or inject the Electron app version from the release tag before publishing. Right now a new `electron-v*` tag can still ship `0.1.0` metadata if `apps/electron/package.json` wasn't bumped.</violation>
<violation number="2" location=".github/workflows/electron-release.yml:34">
P1: Publish the macOS build with signing/notarization credentials. Unsigned macOS artifacts won't work reliably with `electron-updater` and are difficult for users to install.</violation>
</file>
<file name="apps/chat/app/api/auth/electron-callback/route.ts">
<violation number="1" location="apps/chat/app/api/auth/electron-callback/route.ts:9">
P1: This token exposes the real session cookie because it's only signed, then passed through query strings. Use an opaque one-time code or encrypted payload instead of embedding `sessionToken` here.</violation>
</file>
<file name="packages/cli/src/helpers/scaffold.ts">
<violation number="1" location="packages/cli/src/helpers/scaffold.ts:37">
P1: Validate or normalize `appScheme` before writing it into the Electron scaffold. Project names can start with digits, but URI schemes cannot, so some generated apps will get a broken deep-link protocol.</violation>
</file>
<file name="apps/chat/app/layout.tsx">
<violation number="1" location="apps/chat/app/layout.tsx:91">
P2: This duplicates the existing Electron titlebar offset logic and creates two sources of truth for the same body padding.</violation>
</file>
<file name="scripts/sync-template.ts">
<violation number="1" location="scripts/sync-template.ts:143">
P2: The Electron template transform is incomplete, so scaffolded apps still ship with hardcoded ChatJS branding.</violation>
</file>
<file name="packages/cli/src/commands/create.ts">
<violation number="1" location="packages/cli/src/commands/create.ts:218">
P2: The printed Electron command is wrong: after step 1 you're already in the project, and this sub-app expects Bun.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| <body className="antialiased"> | ||
| <body | ||
| className="antialiased" | ||
| style={{ paddingTop: "var(--electron-titlebar-height, 0px)" }} |
There was a problem hiding this comment.
P2: This duplicates the existing Electron titlebar offset logic and creates two sources of truth for the same body padding.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/chat/app/layout.tsx, line 91:
<comment>This duplicates the existing Electron titlebar offset logic and creates two sources of truth for the same body padding.</comment>
<file context>
@@ -85,7 +86,12 @@ export default async function RootLayout({
- <body className="antialiased">
+ <body
+ className="antialiased"
+ style={{ paddingTop: "var(--electron-titlebar-height, 0px)" }}
+ suppressHydrationWarning
+ >
</file context>
- Corrected the URL for Zustand documentation to the new location. - Updated the URL for AI Elements to reflect the new site structure.
- Updated `turbo.json` to include additional inputs and outputs for the Electron build process. - Improved token verification logic in `electron-exchange` route to ensure proper type checking. - Revised documentation to clarify the structure of the Electron app, including the handling of the app icon and build files. - Adjusted the `electron-builder.yml` repository name for consistency. - Enhanced icon generation script to support a larger icon size for macOS.
- Updated `SocialAuthProviders` to handle Electron detection more gracefully by rendering nothing until detection completes. - Modified `entitlements.mac.plist` to remove unnecessary keys for improved security. - Enhanced `scaffoldElectron` function to ensure app scheme adheres to URI standards by prefixing with "app-" if necessary.
There was a problem hiding this comment.
1 issue found across 3 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/chat/components/auth-providers.tsx">
<violation number="1" location="apps/chat/components/auth-providers.tsx:61">
P2: Returning `null` here hides all social login buttons on the first render for web users, so the auth section stays blank until hydration/effect completion.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
- Added a step to set the version from the Git tag in the Electron release workflow for macOS, Windows, and Linux. - Updated `scaffoldElectron` function to inject a placeholder in `package.json` for project name consistency. - Improved template synchronization by replacing hardcoded package names in the Electron template files.
There was a problem hiding this comment.
2 issues found across 5 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name=".github/workflows/electron-release.yml">
<violation number="1" location=".github/workflows/electron-release.yml:35">
P1: In `build-win`, this version extraction uses bash syntax even though `windows-latest` runs `run` steps in PowerShell by default, so the Windows release job will fail before publishing.</violation>
</file>
<file name="apps/chat/components/auth-providers.tsx">
<violation number="1" location="apps/chat/components/auth-providers.tsx:50">
P2: This synchronous Electron check still renders the web OAuth buttons during SSR, so Electron clients hydrate to different markup and can flash the wrong auth UI.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| VERSION="${GITHUB_REF_NAME#electron-v}" | ||
| npm version "$VERSION" --no-git-tag-version |
There was a problem hiding this comment.
P1: In build-win, this version extraction uses bash syntax even though windows-latest runs run steps in PowerShell by default, so the Windows release job will fail before publishing.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/electron-release.yml, line 35:
<comment>In `build-win`, this version extraction uses bash syntax even though `windows-latest` runs `run` steps in PowerShell by default, so the Windows release job will fail before publishing.</comment>
<file context>
@@ -29,6 +29,12 @@ jobs:
+ - name: Set version from tag
+ working-directory: apps/electron
+ run: |
+ VERSION="${GITHUB_REF_NAME#electron-v}"
+ npm version "$VERSION" --no-git-tag-version
+
</file context>
| VERSION="${GITHUB_REF_NAME#electron-v}" | |
| npm version "$VERSION" --no-git-tag-version | |
| $VERSION = $env:GITHUB_REF_NAME -replace '^electron-v', '' | |
| npm version $VERSION --no-git-tag-version |
- Introduced a new `electron-builder.config.js` file to replace the deprecated `electron-builder.yml`, streamlining the build configuration for the Electron app. - Added a `branding.json` file to centralize branding information, generated by a new script `write-branding.ts`. - Updated `package.json` to ensure branding script runs during the prebuild step. - Modified configuration imports in the app to utilize the new branding structure for improved consistency.
- Updated the `scaffoldElectron` function to utilize `electron-builder.config.js` instead of `electron-builder.yml`, enhancing the build configuration process. - Removed hardcoded values in template files, replacing them with placeholders for improved flexibility and maintainability. - Added `branding.json` to the excluded files list to streamline template synchronization. - Adjusted the `applyElectronTemplateTransforms` function to rewrite paths in `tsconfig.json` for better compatibility in monorepo setups.
- Revised the `electron.mdx` file to clarify the transition from `electron-builder.yml` to `electron-builder.config.js`, emphasizing the new structure for app name, URL scheme, and production URL management. - Updated instructions for configuring the URL scheme and branding values, highlighting the role of `chat.config.ts` in the prebuild process. - Enhanced clarity on the CLI's automatic pre-filling of GitHub repository details and the implications for app updates.
There was a problem hiding this comment.
4 issues found across 11 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/electron/electron-builder.config.js">
<violation number="1" location="apps/electron/electron-builder.config.js:51">
P1: Add the custom protocol to the Linux build too; otherwise OAuth deep links won't return to the packaged Linux app.</violation>
</file>
<file name="apps/electron/scripts/write-branding.ts">
<violation number="1" location="apps/electron/scripts/write-branding.ts:9">
P1: The generated branding keys do not match what `electron-builder.config.js` reads, so packaging metadata resolves to `undefined`.</violation>
</file>
<file name="packages/cli/src/helpers/scaffold.ts">
<violation number="1" location="packages/cli/src/helpers/scaffold.ts:36">
P1: Removing URI-scheme normalization breaks Electron deep links for project names that start with digits.</violation>
</file>
<file name="apps/docs/desktop/electron.mdx">
<violation number="1" location="apps/docs/desktop/electron.mdx:119">
P2: This line overstates the scaffolded release config: the CLI only derives `repo`; `owner` is still a placeholder that must be edited manually.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| createStartMenuShortcut: true, | ||
| }, | ||
|
|
||
| linux: { |
There was a problem hiding this comment.
P1: Add the custom protocol to the Linux build too; otherwise OAuth deep links won't return to the packaged Linux app.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/electron/electron-builder.config.js, line 51:
<comment>Add the custom protocol to the Linux build too; otherwise OAuth deep links won't return to the packaged Linux app.</comment>
<file context>
@@ -0,0 +1,55 @@
+ createStartMenuShortcut: true,
+ },
+
+ linux: {
+ target: [{ target: "AppImage", arch: ["x64"] }],
+ category: "Network",
</file context>
|
|
||
| writeFileSync( | ||
| resolve(__dirname, "..", "branding.json"), | ||
| JSON.stringify({ appName, appPrefix, appUrl, orgName: organization.name }, null, 2) |
There was a problem hiding this comment.
P1: The generated branding keys do not match what electron-builder.config.js reads, so packaging metadata resolves to undefined.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/electron/scripts/write-branding.ts, line 9:
<comment>The generated branding keys do not match what `electron-builder.config.js` reads, so packaging metadata resolves to `undefined`.</comment>
<file context>
@@ -0,0 +1,12 @@
+
+writeFileSync(
+ resolve(__dirname, "..", "branding.json"),
+ JSON.stringify({ appName, appPrefix, appUrl, orgName: organization.name }, null, 2)
+);
+
</file context>
| await cp(templateDir, destination, { recursive: true }); | ||
|
|
||
| // electron-builder.config.js: inject GitHub publish config | ||
| const builderPath = join(destination, "electron-builder.config.js"); |
There was a problem hiding this comment.
P1: Removing URI-scheme normalization breaks Electron deep links for project names that start with digits.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/cli/src/helpers/scaffold.ts, line 36:
<comment>Removing URI-scheme normalization breaks Electron deep links for project names that start with digits.</comment>
<file context>
@@ -28,32 +28,18 @@ export async function scaffoldElectron(
- const builderPath = join(destination, "electron-builder.yml");
- const appId = `com.example.${opts.projectName}`;
+ // electron-builder.config.js: inject GitHub publish config
+ const builderPath = join(destination, "electron-builder.config.js");
const builder = (await readFile(builderPath, "utf8"))
- .replace("__APP_ID__", appId)
</file context>
| }, | ||
| ``` | ||
|
|
||
| The CLI pre-fills `owner` and `repo` from your project. Updates only run when the app is packaged (`app.isPackaged`). They are skipped in development. |
There was a problem hiding this comment.
P2: This line overstates the scaffolded release config: the CLI only derives repo; owner is still a placeholder that must be edited manually.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/docs/desktop/electron.mdx, line 119:
<comment>This line overstates the scaffolded release config: the CLI only derives `repo`; `owner` is still a placeholder that must be edited manually.</comment>
<file context>
@@ -99,17 +105,18 @@ Closing the window hides it. Use **Quit** from the tray to fully exit.
-Updates only run when the app is packaged (app.isPackaged). They are skipped in development.
+The CLI pre-fills owner and repo from your project. Updates only run when the app is packaged (app.isPackaged). They are skipped in development.
Customization
</file context>
</details>
```suggestion
The CLI pre-fills `repo` from your project, but `owner` remains `your-github-username` and must be updated before releasing. Updates only run when the app is packaged (`app.isPackaged`). They are skipped in development.
Summary by Sourcery
Add an Electron desktop application wrapper for the ChatJS web app, including OAuth deep-link authentication, CLI scaffolding support, and documentation, while adjusting the web UI and templates to integrate cleanly with the desktop environment.
New Features:
Bug Fixes:
Enhancements:
Build:
CI:
Deployment:
Documentation:
Chores:
Summary by cubic
Adds a cross-platform Electron desktop app with deep-link OAuth, tray, auto-updates, and consistent titlebar spacing. Moves build config to
electron-builder.config.jswith a prebuild that writesbranding.jsonfromchat.config.ts, and updates CLI scaffolding and the release workflow.New Features
apps/electronwrapper: hidden title bar, tray menu, single-instance, andelectron-updaterauto-updates; OAuth uses the system browser + custom protocol with/api/auth/electron-callbackand/api/auth/electron-exchange.ElectronTitlebarOffsetand CSS--electron-titlebar-heightfor consistent spacing;SocialAuthProvidersopens the browser in Electron.@chat-js/cli): prompts to include Electron; scaffolds anelectron/folder, injects project/package placeholders and GitHub owner/repo, and adds turbo/root scripts (dev:electron,build:electron,dist:electron).electron-builder.config.js; prebuild writesbranding.jsonfromchat.config.ts; icon generation script; docs updated;.github/workflows/electron-release.ymlbuilds/publishes installers onelectron-v*tags and sets the version from the tag.Migration
AUTH_SECRETin the web app.chat.config.ts; the prebuild writesapps/electron/branding.json, andelectron-builder.config.jsreads from it.owner/repoinapps/electron/electron-builder.config.jsfor releases.apps/electron/icon.png(512×512) and runbun run generate-icons; dev: start the web app, thencd apps/electron && bun install && bun run dev; release: push anelectron-vX.Y.Ztag.Written for commit 6e1216e. Summary will update on new commits.