lint using oxlint (#106)
This commit is contained in:
5
.oxlintrc.json
Normal file
5
.oxlintrc.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"rules": {
|
||||||
|
"eslint/no-unused-vars": "error"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,8 +7,6 @@ import { VitePlugin } from "@electron-forge/plugin-vite";
|
|||||||
import { FusesPlugin } from "@electron-forge/plugin-fuses";
|
import { FusesPlugin } from "@electron-forge/plugin-fuses";
|
||||||
import { FuseV1Options, FuseVersion } from "@electron/fuses";
|
import { FuseV1Options, FuseVersion } from "@electron/fuses";
|
||||||
import { AutoUnpackNativesPlugin } from "@electron-forge/plugin-auto-unpack-natives";
|
import { AutoUnpackNativesPlugin } from "@electron-forge/plugin-auto-unpack-natives";
|
||||||
import path from "path";
|
|
||||||
import fs from "fs";
|
|
||||||
|
|
||||||
// Based on https://github.com/electron/forge/blob/6b2d547a7216c30fde1e1fddd1118eee5d872945/packages/plugin/vite/src/VitePlugin.ts#L124
|
// Based on https://github.com/electron/forge/blob/6b2d547a7216c30fde1e1fddd1118eee5d872945/packages/plugin/vite/src/VitePlugin.ts#L124
|
||||||
const ignore = (file: string) => {
|
const ignore = (file: string) => {
|
||||||
|
|||||||
140
package-lock.json
generated
140
package-lock.json
generated
@@ -99,6 +99,7 @@
|
|||||||
"happy-dom": "^17.4.4",
|
"happy-dom": "^17.4.4",
|
||||||
"husky": "^9.1.7",
|
"husky": "^9.1.7",
|
||||||
"lint-staged": "^15.5.2",
|
"lint-staged": "^15.5.2",
|
||||||
|
"oxlint": "^0.16.9",
|
||||||
"prettier": "3.5.3",
|
"prettier": "3.5.3",
|
||||||
"typescript": "^5.8.3",
|
"typescript": "^5.8.3",
|
||||||
"vite": "^5.4.17",
|
"vite": "^5.4.17",
|
||||||
@@ -3604,6 +3605,118 @@
|
|||||||
"node": ">=8.0.0"
|
"node": ">=8.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@oxlint/darwin-arm64": {
|
||||||
|
"version": "0.16.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/@oxlint/darwin-arm64/-/darwin-arm64-0.16.9.tgz",
|
||||||
|
"integrity": "sha512-s8gPacumFNuDQcl0dCRLI0+efbiQrOF984brGrW1i2buJtaMzjYiunaU5TSrbHgnb/omvpFnG4l9g+YHOK/s0A==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@oxlint/darwin-x64": {
|
||||||
|
"version": "0.16.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/@oxlint/darwin-x64/-/darwin-x64-0.16.9.tgz",
|
||||||
|
"integrity": "sha512-QFue9yhfRU+fkbsOmDzCCwDafPR6fnaP/M+Rocp/MMDQ7qvjbB2sj0/xxp/CcvL7aLtFklMeXPR0hCfW3LyrSw==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@oxlint/linux-arm64-gnu": {
|
||||||
|
"version": "0.16.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/@oxlint/linux-arm64-gnu/-/linux-arm64-gnu-0.16.9.tgz",
|
||||||
|
"integrity": "sha512-qP/wdlgqLuiW9WDkAsyMN85wQ3nqAQynjRD+1II1QO0yI9N1ZHD6LF9P5fXAqY0eJwcf3emluQMoaeveewtiCg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@oxlint/linux-arm64-musl": {
|
||||||
|
"version": "0.16.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/@oxlint/linux-arm64-musl/-/linux-arm64-musl-0.16.9.tgz",
|
||||||
|
"integrity": "sha512-486wn1MIqP4hkHTnuWedTb16X6Zs3ImmmMxqzfYlcemf9kODM6yNlxal6wGvkm7SGRPYrsB/P9S5wgpzmLzKrw==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@oxlint/linux-x64-gnu": {
|
||||||
|
"version": "0.16.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/@oxlint/linux-x64-gnu/-/linux-x64-gnu-0.16.9.tgz",
|
||||||
|
"integrity": "sha512-d20zqy4Mimz9CxjIEJdGd6jtyyhpSryff95gNJSTvh/EA4NqvjjlbjxuHt3clNjglRwJWE3kgmUCw9U9oWFcWA==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@oxlint/linux-x64-musl": {
|
||||||
|
"version": "0.16.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/@oxlint/linux-x64-musl/-/linux-x64-musl-0.16.9.tgz",
|
||||||
|
"integrity": "sha512-mZLshz99773RMa77YhtsgWbqE7JY4xnYSDecDy+ZkafRb0acqz1Ujiq2l4cE+HnJOGVOMaOpzG0UoQ3ZNkXNAA==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@oxlint/win32-arm64": {
|
||||||
|
"version": "0.16.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/@oxlint/win32-arm64/-/win32-arm64-0.16.9.tgz",
|
||||||
|
"integrity": "sha512-Zp9+0CfTb7ebgvRwDO2F6NVgRtRmxWMdBnrbMRdVbKY6CCT2vjLAIILwBf5AsNLdLQC7FbXAEivSKbRX0UPyJA==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@oxlint/win32-x64": {
|
||||||
|
"version": "0.16.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/@oxlint/win32-x64/-/win32-x64-0.16.9.tgz",
|
||||||
|
"integrity": "sha512-6a507bALmDNFdvEbJzu9ybajryBHo+6nMWPNyu/mBguCqmconoBbQXftELd2VG/0ecxBmBcMKAQW6aONGUVc3w==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
]
|
||||||
|
},
|
||||||
"node_modules/@petamoriken/float16": {
|
"node_modules/@petamoriken/float16": {
|
||||||
"version": "3.9.2",
|
"version": "3.9.2",
|
||||||
"resolved": "https://registry.npmjs.org/@petamoriken/float16/-/float16-3.9.2.tgz",
|
"resolved": "https://registry.npmjs.org/@petamoriken/float16/-/float16-3.9.2.tgz",
|
||||||
@@ -15062,6 +15175,33 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/oxlint": {
|
||||||
|
"version": "0.16.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/oxlint/-/oxlint-0.16.9.tgz",
|
||||||
|
"integrity": "sha512-YMGu177AURJxdCq45/Yw6Q+uDh9ZfU++GuLYhUz+DfIGdHpAqVlBI9lCqm2HkLc6qO8ySYZ+8ljsWHLQA8F+EQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"oxc_language_server": "bin/oxc_language_server",
|
||||||
|
"oxlint": "bin/oxlint"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.*"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/Boshen"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@oxlint/darwin-arm64": "0.16.9",
|
||||||
|
"@oxlint/darwin-x64": "0.16.9",
|
||||||
|
"@oxlint/linux-arm64-gnu": "0.16.9",
|
||||||
|
"@oxlint/linux-arm64-musl": "0.16.9",
|
||||||
|
"@oxlint/linux-x64-gnu": "0.16.9",
|
||||||
|
"@oxlint/linux-x64-musl": "0.16.9",
|
||||||
|
"@oxlint/win32-arm64": "0.16.9",
|
||||||
|
"@oxlint/win32-x64": "0.16.9"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/p-cancelable": {
|
"node_modules/p-cancelable": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz",
|
||||||
|
|||||||
@@ -18,7 +18,8 @@
|
|||||||
"make": "npm run clean && electron-forge make",
|
"make": "npm run clean && electron-forge make",
|
||||||
"publish": "npm run clean && electron-forge publish",
|
"publish": "npm run clean && electron-forge publish",
|
||||||
"ts": "npx tsc -p tsconfig.app.json --noEmit",
|
"ts": "npx tsc -p tsconfig.app.json --noEmit",
|
||||||
"lint": "npx biome lint src --fix --unsafe",
|
"lint": "npx oxlint --fix",
|
||||||
|
"lint:fix": "npx oxlint --fix --fix-suggestions --fix-dangerously",
|
||||||
"db:generate": "drizzle-kit generate",
|
"db:generate": "drizzle-kit generate",
|
||||||
"db:push": "drizzle-kit push",
|
"db:push": "drizzle-kit push",
|
||||||
"db:studio": "drizzle-kit studio",
|
"db:studio": "drizzle-kit studio",
|
||||||
@@ -61,6 +62,7 @@
|
|||||||
"happy-dom": "^17.4.4",
|
"happy-dom": "^17.4.4",
|
||||||
"husky": "^9.1.7",
|
"husky": "^9.1.7",
|
||||||
"lint-staged": "^15.5.2",
|
"lint-staged": "^15.5.2",
|
||||||
|
"oxlint": "^0.16.9",
|
||||||
"prettier": "3.5.3",
|
"prettier": "3.5.3",
|
||||||
"typescript": "^5.8.3",
|
"typescript": "^5.8.3",
|
||||||
"vite": "^5.4.17",
|
"vite": "^5.4.17",
|
||||||
@@ -131,6 +133,7 @@
|
|||||||
"uuid": "^11.1.0"
|
"uuid": "^11.1.0"
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
|
"**/*.{js,mjs,cjs,jsx,ts,mts,cts,tsx,vue,astro,svelte}": "oxlint",
|
||||||
"*.{js,css,md,ts,tsx,jsx,json}": "prettier --write"
|
"*.{js,css,md,ts,tsx,jsx,json}": "prettier --write"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
? new URL(url, window.location.href).href
|
? new URL(url, window.location.href).href
|
||||||
: window.location.href;
|
: window.location.href;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
console.error("Could not parse URL", e);
|
||||||
newUrl = window.location.href;
|
newUrl = window.location.href;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,7 +65,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
// --- Listener for Back/Forward Navigation (popstate event) ---
|
// --- Listener for Back/Forward Navigation (popstate event) ---
|
||||||
window.addEventListener("popstate", (event) => {
|
window.addEventListener("popstate", () => {
|
||||||
const currentUrl = window.location.href;
|
const currentUrl = window.location.href;
|
||||||
previousUrl = currentUrl;
|
previousUrl = currentUrl;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ type ToasterToast = ToastProps & {
|
|||||||
action?: ToastActionElement;
|
action?: ToastActionElement;
|
||||||
};
|
};
|
||||||
|
|
||||||
const actionTypes = {
|
const _actionTypes = {
|
||||||
ADD_TOAST: "ADD_TOAST",
|
ADD_TOAST: "ADD_TOAST",
|
||||||
UPDATE_TOAST: "UPDATE_TOAST",
|
UPDATE_TOAST: "UPDATE_TOAST",
|
||||||
DISMISS_TOAST: "DISMISS_TOAST",
|
DISMISS_TOAST: "DISMISS_TOAST",
|
||||||
@@ -26,7 +26,7 @@ function genId() {
|
|||||||
return count.toString();
|
return count.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
type ActionType = typeof actionTypes;
|
type ActionType = typeof _actionTypes;
|
||||||
|
|
||||||
type Action =
|
type Action =
|
||||||
| {
|
| {
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ export function devErrorAndNavigationPlugin(): Plugin {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default defineConfig(({ mode }) => ({
|
export default defineConfig(() => ({
|
||||||
server: {
|
server: {
|
||||||
host: "::",
|
host: "::",
|
||||||
port: 8080,
|
port: 8080,
|
||||||
|
|||||||
@@ -99,8 +99,8 @@ console.log("TodoItem");
|
|||||||
expect(result).toEqual([
|
expect(result).toEqual([
|
||||||
{
|
{
|
||||||
path: "src/components/TodoItem.tsx",
|
path: "src/components/TodoItem.tsx",
|
||||||
content: `import React from \"react\";
|
content: `import React from "react";
|
||||||
console.log(\"TodoItem\");`,
|
console.log("TodoItem");`,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
@@ -117,8 +117,8 @@ console.log("TodoItem");
|
|||||||
expect(result).toEqual([
|
expect(result).toEqual([
|
||||||
{
|
{
|
||||||
path: "src/components/TodoItem.tsx",
|
path: "src/components/TodoItem.tsx",
|
||||||
content: `import React from \"react\";
|
content: `import React from "react";
|
||||||
console.log(\"TodoItem\");`,
|
console.log("TodoItem");`,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { atom } from "jotai";
|
import { atom } from "jotai";
|
||||||
import type { CodeProposal, ProposalResult } from "@/lib/schemas";
|
import type { ProposalResult } from "@/lib/schemas";
|
||||||
|
|
||||||
export const proposalResultAtom = atom<ProposalResult | null>(null);
|
export const proposalResultAtom = atom<ProposalResult | null>(null);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { useNavigate, useRouterState } from "@tanstack/react-router";
|
import { useNavigate, useRouterState } from "@tanstack/react-router";
|
||||||
import type { ChatSummary } from "@/lib/schemas";
|
|
||||||
import { formatDistanceToNow } from "date-fns";
|
import { formatDistanceToNow } from "date-fns";
|
||||||
import { PlusCircle, MoreVertical, Trash2 } from "lucide-react";
|
import { PlusCircle, MoreVertical, Trash2 } from "lucide-react";
|
||||||
import { useAtom } from "jotai";
|
import { useAtom } from "jotai";
|
||||||
@@ -29,7 +29,7 @@ export function ChatList({ show }: { show?: boolean }) {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [selectedChatId, setSelectedChatId] = useAtom(selectedChatIdAtom);
|
const [selectedChatId, setSelectedChatId] = useAtom(selectedChatIdAtom);
|
||||||
const [selectedAppId, setSelectedAppId] = useAtom(selectedAppIdAtom);
|
const [selectedAppId, setSelectedAppId] = useAtom(selectedAppIdAtom);
|
||||||
const [isDropdownOpen, setIsDropdownOpen] = useAtom(dropdownOpenAtom);
|
const [, setIsDropdownOpen] = useAtom(dropdownOpenAtom);
|
||||||
const { chats, loading, refreshChats } = useChats(selectedAppId);
|
const { chats, loading, refreshChats } = useChats(selectedAppId);
|
||||||
const routerState = useRouterState();
|
const routerState = useRouterState();
|
||||||
const isChatRoute = routerState.location.pathname === "/chat";
|
const isChatRoute = routerState.location.pathname === "/chat";
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useState, useRef, useEffect, useCallback } from "react";
|
|||||||
import { useAtom, useAtomValue } from "jotai";
|
import { useAtom, useAtomValue } from "jotai";
|
||||||
import { chatMessagesAtom, chatStreamCountAtom } from "../atoms/chatAtoms";
|
import { chatMessagesAtom, chatStreamCountAtom } from "../atoms/chatAtoms";
|
||||||
import { IpcClient } from "@/ipc/ipc_client";
|
import { IpcClient } from "@/ipc/ipc_client";
|
||||||
import { selectedAppIdAtom } from "@/atoms/appAtoms";
|
|
||||||
import { ChatHeader } from "./chat/ChatHeader";
|
import { ChatHeader } from "./chat/ChatHeader";
|
||||||
import { MessagesList } from "./chat/MessagesList";
|
import { MessagesList } from "./chat/MessagesList";
|
||||||
import { ChatInput } from "./chat/ChatInput";
|
import { ChatInput } from "./chat/ChatInput";
|
||||||
@@ -20,14 +20,11 @@ export function ChatPanel({
|
|||||||
isPreviewOpen,
|
isPreviewOpen,
|
||||||
onTogglePreview,
|
onTogglePreview,
|
||||||
}: ChatPanelProps) {
|
}: ChatPanelProps) {
|
||||||
const appId = useAtomValue(selectedAppIdAtom);
|
|
||||||
const [messages, setMessages] = useAtom(chatMessagesAtom);
|
const [messages, setMessages] = useAtom(chatMessagesAtom);
|
||||||
const [appName, setAppName] = useState<string>("Chat");
|
|
||||||
const [isVersionPaneOpen, setIsVersionPaneOpen] = useState(false);
|
const [isVersionPaneOpen, setIsVersionPaneOpen] = useState(false);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const streamCount = useAtomValue(chatStreamCountAtom);
|
const streamCount = useAtomValue(chatStreamCountAtom);
|
||||||
// Reference to store the processed prompt so we don't submit it twice
|
// Reference to store the processed prompt so we don't submit it twice
|
||||||
const processedPromptRef = useRef<string | null>(null);
|
|
||||||
|
|
||||||
const messagesEndRef = useRef<HTMLDivElement | null>(null);
|
const messagesEndRef = useRef<HTMLDivElement | null>(null);
|
||||||
const messagesContainerRef = useRef<HTMLDivElement | null>(null);
|
const messagesContainerRef = useRef<HTMLDivElement | null>(null);
|
||||||
@@ -83,23 +80,6 @@ export function ChatPanel({
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const fetchAppName = async () => {
|
|
||||||
if (!appId) return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const app = await IpcClient.getInstance().getApp(appId);
|
|
||||||
if (app?.name) {
|
|
||||||
setAppName(app.name);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Failed to fetch app name:", error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
fetchAppName();
|
|
||||||
}, [appId]);
|
|
||||||
|
|
||||||
const fetchChatMessages = useCallback(async () => {
|
const fetchChatMessages = useCallback(async () => {
|
||||||
if (!chatId) {
|
if (!chatId) {
|
||||||
setMessages([]);
|
setMessages([]);
|
||||||
|
|||||||
@@ -1,10 +1,4 @@
|
|||||||
import React, {
|
import React, { useState, useEffect } from "react";
|
||||||
Component,
|
|
||||||
ErrorInfo,
|
|
||||||
ReactNode,
|
|
||||||
useState,
|
|
||||||
useEffect,
|
|
||||||
} from "react";
|
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { LightbulbIcon } from "lucide-react";
|
import { LightbulbIcon } from "lucide-react";
|
||||||
import { ErrorComponentProps } from "@tanstack/react-router";
|
import { ErrorComponentProps } from "@tanstack/react-router";
|
||||||
|
|||||||
@@ -292,7 +292,7 @@ Session ID: ${sessionId}
|
|||||||
<div className="border rounded-md p-3">
|
<div className="border rounded-md p-3">
|
||||||
<h3 className="font-medium mb-2">Chat Messages</h3>
|
<h3 className="font-medium mb-2">Chat Messages</h3>
|
||||||
<div className="text-sm bg-slate-50 dark:bg-slate-900 rounded p-2 max-h-40 overflow-y-auto">
|
<div className="text-sm bg-slate-50 dark:bg-slate-900 rounded p-2 max-h-40 overflow-y-auto">
|
||||||
{chatLogsData.chat.messages.map((msg, index) => (
|
{chatLogsData.chat.messages.map((msg) => (
|
||||||
<div key={msg.id} className="mb-2">
|
<div key={msg.id} className="mb-2">
|
||||||
<span className="font-semibold">
|
<span className="font-semibold">
|
||||||
{msg.role === "user" ? "You" : "Assistant"}:{" "}
|
{msg.role === "user" ? "You" : "Assistant"}:{" "}
|
||||||
|
|||||||
@@ -10,13 +10,8 @@ import { providerSettingsRoute } from "@/routes/settings/providers/$provider";
|
|||||||
import type { ModelProvider } from "@/lib/schemas";
|
import type { ModelProvider } from "@/lib/schemas";
|
||||||
import { useSettings } from "@/hooks/useSettings";
|
import { useSettings } from "@/hooks/useSettings";
|
||||||
import { GiftIcon } from "lucide-react";
|
import { GiftIcon } from "lucide-react";
|
||||||
interface ProviderSettingsProps {
|
|
||||||
configuredProviders?: ModelProvider[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ProviderSettingsGrid({
|
export function ProviderSettingsGrid() {
|
||||||
configuredProviders = [],
|
|
||||||
}: ProviderSettingsProps) {
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const handleProviderClick = (provider: ModelProvider) => {
|
const handleProviderClick = (provider: ModelProvider) => {
|
||||||
@@ -33,10 +28,6 @@ export function ProviderSettingsGrid({
|
|||||||
<h2 className="text-2xl font-bold mb-6">AI Providers</h2>
|
<h2 className="text-2xl font-bold mb-6">AI Providers</h2>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||||
{Object.entries(PROVIDERS).map(([key, provider]) => {
|
{Object.entries(PROVIDERS).map(([key, provider]) => {
|
||||||
const isConfigured = configuredProviders.includes(
|
|
||||||
key as ModelProvider,
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
key={key}
|
key={key}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Input } from "@/components/ui/input";
|
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { SupabaseSchema } from "@/lib/schemas";
|
|
||||||
import { IpcClient } from "@/ipc/ipc_client";
|
import { IpcClient } from "@/ipc/ipc_client";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { useSettings } from "@/hooks/useSettings";
|
import { useSettings } from "@/hooks/useSettings";
|
||||||
@@ -24,7 +24,7 @@ import {
|
|||||||
import { Skeleton } from "@/components/ui/skeleton";
|
import { Skeleton } from "@/components/ui/skeleton";
|
||||||
import { useLoadApp } from "@/hooks/useLoadApp";
|
import { useLoadApp } from "@/hooks/useLoadApp";
|
||||||
import { useDeepLink } from "@/contexts/DeepLinkContext";
|
import { useDeepLink } from "@/contexts/DeepLinkContext";
|
||||||
const OAUTH_CLIENT_ID = "bf747de7-60bb-48a2-9015-6494e0b04983";
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import supabaseLogoLight from "../../assets/supabase/supabase-logo-wordmark--light.svg";
|
import supabaseLogoLight from "../../assets/supabase/supabase-logo-wordmark--light.svg";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@@ -74,7 +74,7 @@ export function SupabaseConnector({ appId }: { appId: number }) {
|
|||||||
toast.success("Project connected to app successfully");
|
toast.success("Project connected to app successfully");
|
||||||
await refreshApp();
|
await refreshApp();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
toast.error("Failed to connect project to app");
|
toast.error("Failed to connect project to app: " + error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { IpcClient } from "@/ipc/ipc_client";
|
import { IpcClient } from "@/ipc/ipc_client";
|
||||||
import React, { useState } from "react";
|
import React from "react";
|
||||||
import { Button } from "./ui/button";
|
import { Button } from "./ui/button";
|
||||||
import { atom, useAtom } from "jotai";
|
import { atom, useAtom } from "jotai";
|
||||||
import { useSettings } from "@/hooks/useSettings";
|
import { useSettings } from "@/hooks/useSettings";
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { useSettings } from "@/hooks/useSettings";
|
import { useSettings } from "@/hooks/useSettings";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { Switch } from "@/components/ui/switch";
|
import { Switch } from "@/components/ui/switch";
|
||||||
import { showInfo } from "@/lib/toast";
|
|
||||||
|
|
||||||
export function TelemetrySwitch() {
|
export function TelemetrySwitch() {
|
||||||
const { settings, updateSettings } = useSettings();
|
const { settings, updateSettings } = useSettings();
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { FileText, X } from "lucide-react";
|
import { FileText, X } from "lucide-react";
|
||||||
import { useEffect } from "react";
|
|
||||||
|
|
||||||
interface AttachmentsListProps {
|
interface AttachmentsListProps {
|
||||||
attachments: File[];
|
attachments: File[];
|
||||||
|
|||||||
@@ -3,11 +3,10 @@ import {
|
|||||||
History,
|
History,
|
||||||
PlusCircle,
|
PlusCircle,
|
||||||
GitBranch,
|
GitBranch,
|
||||||
AlertCircle,
|
|
||||||
Info,
|
Info,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { PanelRightClose } from "lucide-react";
|
import { PanelRightClose } from "lucide-react";
|
||||||
import { useAtom, useAtomValue, useSetAtom } from "jotai";
|
import { useAtom, useAtomValue } from "jotai";
|
||||||
import { selectedAppIdAtom } from "@/atoms/appAtoms";
|
import { selectedAppIdAtom } from "@/atoms/appAtoms";
|
||||||
import { useVersions } from "@/hooks/useVersions";
|
import { useVersions } from "@/hooks/useVersions";
|
||||||
import { Button } from "../ui/button";
|
import { Button } from "../ui/button";
|
||||||
|
|||||||
@@ -58,17 +58,14 @@ import { useVersions } from "@/hooks/useVersions";
|
|||||||
import { useAttachments } from "@/hooks/useAttachments";
|
import { useAttachments } from "@/hooks/useAttachments";
|
||||||
import { AttachmentsList } from "./AttachmentsList";
|
import { AttachmentsList } from "./AttachmentsList";
|
||||||
import { DragDropOverlay } from "./DragDropOverlay";
|
import { DragDropOverlay } from "./DragDropOverlay";
|
||||||
import {
|
import { showUncommittedFilesWarning } from "@/lib/toast";
|
||||||
showError as showErrorToast,
|
|
||||||
showUncommittedFilesWarning,
|
|
||||||
} from "@/lib/toast";
|
|
||||||
const showTokenBarAtom = atom(false);
|
const showTokenBarAtom = atom(false);
|
||||||
|
|
||||||
export function ChatInput({ chatId }: { chatId?: number }) {
|
export function ChatInput({ chatId }: { chatId?: number }) {
|
||||||
const posthog = usePostHog();
|
const posthog = usePostHog();
|
||||||
const [inputValue, setInputValue] = useAtom(chatInputValueAtom);
|
const [inputValue, setInputValue] = useAtom(chatInputValueAtom);
|
||||||
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||||
const { settings, updateSettings, isAnyProviderSetup } = useSettings();
|
const { settings, updateSettings } = useSettings();
|
||||||
const appId = useAtomValue(selectedAppIdAtom);
|
const appId = useAtomValue(selectedAppIdAtom);
|
||||||
const { refreshVersions } = useVersions(appId);
|
const { refreshVersions } = useVersions(appId);
|
||||||
const { streamMessage, isStreaming, setIsStreaming, error, setError } =
|
const { streamMessage, isStreaming, setIsStreaming, error, setError } =
|
||||||
@@ -76,7 +73,7 @@ export function ChatInput({ chatId }: { chatId?: number }) {
|
|||||||
const [showError, setShowError] = useState(true);
|
const [showError, setShowError] = useState(true);
|
||||||
const [isApproving, setIsApproving] = useState(false); // State for approving
|
const [isApproving, setIsApproving] = useState(false); // State for approving
|
||||||
const [isRejecting, setIsRejecting] = useState(false); // State for rejecting
|
const [isRejecting, setIsRejecting] = useState(false); // State for rejecting
|
||||||
const [messages, setMessages] = useAtom<Message[]>(chatMessagesAtom);
|
const [, setMessages] = useAtom<Message[]>(chatMessagesAtom);
|
||||||
const setIsPreviewOpen = useSetAtom(isPreviewOpenAtom);
|
const setIsPreviewOpen = useSetAtom(isPreviewOpenAtom);
|
||||||
const [showTokenBar, setShowTokenBar] = useAtom(showTokenBarAtom);
|
const [showTokenBar, setShowTokenBar] = useAtom(showTokenBarAtom);
|
||||||
|
|
||||||
@@ -101,7 +98,7 @@ export function ChatInput({ chatId }: { chatId?: number }) {
|
|||||||
error: proposalError,
|
error: proposalError,
|
||||||
refreshProposal,
|
refreshProposal,
|
||||||
} = useProposal(chatId);
|
} = useProposal(chatId);
|
||||||
const { proposal, chatId: proposalChatId, messageId } = proposalResult ?? {};
|
const { proposal, messageId } = proposalResult ?? {};
|
||||||
|
|
||||||
const adjustHeight = () => {
|
const adjustHeight = () => {
|
||||||
const textarea = textareaRef.current;
|
const textarea = textareaRef.current;
|
||||||
@@ -620,7 +617,6 @@ function ChatInputActions({
|
|||||||
isApproving,
|
isApproving,
|
||||||
isRejecting,
|
isRejecting,
|
||||||
}: ChatInputActionsProps) {
|
}: ChatInputActionsProps) {
|
||||||
const [autoApprove, setAutoApprove] = useState(false);
|
|
||||||
const [isDetailsVisible, setIsDetailsVisible] = useState(false);
|
const [isDetailsVisible, setIsDetailsVisible] = useState(false);
|
||||||
|
|
||||||
if (proposal.type === "tip-proposal") {
|
if (proposal.type === "tip-proposal") {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { memo } from "react";
|
|
||||||
import type { Message } from "@/ipc/ipc_types";
|
import type { Message } from "@/ipc/ipc_types";
|
||||||
import {
|
import {
|
||||||
DyadMarkdownParser,
|
DyadMarkdownParser,
|
||||||
|
|||||||
@@ -1,19 +1,10 @@
|
|||||||
import type React from "react";
|
import type React from "react";
|
||||||
import type { ReactNode } from "react";
|
import type { ReactNode } from "react";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { Button } from "../ui/button";
|
|
||||||
import { IpcClient } from "../../ipc/ipc_client";
|
import { IpcClient } from "../../ipc/ipc_client";
|
||||||
import { useAtom, useAtomValue } from "jotai";
|
|
||||||
import { chatMessagesAtom, selectedChatIdAtom } from "../../atoms/chatAtoms";
|
import { Package, ChevronsUpDown, ChevronsDownUp } from "lucide-react";
|
||||||
import { useStreamChat } from "@/hooks/useStreamChat";
|
|
||||||
import {
|
|
||||||
Package,
|
|
||||||
ChevronsUpDown,
|
|
||||||
ChevronsDownUp,
|
|
||||||
Loader,
|
|
||||||
ExternalLink,
|
|
||||||
Download,
|
|
||||||
} from "lucide-react";
|
|
||||||
import { CodeHighlight } from "./CodeHighlight";
|
import { CodeHighlight } from "./CodeHighlight";
|
||||||
|
|
||||||
interface DyadAddDependencyProps {
|
interface DyadAddDependencyProps {
|
||||||
@@ -28,15 +19,14 @@ export const DyadAddDependency: React.FC<DyadAddDependencyProps> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
// Extract package attribute from the node if available
|
// Extract package attribute from the node if available
|
||||||
const packages = node?.properties?.packages?.split(" ") || "";
|
const packages = node?.properties?.packages?.split(" ") || "";
|
||||||
const [isInstalling, setIsInstalling] = useState(false);
|
|
||||||
const [isContentVisible, setIsContentVisible] = useState(false);
|
const [isContentVisible, setIsContentVisible] = useState(false);
|
||||||
const hasChildren = !!children;
|
const hasChildren = !!children;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`bg-(--background-lightest) dark:bg-gray-900 hover:bg-(--background-lighter) rounded-lg px-4 py-3 border my-2 ${
|
className={`bg-(--background-lightest) dark:bg-gray-900 hover:bg-(--background-lighter) rounded-lg px-4 py-3 border my-2 border-border ${
|
||||||
hasChildren ? "cursor-pointer" : ""
|
hasChildren ? "cursor-pointer" : ""
|
||||||
} ${isInstalling ? "border-amber-500" : "border-border"}`}
|
}`}
|
||||||
onClick={
|
onClick={
|
||||||
hasChildren ? () => setIsContentVisible(!isContentVisible) : undefined
|
hasChildren ? () => setIsContentVisible(!isContentVisible) : undefined
|
||||||
}
|
}
|
||||||
@@ -66,12 +56,6 @@ export const DyadAddDependency: React.FC<DyadAddDependencyProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{isInstalling && (
|
|
||||||
<div className="flex items-center text-amber-600 text-xs ml-2">
|
|
||||||
<Loader size={14} className="mr-1 animate-spin" />
|
|
||||||
<span>Installing...</span>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
{hasChildren && (
|
{hasChildren && (
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
|
|||||||
@@ -30,7 +30,13 @@ type ContentPiece =
|
|||||||
| { type: "markdown"; content: string }
|
| { type: "markdown"; content: string }
|
||||||
| { type: "custom-tag"; tagInfo: CustomTagInfo };
|
| { type: "custom-tag"; tagInfo: CustomTagInfo };
|
||||||
|
|
||||||
const customLink = ({ node, ...props }: { node?: any; [key: string]: any }) => (
|
const customLink = ({
|
||||||
|
node: _node,
|
||||||
|
...props
|
||||||
|
}: {
|
||||||
|
node?: any;
|
||||||
|
[key: string]: any;
|
||||||
|
}) => (
|
||||||
<a
|
<a
|
||||||
{...props}
|
{...props}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
@@ -358,11 +364,3 @@ function renderCustomTag(
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Extract attribute values from className string
|
|
||||||
*/
|
|
||||||
function extractAttribute(className: string, attrName: string): string {
|
|
||||||
const match = new RegExp(`${attrName}="([^"]*)"`, "g").exec(className);
|
|
||||||
return match ? match[1] : "";
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import {
|
|||||||
XCircle,
|
XCircle,
|
||||||
Sparkles,
|
Sparkles,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { useAtom, useSetAtom } from "jotai";
|
import { useAtomValue } from "jotai";
|
||||||
import { chatInputValueAtom, selectedChatIdAtom } from "@/atoms/chatAtoms";
|
import { selectedChatIdAtom } from "@/atoms/chatAtoms";
|
||||||
import { useStreamChat } from "@/hooks/useStreamChat";
|
import { useStreamChat } from "@/hooks/useStreamChat";
|
||||||
interface DyadOutputProps {
|
interface DyadOutputProps {
|
||||||
type: "error" | "warning";
|
type: "error" | "warning";
|
||||||
@@ -21,7 +21,7 @@ export const DyadOutput: React.FC<DyadOutputProps> = ({
|
|||||||
children,
|
children,
|
||||||
}) => {
|
}) => {
|
||||||
const [isContentVisible, setIsContentVisible] = useState(false);
|
const [isContentVisible, setIsContentVisible] = useState(false);
|
||||||
const [selectedChatId, setSelectedChatId] = useAtom(selectedChatIdAtom);
|
const selectedChatId = useAtomValue(selectedChatIdAtom);
|
||||||
const { streamMessage } = useStreamChat();
|
const { streamMessage } = useStreamChat();
|
||||||
|
|
||||||
// If the type is not warning, it is an error (in case LLM gives a weird "type")
|
// If the type is not warning, it is an error (in case LLM gives a weird "type")
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { SendIcon, StopCircleIcon, X, Paperclip, Loader2 } from "lucide-react";
|
import { SendIcon, StopCircleIcon, Paperclip } from "lucide-react";
|
||||||
import type React from "react";
|
import type React from "react";
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef } from "react";
|
||||||
import { ModelPicker } from "@/components/ModelPicker";
|
import { ModelPicker } from "@/components/ModelPicker";
|
||||||
import { useSettings } from "@/hooks/useSettings";
|
import { useSettings } from "@/hooks/useSettings";
|
||||||
import { homeChatInputValueAtom } from "@/atoms/chatAtoms"; // Use a different atom for home input
|
import { homeChatInputValueAtom } from "@/atoms/chatAtoms"; // Use a different atom for home input
|
||||||
@@ -21,7 +21,7 @@ export function HomeChatInput({
|
|||||||
const [inputValue, setInputValue] = useAtom(homeChatInputValueAtom);
|
const [inputValue, setInputValue] = useAtom(homeChatInputValueAtom);
|
||||||
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||||
const { settings, updateSettings, isAnyProviderSetup } = useSettings();
|
const { settings, updateSettings, isAnyProviderSetup } = useSettings();
|
||||||
const { streamMessage, isStreaming, setIsStreaming } = useStreamChat({
|
const { isStreaming } = useStreamChat({
|
||||||
hasChatId: false,
|
hasChatId: false,
|
||||||
}); // eslint-disable-line @typescript-eslint/no-unused-vars
|
}); // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||||
|
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ import { SetupBanner } from "../SetupBanner";
|
|||||||
import { useSettings } from "@/hooks/useSettings";
|
import { useSettings } from "@/hooks/useSettings";
|
||||||
import { useStreamChat } from "@/hooks/useStreamChat";
|
import { useStreamChat } from "@/hooks/useStreamChat";
|
||||||
import { selectedChatIdAtom } from "@/atoms/chatAtoms";
|
import { selectedChatIdAtom } from "@/atoms/chatAtoms";
|
||||||
import { useAtom, useAtomValue, useSetAtom } from "jotai";
|
import { useAtomValue, useSetAtom } from "jotai";
|
||||||
import { Loader2, RefreshCw, Undo } from "lucide-react";
|
import { Loader2, RefreshCw, Undo } from "lucide-react";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { useVersions } from "@/hooks/useVersions";
|
import { useVersions } from "@/hooks/useVersions";
|
||||||
import { selectedAppIdAtom } from "@/atoms/appAtoms";
|
import { selectedAppIdAtom } from "@/atoms/appAtoms";
|
||||||
import { showError, showSuccess, showWarning } from "@/lib/toast";
|
import { showError, showWarning } from "@/lib/toast";
|
||||||
import { IpcClient } from "@/ipc/ipc_client";
|
import { IpcClient } from "@/ipc/ipc_client";
|
||||||
import { chatMessagesAtom } from "@/atoms/chatAtoms";
|
import { chatMessagesAtom } from "@/atoms/chatAtoms";
|
||||||
|
|
||||||
@@ -24,13 +24,13 @@ export const MessagesList = forwardRef<HTMLDivElement, MessagesListProps>(
|
|||||||
function MessagesList({ messages, messagesEndRef }, ref) {
|
function MessagesList({ messages, messagesEndRef }, ref) {
|
||||||
const appId = useAtomValue(selectedAppIdAtom);
|
const appId = useAtomValue(selectedAppIdAtom);
|
||||||
const { versions, revertVersion } = useVersions(appId);
|
const { versions, revertVersion } = useVersions(appId);
|
||||||
const { streamMessage, isStreaming, error, setError } = useStreamChat();
|
const { streamMessage, isStreaming } = useStreamChat();
|
||||||
const { isAnyProviderSetup } = useSettings();
|
const { isAnyProviderSetup } = useSettings();
|
||||||
|
|
||||||
const setMessages = useSetAtom(chatMessagesAtom);
|
const setMessages = useSetAtom(chatMessagesAtom);
|
||||||
const [isUndoLoading, setIsUndoLoading] = useState(false);
|
const [isUndoLoading, setIsUndoLoading] = useState(false);
|
||||||
const [isRetryLoading, setIsRetryLoading] = useState(false);
|
const [isRetryLoading, setIsRetryLoading] = useState(false);
|
||||||
const [selectedChatId, setSelectedChatId] = useAtom(selectedChatIdAtom);
|
const selectedChatId = useAtomValue(selectedChatIdAtom);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex-1 overflow-y-auto p-4" ref={ref}>
|
<div className="flex-1 overflow-y-auto p-4" ref={ref}>
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { useState } from "react";
|
|
||||||
import { FileEditor } from "./FileEditor";
|
import { FileEditor } from "./FileEditor";
|
||||||
import { FileTree } from "./FileTree";
|
import { FileTree } from "./FileTree";
|
||||||
import { RefreshCw } from "lucide-react";
|
import { RefreshCw } from "lucide-react";
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ export const FileEditor = ({ appId, filePath }: FileEditorProps) => {
|
|||||||
const editorTheme = isDarkMode ? "dyad-dark" : "dyad-light";
|
const editorTheme = isDarkMode ? "dyad-dark" : "dyad-light";
|
||||||
|
|
||||||
// Handle editor mount
|
// Handle editor mount
|
||||||
const handleEditorDidMount: OnMount = (editor, monaco) => {
|
const handleEditorDidMount: OnMount = (editor) => {
|
||||||
editorRef.current = editor;
|
editorRef.current = editor;
|
||||||
|
|
||||||
// Listen for model content change events
|
// Listen for model content change events
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import {
|
|||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { selectedChatIdAtom } from "@/atoms/chatAtoms";
|
import { selectedChatIdAtom } from "@/atoms/chatAtoms";
|
||||||
import { IpcClient } from "@/ipc/ipc_client";
|
import { IpcClient } from "@/ipc/ipc_client";
|
||||||
import { useLoadApp } from "@/hooks/useLoadApp";
|
|
||||||
import { useLoadAppFile } from "@/hooks/useLoadAppFile";
|
import { useLoadAppFile } from "@/hooks/useLoadAppFile";
|
||||||
import {
|
import {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
@@ -28,8 +28,6 @@ import {
|
|||||||
DropdownMenuItem,
|
DropdownMenuItem,
|
||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from "@/components/ui/dropdown-menu";
|
} from "@/components/ui/dropdown-menu";
|
||||||
import { useSettings } from "@/hooks/useSettings";
|
|
||||||
import { useRunApp } from "@/hooks/useRunApp";
|
|
||||||
import { useStreamChat } from "@/hooks/useStreamChat";
|
import { useStreamChat } from "@/hooks/useStreamChat";
|
||||||
|
|
||||||
interface ErrorBannerProps {
|
interface ErrorBannerProps {
|
||||||
@@ -113,7 +111,7 @@ export const PreviewIframe = ({ loading }: { loading: boolean }) => {
|
|||||||
// State to trigger iframe reload
|
// State to trigger iframe reload
|
||||||
const [reloadKey, setReloadKey] = useState(0);
|
const [reloadKey, setReloadKey] = useState(0);
|
||||||
const [errorMessage, setErrorMessage] = useAtom(previewErrorMessageAtom);
|
const [errorMessage, setErrorMessage] = useAtom(previewErrorMessageAtom);
|
||||||
const [selectedChatId, setSelectedChatId] = useAtom(selectedChatIdAtom);
|
const selectedChatId = useAtomValue(selectedChatIdAtom);
|
||||||
const { streamMessage } = useStreamChat();
|
const { streamMessage } = useStreamChat();
|
||||||
const [availableRoutes, setAvailableRoutes] = useState<
|
const [availableRoutes, setAvailableRoutes] = useState<
|
||||||
Array<{ path: string; label: string }>
|
Array<{ path: string; label: string }>
|
||||||
@@ -168,7 +166,6 @@ export const PreviewIframe = ({ loading }: { loading: boolean }) => {
|
|||||||
const [navigationHistory, setNavigationHistory] = useState<string[]>([]);
|
const [navigationHistory, setNavigationHistory] = useState<string[]>([]);
|
||||||
const [currentHistoryPosition, setCurrentHistoryPosition] = useState(0);
|
const [currentHistoryPosition, setCurrentHistoryPosition] = useState(0);
|
||||||
const iframeRef = useRef<HTMLIFrameElement>(null);
|
const iframeRef = useRef<HTMLIFrameElement>(null);
|
||||||
const { settings } = useSettings();
|
|
||||||
|
|
||||||
// Add message listener for iframe errors and navigation events
|
// Add message listener for iframe errors and navigation events
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {
|
|||||||
previewPanelKeyAtom,
|
previewPanelKeyAtom,
|
||||||
selectedAppIdAtom,
|
selectedAppIdAtom,
|
||||||
} from "../../atoms/appAtoms";
|
} from "../../atoms/appAtoms";
|
||||||
import { useLoadApp } from "@/hooks/useLoadApp";
|
|
||||||
import { CodeView } from "./CodeView";
|
import { CodeView } from "./CodeView";
|
||||||
import { PreviewIframe } from "./PreviewIframe";
|
import { PreviewIframe } from "./PreviewIframe";
|
||||||
import {
|
import {
|
||||||
@@ -14,11 +14,8 @@ import {
|
|||||||
ChevronDown,
|
ChevronDown,
|
||||||
ChevronUp,
|
ChevronUp,
|
||||||
Logs,
|
Logs,
|
||||||
RefreshCw,
|
|
||||||
MoreVertical,
|
MoreVertical,
|
||||||
Trash2,
|
|
||||||
Cog,
|
Cog,
|
||||||
CirclePower,
|
|
||||||
Power,
|
Power,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { motion } from "framer-motion";
|
import { motion } from "framer-motion";
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ export function ProviderSettingsPage({ provider }: ProviderSettingsPageProps) {
|
|||||||
providerSettings: {
|
providerSettings: {
|
||||||
...settings?.providerSettings,
|
...settings?.providerSettings,
|
||||||
[provider]: {
|
[provider]: {
|
||||||
...(settings?.providerSettings?.[provider] || {}),
|
...settings?.providerSettings?.[provider],
|
||||||
apiKey: {
|
apiKey: {
|
||||||
value: apiKeyInput,
|
value: apiKeyInput,
|
||||||
},
|
},
|
||||||
@@ -134,7 +134,7 @@ export function ProviderSettingsPage({ provider }: ProviderSettingsPageProps) {
|
|||||||
providerSettings: {
|
providerSettings: {
|
||||||
...settings?.providerSettings,
|
...settings?.providerSettings,
|
||||||
[provider]: {
|
[provider]: {
|
||||||
...(settings?.providerSettings?.[provider] || {}),
|
...settings?.providerSettings?.[provider],
|
||||||
apiKey: undefined,
|
apiKey: undefined,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { Slot } from "@radix-ui/react-slot";
|
import { Slot } from "@radix-ui/react-slot";
|
||||||
import { type VariantProps, cva } from "class-variance-authority";
|
import { type VariantProps, cva } from "class-variance-authority";
|
||||||
import { Menu, PanelLeftIcon } from "lucide-react";
|
import { Menu } from "lucide-react";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
@@ -224,7 +224,6 @@ function Sidebar({
|
|||||||
}
|
}
|
||||||
|
|
||||||
function SidebarTrigger({
|
function SidebarTrigger({
|
||||||
className,
|
|
||||||
onClick,
|
onClick,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof Button>) {
|
}: React.ComponentProps<typeof Button>) {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export function useAppVersion() {
|
|||||||
try {
|
try {
|
||||||
const version = await IpcClient.getInstance().getAppVersion();
|
const version = await IpcClient.getInstance().getAppVersion();
|
||||||
setAppVersion(version);
|
setAppVersion(version);
|
||||||
} catch (error) {
|
} catch {
|
||||||
setAppVersion(null);
|
setAppVersion(null);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { IpcClient } from "@/ipc/ipc_client";
|
import { IpcClient } from "@/ipc/ipc_client";
|
||||||
import type { App } from "@/ipc/ipc_types";
|
|
||||||
import { atom, useAtom } from "jotai";
|
import { useAtom } from "jotai";
|
||||||
import { currentAppAtom } from "@/atoms/appAtoms";
|
import { currentAppAtom } from "@/atoms/appAtoms";
|
||||||
|
|
||||||
export function useLoadApp(appId: number | null) {
|
export function useLoadApp(appId: number | null) {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { IpcClient } from "@/ipc/ipc_client";
|
|||||||
|
|
||||||
export function useLoadApps() {
|
export function useLoadApps() {
|
||||||
const [apps, setApps] = useAtom(appsListAtom);
|
const [apps, setApps] = useAtom(appsListAtom);
|
||||||
const [appBasePath, setAppBasePath] = useAtom(appBasePathAtom);
|
const [, setAppBasePath] = useAtom(appBasePathAtom);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [error, setError] = useState<Error | null>(null);
|
const [error, setError] = useState<Error | null>(null);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useState, useEffect, useCallback } from "react";
|
import { useState, useEffect, useCallback } from "react";
|
||||||
import { IpcClient } from "@/ipc/ipc_client";
|
import { IpcClient } from "@/ipc/ipc_client";
|
||||||
import type { CodeProposal, ProposalResult } from "@/lib/schemas"; // Import Proposal type
|
import type { ProposalResult } from "@/lib/schemas"; // Import Proposal type
|
||||||
import { proposalResultAtom } from "@/atoms/proposalAtoms";
|
import { proposalResultAtom } from "@/atoms/proposalAtoms";
|
||||||
import { useAtom } from "jotai";
|
import { useAtom } from "jotai";
|
||||||
export function useProposal(chatId?: number | undefined) {
|
export function useProposal(chatId?: number | undefined) {
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import {
|
|||||||
selectedAppIdAtom,
|
selectedAppIdAtom,
|
||||||
} from "@/atoms/appAtoms";
|
} from "@/atoms/appAtoms";
|
||||||
import { useAtom, useAtomValue, useSetAtom } from "jotai";
|
import { useAtom, useAtomValue, useSetAtom } from "jotai";
|
||||||
import { App } from "@/ipc/ipc_types";
|
|
||||||
|
|
||||||
export function useRunApp() {
|
export function useRunApp() {
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useState, useEffect, useCallback } from "react";
|
import { useState, useEffect, useCallback } from "react";
|
||||||
import { atom, useAtom } from "jotai";
|
import { useAtom } from "jotai";
|
||||||
import { userSettingsAtom, envVarsAtom } from "@/atoms/appAtoms";
|
import { userSettingsAtom, envVarsAtom } from "@/atoms/appAtoms";
|
||||||
import { IpcClient } from "@/ipc/ipc_client";
|
import { IpcClient } from "@/ipc/ipc_client";
|
||||||
import { cloudProviders, type UserSettings } from "@/lib/schemas";
|
import { cloudProviders, type UserSettings } from "@/lib/schemas";
|
||||||
@@ -11,9 +11,6 @@ const PROVIDER_TO_ENV_VAR: Record<string, string> = {
|
|||||||
google: "GEMINI_API_KEY",
|
google: "GEMINI_API_KEY",
|
||||||
};
|
};
|
||||||
|
|
||||||
// Define a type for the environment variables we expect
|
|
||||||
type EnvVars = Record<string, string | undefined>;
|
|
||||||
|
|
||||||
const TELEMETRY_CONSENT_KEY = "dyadTelemetryConsent";
|
const TELEMETRY_CONSENT_KEY = "dyadTelemetryConsent";
|
||||||
const TELEMETRY_USER_ID_KEY = "dyadTelemetryUserId";
|
const TELEMETRY_USER_ID_KEY = "dyadTelemetryUserId";
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useCallback, useState } from "react";
|
import { useCallback } from "react";
|
||||||
import type { Message } from "@/ipc/ipc_types";
|
import type { Message } from "@/ipc/ipc_types";
|
||||||
import { useAtom, useSetAtom } from "jotai";
|
import { useAtom, useSetAtom } from "jotai";
|
||||||
import {
|
import {
|
||||||
@@ -14,7 +14,7 @@ import { useChats } from "./useChats";
|
|||||||
import { useLoadApp } from "./useLoadApp";
|
import { useLoadApp } from "./useLoadApp";
|
||||||
import { selectedAppIdAtom } from "@/atoms/appAtoms";
|
import { selectedAppIdAtom } from "@/atoms/appAtoms";
|
||||||
import { useVersions } from "./useVersions";
|
import { useVersions } from "./useVersions";
|
||||||
import { showError, showUncommittedFilesWarning } from "@/lib/toast";
|
import { showUncommittedFilesWarning } from "@/lib/toast";
|
||||||
import { useProposal } from "./useProposal";
|
import { useProposal } from "./useProposal";
|
||||||
import { useSearch } from "@tanstack/react-router";
|
import { useSearch } from "@tanstack/react-router";
|
||||||
import { useRunApp } from "./useRunApp";
|
import { useRunApp } from "./useRunApp";
|
||||||
@@ -27,7 +27,7 @@ export function getRandomNumberId() {
|
|||||||
export function useStreamChat({
|
export function useStreamChat({
|
||||||
hasChatId = true,
|
hasChatId = true,
|
||||||
}: { hasChatId?: boolean } = {}) {
|
}: { hasChatId?: boolean } = {}) {
|
||||||
const [messages, setMessages] = useAtom(chatMessagesAtom);
|
const [, setMessages] = useAtom(chatMessagesAtom);
|
||||||
const [isStreaming, setIsStreaming] = useAtom(isStreamingAtom);
|
const [isStreaming, setIsStreaming] = useAtom(isStreamingAtom);
|
||||||
const [error, setError] = useAtom(chatErrorAtom);
|
const [error, setError] = useAtom(chatErrorAtom);
|
||||||
const setIsPreviewOpen = useSetAtom(isPreviewOpenAtom);
|
const setIsPreviewOpen = useSetAtom(isPreviewOpenAtom);
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export function useVersions(appId: number | null) {
|
|||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [error, setError] = useState<Error | null>(null);
|
const [error, setError] = useState<Error | null>(null);
|
||||||
const selectedChatId = useAtomValue(selectedChatIdAtom);
|
const selectedChatId = useAtomValue(selectedChatIdAtom);
|
||||||
const [messages, setMessages] = useAtom(chatMessagesAtom);
|
const [, setMessages] = useAtom(chatMessagesAtom);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const loadVersions = async () => {
|
const loadVersions = async () => {
|
||||||
// If no app is selected, clear versions and return
|
// If no app is selected, clear versions and return
|
||||||
|
|||||||
@@ -1,20 +1,15 @@
|
|||||||
import { ipcMain } from "electron";
|
import { ipcMain } from "electron";
|
||||||
import { db, getDatabasePath } from "../../db";
|
import { db, getDatabasePath } from "../../db";
|
||||||
import { apps, chats, messages } from "../../db/schema";
|
import { apps, chats } from "../../db/schema";
|
||||||
import { desc, eq, and, gte, sql, gt } from "drizzle-orm";
|
import { desc, eq } from "drizzle-orm";
|
||||||
import type {
|
import type { App, CreateAppParams } from "../ipc_types";
|
||||||
App,
|
|
||||||
CreateAppParams,
|
|
||||||
SandboxConfig,
|
|
||||||
Version,
|
|
||||||
} from "../ipc_types";
|
|
||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { getDyadAppPath, getUserDataPath } from "../../paths/paths";
|
import { getDyadAppPath, getUserDataPath } from "../../paths/paths";
|
||||||
import { spawn } from "node:child_process";
|
import { spawn } from "node:child_process";
|
||||||
import git from "isomorphic-git";
|
import git from "isomorphic-git";
|
||||||
import { promises as fsPromises } from "node:fs";
|
import { promises as fsPromises } from "node:fs";
|
||||||
import { extractCodebase } from "../../utils/codebase";
|
|
||||||
// Import our utility modules
|
// Import our utility modules
|
||||||
import { withLock } from "../utils/lock_utils";
|
import { withLock } from "../utils/lock_utils";
|
||||||
import {
|
import {
|
||||||
@@ -26,19 +21,17 @@ import {
|
|||||||
processCounter,
|
processCounter,
|
||||||
killProcess,
|
killProcess,
|
||||||
removeAppIfCurrentProcess,
|
removeAppIfCurrentProcess,
|
||||||
RunningAppInfo,
|
|
||||||
} from "../utils/process_manager";
|
} from "../utils/process_manager";
|
||||||
import { ALLOWED_ENV_VARS } from "../../constants/models";
|
import { ALLOWED_ENV_VARS } from "../../constants/models";
|
||||||
import { getEnvVar } from "../utils/read_env";
|
import { getEnvVar } from "../utils/read_env";
|
||||||
import { readSettings } from "../../main/settings";
|
import { readSettings } from "../../main/settings";
|
||||||
import { Worker } from "worker_threads";
|
|
||||||
import fixPath from "fix-path";
|
import fixPath from "fix-path";
|
||||||
import { getGitAuthor } from "../utils/git_author";
|
import { getGitAuthor } from "../utils/git_author";
|
||||||
import killPort from "kill-port";
|
import killPort from "kill-port";
|
||||||
import util from "util";
|
import util from "util";
|
||||||
import log from "electron-log";
|
import log from "electron-log";
|
||||||
import { getSupabaseProjectName } from "../../supabase_admin/supabase_management_client";
|
import { getSupabaseProjectName } from "../../supabase_admin/supabase_management_client";
|
||||||
import { settings } from "happy-dom/lib/PropertySymbol.js";
|
|
||||||
|
|
||||||
const logger = log.scope("app_handlers");
|
const logger = log.scope("app_handlers");
|
||||||
|
|
||||||
@@ -138,7 +131,7 @@ async function executeAppLocalNode({
|
|||||||
async function killProcessOnPort(port: number): Promise<void> {
|
async function killProcessOnPort(port: number): Promise<void> {
|
||||||
try {
|
try {
|
||||||
await killPort(port, "tcp");
|
await killPort(port, "tcp");
|
||||||
} catch (err) {
|
} catch {
|
||||||
// Ignore if nothing was running on that port
|
// Ignore if nothing was running on that port
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { desc, eq } from "drizzle-orm";
|
|||||||
import type { ChatSummary } from "../../lib/schemas";
|
import type { ChatSummary } from "../../lib/schemas";
|
||||||
import * as git from "isomorphic-git";
|
import * as git from "isomorphic-git";
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import * as path from "path";
|
|
||||||
import log from "electron-log";
|
import log from "electron-log";
|
||||||
import { getDyadAppPath } from "../../paths/paths";
|
import { getDyadAppPath } from "../../paths/paths";
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import * as fs from "fs";
|
|||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
import * as os from "os";
|
import * as os from "os";
|
||||||
import * as crypto from "crypto";
|
import * as crypto from "crypto";
|
||||||
import { stat, readFile, writeFile, mkdir, unlink } from "fs/promises";
|
import { readFile, writeFile, unlink } from "fs/promises";
|
||||||
|
|
||||||
const logger = log.scope("chat_stream_handlers");
|
const logger = log.scope("chat_stream_handlers");
|
||||||
|
|
||||||
@@ -61,19 +61,6 @@ if (!fs.existsSync(TEMP_DIR)) {
|
|||||||
fs.mkdirSync(TEMP_DIR, { recursive: true });
|
fs.mkdirSync(TEMP_DIR, { recursive: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
// First, define the proper content types to match ai SDK
|
|
||||||
type TextContent = {
|
|
||||||
type: "text";
|
|
||||||
text: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
type ImageContent = {
|
|
||||||
type: "image";
|
|
||||||
image: Buffer;
|
|
||||||
};
|
|
||||||
|
|
||||||
type MessageContent = TextContent | ImageContent;
|
|
||||||
|
|
||||||
export function registerChatStreamHandlers() {
|
export function registerChatStreamHandlers() {
|
||||||
ipcMain.handle("chat:stream", async (event, req: ChatStreamParams) => {
|
ipcMain.handle("chat:stream", async (event, req: ChatStreamParams) => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { ipcMain, app } from "electron";
|
import { ipcMain } from "electron";
|
||||||
import { platform, arch } from "os";
|
import { platform, arch } from "os";
|
||||||
import { SystemDebugInfo, ChatLogsData } from "../ipc_types";
|
import { SystemDebugInfo, ChatLogsData } from "../ipc_types";
|
||||||
import { readSettings } from "../../main/settings";
|
import { readSettings } from "../../main/settings";
|
||||||
import { execSync } from "child_process";
|
|
||||||
import log from "electron-log";
|
import log from "electron-log";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
|
|||||||
@@ -1,15 +1,10 @@
|
|||||||
import {
|
import { ipcMain, BrowserWindow, IpcMainInvokeEvent } from "electron";
|
||||||
ipcMain,
|
|
||||||
IpcMainEvent,
|
|
||||||
BrowserWindow,
|
|
||||||
IpcMainInvokeEvent,
|
|
||||||
} from "electron";
|
|
||||||
import fetch from "node-fetch"; // Use node-fetch for making HTTP requests in main process
|
import fetch from "node-fetch"; // Use node-fetch for making HTTP requests in main process
|
||||||
import { writeSettings, readSettings } from "../../main/settings";
|
import { writeSettings, readSettings } from "../../main/settings";
|
||||||
import { updateAppGithubRepo } from "../../db/index";
|
import { updateAppGithubRepo } from "../../db/index";
|
||||||
import git from "isomorphic-git";
|
import git from "isomorphic-git";
|
||||||
import http from "isomorphic-git/http/node";
|
import http from "isomorphic-git/http/node";
|
||||||
import path from "node:path";
|
|
||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
import { getDyadAppPath } from "../../paths/paths";
|
import { getDyadAppPath } from "../../paths/paths";
|
||||||
import { db } from "../../db";
|
import { db } from "../../db";
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ export async function fetchLMStudioModels(): Promise<LocalModelListResponse> {
|
|||||||
|
|
||||||
logger.info(`Successfully fetched ${models.length} models from LM Studio`);
|
logger.info(`Successfully fetched ${models.length} models from LM Studio`);
|
||||||
return { models, error: null };
|
return { models, error: null };
|
||||||
} catch (error) {
|
} catch {
|
||||||
return { models: [], error: "Failed to fetch models from LM Studio" };
|
return { models: [], error: "Failed to fetch models from LM Studio" };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ipcMain, app } from "electron";
|
import { ipcMain } from "electron";
|
||||||
import { exec, execSync } from "child_process";
|
import { execSync } from "child_process";
|
||||||
import { platform, arch } from "os";
|
import { platform, arch } from "os";
|
||||||
import { NodeSystemInfo } from "../ipc_types";
|
import { NodeSystemInfo } from "../ipc_types";
|
||||||
import fixPath from "fix-path";
|
import fixPath from "fix-path";
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
import { ipcMain, type IpcMainInvokeEvent } from "electron";
|
import { ipcMain, type IpcMainInvokeEvent } from "electron";
|
||||||
import type {
|
import type {
|
||||||
CodeProposal,
|
CodeProposal,
|
||||||
FileChange,
|
|
||||||
ProposalResult,
|
ProposalResult,
|
||||||
SqlQuery,
|
|
||||||
ActionProposal,
|
ActionProposal,
|
||||||
} from "../../lib/schemas";
|
} from "../../lib/schemas";
|
||||||
import { db } from "../../db";
|
import { db } from "../../db";
|
||||||
import { messages, chats } from "../../db/schema";
|
import { messages, chats } from "../../db/schema";
|
||||||
import { desc, eq, and, Update } from "drizzle-orm";
|
import { desc, eq, and } from "drizzle-orm";
|
||||||
import path from "node:path"; // Import path for basename
|
import path from "node:path"; // Import path for basename
|
||||||
// Import tag parsers
|
// Import tag parsers
|
||||||
import {
|
import {
|
||||||
@@ -31,26 +29,9 @@ import {
|
|||||||
import { extractCodebase } from "../../utils/codebase";
|
import { extractCodebase } from "../../utils/codebase";
|
||||||
import { getDyadAppPath } from "../../paths/paths";
|
import { getDyadAppPath } from "../../paths/paths";
|
||||||
import { withLock } from "../utils/lock_utils";
|
import { withLock } from "../utils/lock_utils";
|
||||||
|
|
||||||
const logger = log.scope("proposal_handlers");
|
const logger = log.scope("proposal_handlers");
|
||||||
|
|
||||||
// Placeholder Proposal data (can be removed or kept for reference)
|
|
||||||
// const placeholderProposal: Proposal = { ... };
|
|
||||||
|
|
||||||
// Type guard for the parsed proposal structure
|
|
||||||
interface ParsedProposal {
|
|
||||||
title: string;
|
|
||||||
files: string[];
|
|
||||||
}
|
|
||||||
function isParsedProposal(obj: any): obj is ParsedProposal {
|
|
||||||
return (
|
|
||||||
obj &&
|
|
||||||
typeof obj === "object" &&
|
|
||||||
typeof obj.title === "string" &&
|
|
||||||
Array.isArray(obj.files) &&
|
|
||||||
obj.files.every((file: any) => typeof file === "string")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cache for codebase token counts
|
// Cache for codebase token counts
|
||||||
interface CodebaseTokenCache {
|
interface CodebaseTokenCache {
|
||||||
chatId: number;
|
chatId: number;
|
||||||
|
|||||||
@@ -5,28 +5,7 @@ import { readSettings } from "../../main/settings";
|
|||||||
|
|
||||||
export function registerSettingsHandlers() {
|
export function registerSettingsHandlers() {
|
||||||
ipcMain.handle("get-user-settings", async () => {
|
ipcMain.handle("get-user-settings", async () => {
|
||||||
const settings = await readSettings();
|
const settings = readSettings();
|
||||||
|
|
||||||
// Mask API keys before sending to renderer
|
|
||||||
if (settings?.providerSettings) {
|
|
||||||
// Use optional chaining
|
|
||||||
for (const providerKey in settings.providerSettings) {
|
|
||||||
// Ensure the key is own property and providerSetting exists
|
|
||||||
if (
|
|
||||||
Object.prototype.hasOwnProperty.call(
|
|
||||||
settings.providerSettings,
|
|
||||||
providerKey,
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
const providerSetting = settings.providerSettings[providerKey];
|
|
||||||
// Check if apiKey exists and is a non-empty string before masking
|
|
||||||
if (providerSetting?.apiKey?.value) {
|
|
||||||
providerSetting.apiKey = providerSetting.apiKey;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return settings;
|
return settings;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { ipcMain } from "electron";
|
import { ipcMain } from "electron";
|
||||||
import { db } from "../../db";
|
import { db } from "../../db";
|
||||||
import { chats, messages } from "../../db/schema";
|
import { chats } from "../../db/schema";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import { SYSTEM_PROMPT } from "../../prompts/system_prompt";
|
import { SYSTEM_PROMPT } from "../../prompts/system_prompt";
|
||||||
import {
|
import {
|
||||||
@@ -11,8 +11,7 @@ import { getDyadAppPath } from "../../paths/paths";
|
|||||||
import log from "electron-log";
|
import log from "electron-log";
|
||||||
import { extractCodebase } from "../../utils/codebase";
|
import { extractCodebase } from "../../utils/codebase";
|
||||||
import { getSupabaseContext } from "../../supabase_admin/supabase_context";
|
import { getSupabaseContext } from "../../supabase_admin/supabase_context";
|
||||||
import { readSettings } from "../../main/settings";
|
|
||||||
import { MODEL_OPTIONS } from "../../constants/models";
|
|
||||||
import { TokenCountParams } from "../ipc_types";
|
import { TokenCountParams } from "../ipc_types";
|
||||||
import { TokenCountResult } from "../ipc_types";
|
import { TokenCountResult } from "../ipc_types";
|
||||||
import { estimateTokens, getContextWindow } from "../utils/token_utils";
|
import { estimateTokens, getContextWindow } from "../utils/token_utils";
|
||||||
|
|||||||
@@ -133,12 +133,7 @@ export function registerVersionHandlers() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Process each file to revert to the state in previousVersionId
|
// Process each file to revert to the state in previousVersionId
|
||||||
for (const [
|
for (const [filepath, headStatus, workdirStatus] of matrix) {
|
||||||
filepath,
|
|
||||||
headStatus,
|
|
||||||
workdirStatus,
|
|
||||||
stageStatus,
|
|
||||||
] of matrix) {
|
|
||||||
const fullPath = path.join(appPath, filepath);
|
const fullPath = path.join(appPath, filepath);
|
||||||
|
|
||||||
// If file exists in HEAD (previous version)
|
// If file exists in HEAD (previous version)
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import type {
|
|||||||
AppOutput,
|
AppOutput,
|
||||||
Chat,
|
Chat,
|
||||||
ChatResponseEnd,
|
ChatResponseEnd,
|
||||||
ChatStreamParams,
|
|
||||||
CreateAppParams,
|
CreateAppParams,
|
||||||
CreateAppResult,
|
CreateAppResult,
|
||||||
ListAppsResponse,
|
ListAppsResponse,
|
||||||
@@ -18,13 +17,12 @@ import type {
|
|||||||
Version,
|
Version,
|
||||||
SystemDebugInfo,
|
SystemDebugInfo,
|
||||||
LocalModel,
|
LocalModel,
|
||||||
LocalModelListResponse,
|
|
||||||
TokenCountParams,
|
TokenCountParams,
|
||||||
TokenCountResult,
|
TokenCountResult,
|
||||||
ChatLogsData,
|
ChatLogsData,
|
||||||
BranchResult,
|
BranchResult,
|
||||||
} from "./ipc_types";
|
} from "./ipc_types";
|
||||||
import type { CodeProposal, ProposalResult } from "@/lib/schemas";
|
import type { ProposalResult } from "@/lib/schemas";
|
||||||
import { showError } from "@/lib/toast";
|
import { showError } from "@/lib/toast";
|
||||||
|
|
||||||
export interface ChatStreamCallbacks {
|
export interface ChatStreamCallbacks {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import fs from "node:fs";
|
|||||||
import { getDyadAppPath } from "../../paths/paths";
|
import { getDyadAppPath } from "../../paths/paths";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import git from "isomorphic-git";
|
import git from "isomorphic-git";
|
||||||
import { getGithubUser } from "../handlers/github_handlers";
|
|
||||||
import { getGitAuthor } from "../utils/git_author";
|
import { getGitAuthor } from "../utils/git_author";
|
||||||
import log from "electron-log";
|
import log from "electron-log";
|
||||||
import { executeAddDependency } from "./executeAddDependency";
|
import { executeAddDependency } from "./executeAddDependency";
|
||||||
@@ -229,7 +229,7 @@ export async function processFullResponseActions(
|
|||||||
if (dyadExecuteSqlQueries.length > 0) {
|
if (dyadExecuteSqlQueries.length > 0) {
|
||||||
for (const query of dyadExecuteSqlQueries) {
|
for (const query of dyadExecuteSqlQueries) {
|
||||||
try {
|
try {
|
||||||
const result = await executeSupabaseSql({
|
await executeSupabaseSql({
|
||||||
supabaseProjectId: chatWithApp.app.supabaseProjectId!,
|
supabaseProjectId: chatWithApp.app.supabaseProjectId!,
|
||||||
query: query.content,
|
query: query.content,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { createOpenAI, OpenAIProvider } from "@ai-sdk/openai";
|
import { createOpenAI } from "@ai-sdk/openai";
|
||||||
import { createGoogleGenerativeAI as createGoogle } from "@ai-sdk/google";
|
import { createGoogleGenerativeAI as createGoogle } from "@ai-sdk/google";
|
||||||
import { createAnthropic } from "@ai-sdk/anthropic";
|
import { createAnthropic } from "@ai-sdk/anthropic";
|
||||||
import { createOpenRouter } from "@openrouter/ai-sdk-provider";
|
import { createOpenRouter } from "@openrouter/ai-sdk-provider";
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ export async function withLock<T>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Acquire a new lock
|
// Acquire a new lock
|
||||||
const { release, promise } = acquireLock(lockId);
|
const { release } = acquireLock(lockId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await fn();
|
const result = await fn();
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import type { Message } from "ai";
|
|
||||||
import { IpcClient } from "../ipc/ipc_client";
|
import { IpcClient } from "../ipc/ipc_client";
|
||||||
import type { ChatSummary } from "./schemas";
|
import type { ChatSummary } from "./schemas";
|
||||||
import type { CreateAppParams, CreateAppResult } from "../ipc/ipc_types";
|
import type { CreateAppParams, CreateAppResult } from "../ipc/ipc_types";
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ export const showLoading = <T>(
|
|||||||
) => {
|
) => {
|
||||||
return toast.promise(promise, {
|
return toast.promise(promise, {
|
||||||
loading: loadingMessage,
|
loading: loadingMessage,
|
||||||
success: (data) => successMessage || "Operation completed successfully",
|
success: () => successMessage || "Operation completed successfully",
|
||||||
error: (err) => errorMessage || `Error: ${err.message || "Unknown error"}`,
|
error: (err) => errorMessage || `Error: ${err.message || "Unknown error"}`,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ const gotTheLock = app.requestSingleInstanceLock();
|
|||||||
if (!gotTheLock) {
|
if (!gotTheLock) {
|
||||||
app.quit();
|
app.quit();
|
||||||
} else {
|
} else {
|
||||||
app.on("second-instance", (event, commandLine, workingDirectory) => {
|
app.on("second-instance", (_event, commandLine, _workingDirectory) => {
|
||||||
// Someone tried to run a second instance, we should focus our window.
|
// Someone tried to run a second instance, we should focus our window.
|
||||||
if (mainWindow) {
|
if (mainWindow) {
|
||||||
if (mainWindow.isMinimized()) mainWindow.restore();
|
if (mainWindow.isMinimized()) mainWindow.restore();
|
||||||
|
|||||||
@@ -3,15 +3,13 @@ import { useAtom, useAtomValue } from "jotai";
|
|||||||
import { appBasePathAtom, appsListAtom } from "@/atoms/appAtoms";
|
import { appBasePathAtom, appsListAtom } from "@/atoms/appAtoms";
|
||||||
import { IpcClient } from "@/ipc/ipc_client";
|
import { IpcClient } from "@/ipc/ipc_client";
|
||||||
import { useLoadApps } from "@/hooks/useLoadApps";
|
import { useLoadApps } from "@/hooks/useLoadApps";
|
||||||
import { useState, useEffect } from "react";
|
import { useState } from "react";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
ArrowLeft,
|
ArrowLeft,
|
||||||
MoreVertical,
|
MoreVertical,
|
||||||
ArrowRight,
|
|
||||||
MessageCircle,
|
MessageCircle,
|
||||||
Pencil,
|
Pencil,
|
||||||
Github,
|
|
||||||
Folder,
|
Folder,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import {
|
import {
|
||||||
@@ -30,7 +28,6 @@ import {
|
|||||||
} from "@/components/ui/dialog";
|
} from "@/components/ui/dialog";
|
||||||
import { GitHubConnector } from "@/components/GitHubConnector";
|
import { GitHubConnector } from "@/components/GitHubConnector";
|
||||||
import { SupabaseConnector } from "@/components/SupabaseConnector";
|
import { SupabaseConnector } from "@/components/SupabaseConnector";
|
||||||
import { useSettings } from "@/hooks/useSettings";
|
|
||||||
|
|
||||||
export default function AppDetailsPage() {
|
export default function AppDetailsPage() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -50,7 +47,7 @@ export default function AppDetailsPage() {
|
|||||||
const [newFolderName, setNewFolderName] = useState("");
|
const [newFolderName, setNewFolderName] = useState("");
|
||||||
const [isRenamingFolder, setIsRenamingFolder] = useState(false);
|
const [isRenamingFolder, setIsRenamingFolder] = useState(false);
|
||||||
const appBasePath = useAtomValue(appBasePathAtom);
|
const appBasePath = useAtomValue(appBasePathAtom);
|
||||||
const { settings } = useSettings();
|
|
||||||
// Get the appId from search params and find the corresponding app
|
// Get the appId from search params and find the corresponding app
|
||||||
const appId = search.appId ? Number(search.appId) : null;
|
const appId = search.appId ? Number(search.appId) : null;
|
||||||
const selectedApp = appId ? appsList.find((app) => app.id === appId) : null;
|
const selectedApp = appId ? appsList.find((app) => app.id === appId) : null;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useState } from "react";
|
||||||
import { useTheme } from "../contexts/ThemeContext";
|
import { useTheme } from "../contexts/ThemeContext";
|
||||||
import { ProviderSettingsGrid } from "@/components/ProviderSettings";
|
import { ProviderSettingsGrid } from "@/components/ProviderSettings";
|
||||||
import ConfirmationDialog from "@/components/ConfirmationDialog";
|
import ConfirmationDialog from "@/components/ConfirmationDialog";
|
||||||
@@ -113,7 +113,7 @@ export default function SettingsPage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="bg-white dark:bg-gray-800 rounded-xl shadow-sm">
|
<div className="bg-white dark:bg-gray-800 rounded-xl shadow-sm">
|
||||||
<ProviderSettingsGrid configuredProviders={[]} />
|
<ProviderSettingsGrid />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ export function getElectron(): typeof import("electron") | undefined {
|
|||||||
if (process.versions.electron) {
|
if (process.versions.electron) {
|
||||||
electron = require("electron");
|
electron = require("electron");
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch {
|
||||||
// Not in Electron environment
|
// Not in Electron environment
|
||||||
}
|
}
|
||||||
return electron;
|
return electron;
|
||||||
|
|||||||
@@ -226,7 +226,7 @@ async function safeParseErrorResponseBody(
|
|||||||
) {
|
) {
|
||||||
return { message: body.message };
|
return { message: body.message };
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ async function isGitIgnored(
|
|||||||
gitIgnoreMtimes.set(rootGitIgnorePath, stats.mtimeMs);
|
gitIgnoreMtimes.set(rootGitIgnorePath, stats.mtimeMs);
|
||||||
shouldClearCache = true;
|
shouldClearCache = true;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch {
|
||||||
// Root .gitignore might not exist, which is fine
|
// Root .gitignore might not exist, which is fine
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,7 +86,7 @@ async function isGitIgnored(
|
|||||||
gitIgnoreMtimes.set(gitIgnorePath, stats.mtimeMs);
|
gitIgnoreMtimes.set(gitIgnorePath, stats.mtimeMs);
|
||||||
shouldClearCache = true;
|
shouldClearCache = true;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch {
|
||||||
// This directory might not have a .gitignore, which is fine
|
// This directory might not have a .gitignore, which is fine
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -324,41 +324,3 @@ async function sortFilesByModificationTime(files: string[]): Promise<string[]> {
|
|||||||
// Sort by modification time (oldest first)
|
// Sort by modification time (oldest first)
|
||||||
return fileStats.sort((a, b) => a.mtime - b.mtime).map((item) => item.file);
|
return fileStats.sort((a, b) => a.mtime - b.mtime).map((item) => item.file);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sort files by their importance for context
|
|
||||||
*/
|
|
||||||
function sortFilesByImportance(files: string[], baseDir: string): string[] {
|
|
||||||
// Define patterns for important files
|
|
||||||
const highPriorityPatterns = [
|
|
||||||
new RegExp(`(^|/)${ALWAYS_INCLUDE_FILES[0]}$`),
|
|
||||||
/tsconfig\.json$/,
|
|
||||||
/README\.md$/,
|
|
||||||
/index\.(ts|js)x?$/,
|
|
||||||
/main\.(ts|js)x?$/,
|
|
||||||
/app\.(ts|js)x?$/,
|
|
||||||
];
|
|
||||||
|
|
||||||
// Custom sorting function
|
|
||||||
return [...files].sort((a, b) => {
|
|
||||||
const relativeA = path.relative(baseDir, a);
|
|
||||||
const relativeB = path.relative(baseDir, b);
|
|
||||||
|
|
||||||
// Check if file A matches any high priority pattern
|
|
||||||
const aIsHighPriority = highPriorityPatterns.some((pattern) =>
|
|
||||||
pattern.test(relativeA),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Check if file B matches any high priority pattern
|
|
||||||
const bIsHighPriority = highPriorityPatterns.some((pattern) =>
|
|
||||||
pattern.test(relativeB),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Sort by priority first
|
|
||||||
if (aIsHighPriority && !bIsHighPriority) return -1;
|
|
||||||
if (!aIsHighPriority && bIsHighPriority) return 1;
|
|
||||||
|
|
||||||
// If both are same priority, sort alphabetically
|
|
||||||
return relativeA.localeCompare(relativeB);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user