diff --git a/src/components/GitHubConnector.tsx b/src/components/GitHubConnector.tsx
index 6f0bb7e..c389420 100644
--- a/src/components/GitHubConnector.tsx
+++ b/src/components/GitHubConnector.tsx
@@ -171,6 +171,89 @@ export function GitHubConnector({ appId, folderName }: GitHubConnectorProps) {
}
};
+ if (!settings?.githubSettings.secrets?.accessToken) {
+ return (
+
+ {" "}
+
+ {/* GitHub Connection Status/Instructions */}
+ {(githubUserCode || githubStatusMessage || githubError) && (
+
+
GitHub Connection
+ {githubError && (
+
+ Error: {githubError}
+
+ )}
+ {githubUserCode && githubVerificationUri && (
+
+ )}
+ {githubStatusMessage && (
+
+ {githubStatusMessage}
+
+ )}
+
+ )}
+
+ );
+ }
+
if (app?.githubOrg && app?.githubRepo) {
const handleSyncToGithub = async () => {
setIsSyncing(true);
@@ -244,9 +327,7 @@ export function GitHubConnector({ appId, folderName }: GitHubConnectorProps) {
)}
);
- }
-
- if (settings?.githubSettings.secrets) {
+ } else {
return (
Set up your GitHub repo
@@ -290,85 +371,4 @@ export function GitHubConnector({ appId, folderName }: GitHubConnectorProps) {
);
}
-
- return (
-
- {" "}
-
- {/* GitHub Connection Status/Instructions */}
- {(githubUserCode || githubStatusMessage || githubError) && (
-
-
GitHub Connection
- {githubError && (
-
- Error: {githubError}
-
- )}
- {githubUserCode && githubVerificationUri && (
-
- )}
- {githubStatusMessage && (
-
- {githubStatusMessage}
-
- )}
-
- )}
-
- );
}
diff --git a/src/ipc/handlers/app_handlers.ts b/src/ipc/handlers/app_handlers.ts
index ef27065..e670904 100644
--- a/src/ipc/handlers/app_handlers.ts
+++ b/src/ipc/handlers/app_handlers.ts
@@ -33,6 +33,7 @@ import { getEnvVar } from "../utils/read_env";
import { readSettings } from "../../main/settings";
import { Worker } from "worker_threads";
import fixPath from "fix-path";
+import { getGitAuthor } from "../utils/git_author";
// Needed, otherwise electron in MacOS/Linux will not be able
// to find "npm".
@@ -346,10 +347,7 @@ export function registerAppHandlers() {
fs: fs,
dir: fullAppPath,
message: "Init from react vite template",
- author: {
- name: "Dyad",
- email: "dyad@example.com",
- },
+ author: await getGitAuthor(),
});
} catch (error) {
console.error("Error in background app initialization:", error);
@@ -708,10 +706,7 @@ export function registerAppHandlers() {
fs,
dir: appPath,
message: `Reverted all changes back to version ${previousVersionId}`,
- author: {
- name: "Dyad",
- email: "hi@dyad.sh",
- },
+ author: await getGitAuthor(),
});
return { success: true };
@@ -845,10 +840,7 @@ export function registerAppHandlers() {
fs,
dir: appPath,
message: `Updated ${filePath}`,
- author: {
- name: "Dyad",
- email: "hi@dyad.sh",
- },
+ author: await getGitAuthor(),
});
}
diff --git a/src/ipc/handlers/github_handlers.ts b/src/ipc/handlers/github_handlers.ts
index e872824..7893834 100644
--- a/src/ipc/handlers/github_handlers.ts
+++ b/src/ipc/handlers/github_handlers.ts
@@ -15,6 +15,7 @@ import { getDyadAppPath } from "../../paths/paths";
import { db } from "../../db";
import { apps } from "../../db/schema";
import { eq } from "drizzle-orm";
+import { GithubUser } from "../../lib/schemas";
// --- GitHub Device Flow Constants ---
// TODO: Fetch this securely, e.g., from environment variables or a config file
@@ -38,6 +39,37 @@ let currentFlowState: DeviceFlowState | null = null;
// --- Helper Functions ---
+/**
+ * Fetches the GitHub username of the currently authenticated user (using the stored access token).
+ * @returns {Promise} The GitHub username, or null if not authenticated or on error.
+ */
+export async function getGithubUser(): Promise {
+ const settings = readSettings();
+ const email = settings.githubUser?.email;
+ if (email) return { email };
+ try {
+ const accessToken = settings.githubSettings?.secrets?.accessToken;
+ if (!accessToken) return null;
+ const res = await fetch("https://api.github.com/user/emails", {
+ headers: { Authorization: `Bearer ${accessToken}` },
+ });
+ if (!res.ok) return null;
+ const emails = await res.json();
+ const email = emails.find((e: any) => e.primary)?.email;
+ if (!email) return null;
+
+ writeSettings({
+ githubUser: {
+ email,
+ },
+ });
+ return { email };
+ } catch (err) {
+ console.error("[GitHub Handler] Failed to get GitHub username:", err);
+ return null;
+ }
+}
+
// function event.sender.send(channel: string, data: any) {
// if (currentFlowState?.window && !currentFlowState.window.isDestroyed()) {
// currentFlowState.window.webContents.send(channel, data);
diff --git a/src/ipc/processors/response_processor.ts b/src/ipc/processors/response_processor.ts
index c318d78..0210273 100644
--- a/src/ipc/processors/response_processor.ts
+++ b/src/ipc/processors/response_processor.ts
@@ -5,6 +5,8 @@ import fs from "node:fs";
import { getDyadAppPath } from "../../paths/paths";
import path from "node:path";
import git from "isomorphic-git";
+import { getGithubUser } from "../handlers/github_handlers";
+import { getGitAuthor } from "../utils/git_author";
export function getDyadWriteTags(fullResponse: string): {
path: string;
@@ -210,10 +212,7 @@ export async function processFullResponseActions(
message: chatSummary
? `[dyad] ${chatSummary} - ${changes.join(", ")}`
: `[dyad] ${changes.join(", ")}`,
- author: {
- name: "Dyad AI",
- email: "dyad-ai@example.com",
- },
+ author: await getGitAuthor(),
});
console.log(`Successfully committed changes: ${changes.join(", ")}`);
return { updatedFiles: true };
diff --git a/src/ipc/utils/git_author.ts b/src/ipc/utils/git_author.ts
new file mode 100644
index 0000000..556a58d
--- /dev/null
+++ b/src/ipc/utils/git_author.ts
@@ -0,0 +1,15 @@
+import { getGithubUser } from "../handlers/github_handlers";
+
+export async function getGitAuthor() {
+ const user = await getGithubUser();
+ const author = user
+ ? {
+ name: `[dyad]`,
+ email: user.email,
+ }
+ : {
+ name: "[dyad]",
+ email: "git@dyad.sh",
+ };
+ return author;
+}
diff --git a/src/lib/schemas.ts b/src/lib/schemas.ts
index a5c1c7e..b902b27 100644
--- a/src/lib/schemas.ts
+++ b/src/lib/schemas.ts
@@ -74,6 +74,11 @@ export const GitHubSettingsSchema = z.object({
});
export type GitHubSettings = z.infer;
+export const GithubUserSchema = z.object({
+ email: z.string(),
+});
+export type GithubUser = z.infer;
+
/**
* Zod schema for user settings
*/
@@ -82,6 +87,7 @@ export const UserSettingsSchema = z.object({
providerSettings: z.record(z.string(), ProviderSettingSchema),
runtimeMode: RuntimeModeSchema,
githubSettings: GitHubSettingsSchema,
+ githubUser: GithubUserSchema.optional(),
});
/**
diff --git a/src/main/settings.ts b/src/main/settings.ts
index 6005270..b7e5d9f 100644
--- a/src/main/settings.ts
+++ b/src/main/settings.ts
@@ -3,6 +3,7 @@ import path from "node:path";
import { getUserDataPath } from "../paths/paths";
import { UserSettingsSchema, type UserSettings } from "../lib/schemas";
import { safeStorage } from "electron";
+
const DEFAULT_SETTINGS: UserSettings = {
selectedModel: {
name: "auto",