Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
B
bit-pm
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
燕伟桐
bit-pm
Commits
c71638a5
Unverified
提交
c71638a5
authored
5月 09, 2025
作者:
Will Chen
提交者:
GitHub
5月 09, 2025
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Simplify handlers & IPC client: move from Result pattern to throwing errors (#120)
上级
26305ee0
全部展开
显示空白字符变更
内嵌
并排
正在显示
25 个修改的文件
包含
137 行增加
和
289 行删除
+137
-289
ChatList.tsx
src/components/ChatList.tsx
+1
-5
GitHubConnector.tsx
src/components/GitHubConnector.tsx
+2
-10
HelpDialog.tsx
src/components/HelpDialog.tsx
+1
-6
ChatInput.tsx
src/components/chat/ChatInput.tsx
+6
-16
MessagesList.tsx
src/components/chat/MessagesList.tsx
+3
-4
FileEditor.tsx
src/components/preview_panel/FileEditor.tsx
+2
-2
useSupabase.ts
src/hooks/useSupabase.ts
+2
-14
app_handlers.ts
src/ipc/handlers/app_handlers.ts
+42
-31
chat_handlers.ts
src/ipc/handlers/chat_handlers.ts
+7
-21
dependency_handlers.ts
src/ipc/handlers/dependency_handlers.ts
+7
-3
github_handlers.ts
src/ipc/handlers/github_handlers.ts
+6
-21
local_model_lmstudio_handler.ts
src/ipc/handlers/local_model_lmstudio_handler.ts
+1
-5
local_model_ollama_handler.ts
src/ipc/handlers/local_model_ollama_handler.ts
+4
-7
proposal_handlers.ts
src/ipc/handlers/proposal_handlers.ts
+12
-44
safe_handle.ts
src/ipc/handlers/safe_handle.ts
+5
-2
settings_handlers.ts
src/ipc/handlers/settings_handlers.ts
+2
-0
shell_handler.ts
src/ipc/handlers/shell_handler.ts
+12
-28
supabase_handlers.ts
src/ipc/handlers/supabase_handlers.ts
+7
-31
token_count_handlers.ts
src/ipc/handlers/token_count_handlers.ts
+5
-15
upload_handlers.ts
src/ipc/handlers/upload_handlers.ts
+5
-15
version_handlers.ts
src/ipc/handlers/version_handlers.ts
+2
-2
ipc_client.ts
src/ipc/ipc_client.ts
+0
-0
ipc_types.ts
src/ipc/ipc_types.ts
+0
-1
app-details.tsx
src/pages/app-details.tsx
+2
-1
settings.tsx
src/pages/settings.tsx
+1
-5
没有找到文件。
src/components/ChatList.tsx
浏览文件 @
c71638a5
...
...
@@ -92,11 +92,7 @@ export function ChatList({ show }: { show?: boolean }) {
const
handleDeleteChat
=
async
(
chatId
:
number
)
=>
{
try
{
const
result
=
await
IpcClient
.
getInstance
().
deleteChat
(
chatId
);
if
(
!
result
.
success
)
{
showError
(
"Failed to delete chat"
);
return
;
}
await
IpcClient
.
getInstance
().
deleteChat
(
chatId
);
showSuccess
(
"Chat deleted successfully"
);
// If the deleted chat was selected, navigate to home
...
...
src/components/GitHubConnector.tsx
浏览文件 @
c71638a5
...
...
@@ -153,18 +153,14 @@ export function GitHubConnector({ appId, folderName }: GitHubConnectorProps) {
setIsCreatingRepo
(
true
);
setCreateRepoSuccess
(
false
);
try
{
const
result
=
await
IpcClient
.
getInstance
().
createGithubRepo
(
await
IpcClient
.
getInstance
().
createGithubRepo
(
githubOrg
,
repoName
,
appId
!
,
);
if
(
result
.
success
)
{
setCreateRepoSuccess
(
true
);
setRepoCheckError
(
null
);
refreshApp
();
}
else
{
setCreateRepoError
(
result
.
error
||
"Failed to create repository."
);
}
}
catch
(
err
:
any
)
{
setCreateRepoError
(
err
.
message
||
"Failed to create repository."
);
}
finally
{
...
...
@@ -180,12 +176,8 @@ export function GitHubConnector({ appId, folderName }: GitHubConnectorProps) {
setIsDisconnecting
(
true
);
setDisconnectError
(
null
);
try
{
const
result
=
await
IpcClient
.
getInstance
().
disconnectGithubRepo
(
appId
);
if
(
result
.
success
)
{
await
IpcClient
.
getInstance
().
disconnectGithubRepo
(
appId
);
refreshApp
();
}
else
{
setDisconnectError
(
result
.
error
||
"Failed to disconnect repository."
);
}
}
catch
(
err
:
any
)
{
setDisconnectError
(
err
.
message
||
"Failed to disconnect repository."
);
}
finally
{
...
...
src/components/HelpDialog.tsx
浏览文件 @
c71638a5
...
...
@@ -171,17 +171,12 @@ ${debugInfo.logs.slice(-3_500) || "No logs available"}
const
{
uploadUrl
,
filename
}
=
await
response
.
json
();
// Upload to the signed URL using IPC
const
uploadResult
=
await
IpcClient
.
getInstance
().
uploadToSignedUrl
(
await
IpcClient
.
getInstance
().
uploadToSignedUrl
(
uploadUrl
,
"application/json"
,
chatLogsJson
,
);
if
(
!
uploadResult
.
success
)
{
throw
new
Error
(
`Failed to upload logs:
${
uploadResult
.
error
}
`
);
}
// Extract session ID (filename without extension)
const
sessionId
=
filename
.
replace
(
".json"
,
""
);
setSessionId
(
sessionId
);
...
...
src/components/chat/ChatInput.tsx
浏览文件 @
c71638a5
...
...
@@ -58,7 +58,7 @@ import { useVersions } from "@/hooks/useVersions";
import
{
useAttachments
}
from
"@/hooks/useAttachments"
;
import
{
AttachmentsList
}
from
"./AttachmentsList"
;
import
{
DragDropOverlay
}
from
"./DragDropOverlay"
;
import
{
showUncommittedFilesWarning
}
from
"@/lib/toast"
;
import
{
show
Error
,
show
UncommittedFilesWarning
}
from
"@/lib/toast"
;
const
showTokenBarAtom
=
atom
(
false
);
export
function
ChatInput
({
chatId
}:
{
chatId
?:
number
})
{
...
...
@@ -182,13 +182,6 @@ export function ChatInput({ chatId }: { chatId?: number }) {
chatId
,
messageId
,
});
if
(
result
.
success
)
{
console
.
log
(
"Proposal approved successfully"
);
// TODO: Maybe refresh proposal state or show confirmation?
}
else
{
console
.
error
(
"Failed to approve proposal:"
,
result
.
error
);
setError
(
result
.
error
||
"Failed to approve proposal"
);
}
if
(
result
.
uncommittedFiles
)
{
showUncommittedFilesWarning
(
result
.
uncommittedFiles
);
}
...
...
@@ -215,17 +208,10 @@ export function ChatInput({ chatId }: { chatId?: number }) {
setIsRejecting
(
true
);
posthog
.
capture
(
"chat:reject"
);
try
{
const
result
=
await
IpcClient
.
getInstance
().
rejectProposal
({
await
IpcClient
.
getInstance
().
rejectProposal
({
chatId
,
messageId
,
});
if
(
result
.
success
)
{
console
.
log
(
"Proposal rejected successfully"
);
// TODO: Maybe refresh proposal state or show confirmation?
}
else
{
console
.
error
(
"Failed to reject proposal:"
,
result
.
error
);
setError
(
result
.
error
||
"Failed to reject proposal"
);
}
}
catch
(
err
)
{
console
.
error
(
"Error rejecting proposal:"
,
err
);
setError
((
err
as
Error
)?.
message
||
"An error occurred while rejecting"
);
...
...
@@ -389,6 +375,7 @@ function SummarizeInNewChatButton() {
console
.
error
(
"No app id found"
);
return
;
}
try
{
const
newChatId
=
await
IpcClient
.
getInstance
().
createChat
(
appId
);
// navigate to new chat
await
navigate
({
to
:
"/chat"
,
search
:
{
id
:
newChatId
}
});
...
...
@@ -396,6 +383,9 @@ function SummarizeInNewChatButton() {
prompt
:
"Summarize from chat-id="
+
chatId
,
chatId
:
newChatId
,
});
}
catch
(
err
)
{
showError
(
err
);
}
};
return
(
<
TooltipProvider
>
...
...
src/components/chat/MessagesList.tsx
浏览文件 @
c71638a5
...
...
@@ -89,14 +89,13 @@ export const MessagesList = forwardRef<HTMLDivElement, MessagesListProps>(
await
revertVersion
({
versionId
:
chat
.
initialCommitHash
,
});
const
result
=
try
{
await
IpcClient
.
getInstance
().
deleteMessages
(
selectedChatId
,
);
if
(
result
.
success
)
{
setMessages
([]);
}
else
{
showError
(
result
.
erro
r
);
}
catch
(
err
)
{
showError
(
er
r
);
}
}
else
{
showWarning
(
...
...
src/components/preview_panel/FileEditor.tsx
浏览文件 @
c71638a5
...
...
@@ -6,6 +6,7 @@ import { ChevronRight, Circle } from "lucide-react";
import
"@/components/chat/monaco"
;
import
{
IpcClient
}
from
"@/ipc/ipc_client"
;
import
{
useSettings
}
from
"@/hooks/useSettings"
;
import
{
showError
}
from
"@/lib/toast"
;
interface
FileEditorProps
{
appId
:
number
|
null
;
...
...
@@ -132,8 +133,7 @@ export const FileEditor = ({ appId, filePath }: FileEditorProps) => {
needsSaveRef
.
current
=
false
;
setDisplayUnsavedChanges
(
false
);
}
catch
(
error
)
{
console
.
error
(
"Error saving file:"
,
error
);
// Could add error notification here
showError
(
error
);
}
finally
{
isSavingRef
.
current
=
false
;
}
...
...
src/hooks/useSupabase.ts
浏览文件 @
c71638a5
...
...
@@ -42,14 +42,8 @@ export function useSupabase() {
async
(
projectId
:
string
,
appId
:
number
)
=>
{
setLoading
(
true
);
try
{
const
result
=
await
ipcClient
.
setSupabaseAppProject
(
projectId
,
appId
);
if
(
result
.
success
)
{
await
ipcClient
.
setSupabaseAppProject
(
projectId
,
appId
);
setError
(
null
);
return
result
;
}
else
{
throw
new
Error
(
"Failed to set project for app"
);
}
}
catch
(
error
)
{
console
.
error
(
"Error setting Supabase project for app:"
,
error
);
setError
(
error
instanceof
Error
?
error
:
new
Error
(
String
(
error
)));
...
...
@@ -68,14 +62,8 @@ export function useSupabase() {
async
(
appId
:
number
)
=>
{
setLoading
(
true
);
try
{
const
result
=
await
ipcClient
.
unsetSupabaseAppProject
(
appId
);
if
(
result
.
success
)
{
await
ipcClient
.
unsetSupabaseAppProject
(
appId
);
setError
(
null
);
return
result
;
}
else
{
throw
new
Error
(
"Failed to unset project for app"
);
}
}
catch
(
error
)
{
console
.
error
(
"Error unsetting Supabase project for app:"
,
error
);
setError
(
error
instanceof
Error
?
error
:
new
Error
(
String
(
error
)));
...
...
src/ipc/handlers/app_handlers.ts
浏览文件 @
c71638a5
...
...
@@ -32,8 +32,10 @@ import killPort from "kill-port";
import
util
from
"util"
;
import
log
from
"electron-log"
;
import
{
getSupabaseProjectName
}
from
"../../supabase_admin/supabase_management_client"
;
import
{
createLoggedHandler
}
from
"./safe_handle"
;
const
logger
=
log
.
scope
(
"app_handlers"
);
const
handle
=
createLoggedHandler
(
logger
);
// Needed, otherwise electron in MacOS/Linux will not be able
// to find node/pnpm.
...
...
@@ -137,7 +139,12 @@ async function killProcessOnPort(port: number): Promise<void> {
}
export
function
registerAppHandlers
()
{
ipcMain
.
handle
(
"create-app"
,
async
(
_
,
params
:
CreateAppParams
)
=>
{
handle
(
"create-app"
,
async
(
_
,
params
:
CreateAppParams
,
):
Promise
<
{
app
:
any
;
chatId
:
number
}
>
=>
{
const
appPath
=
params
.
name
;
const
fullAppPath
=
getDyadAppPath
(
appPath
);
if
(
fs
.
existsSync
(
fullAppPath
))
{
...
...
@@ -200,12 +207,12 @@ export function registerAppHandlers() {
}
catch
(
error
)
{
logger
.
error
(
"Error in background app initialization:"
,
error
);
}
// })();
return
{
app
,
chatId
:
chat
.
id
};
});
},
);
ipcMain
.
handle
(
"get-app"
,
async
(
_
,
appId
:
number
):
Promise
<
App
>
=>
{
handle
(
"get-app"
,
async
(
_
,
appId
:
number
):
Promise
<
App
>
=>
{
const
app
=
await
db
.
query
.
apps
.
findFirst
({
where
:
eq
(
apps
.
id
,
appId
),
});
...
...
@@ -281,6 +288,7 @@ export function registerAppHandlers() {
},
);
// Do NOT use handle for this, it contains sensitive information.
ipcMain
.
handle
(
"get-env-vars"
,
async
()
=>
{
const
envVars
:
Record
<
string
,
string
|
undefined
>
=
{};
for
(
const
key
of
ALLOWED_ENV_VARS
)
{
...
...
@@ -294,13 +302,12 @@ export function registerAppHandlers() {
async
(
event
:
Electron
.
IpcMainInvokeEvent
,
{
appId
}:
{
appId
:
number
},
)
=>
{
)
:
Promise
<
void
>
=>
{
return
withLock
(
appId
,
async
()
=>
{
// Check if app is already running
if
(
runningApps
.
has
(
appId
))
{
logger
.
debug
(
`App
${
appId
}
is already running.`
);
// Potentially return the existing process info or confirm status
return
{
success
:
true
,
message
:
"App already running."
};
return
;
}
const
app
=
await
db
.
query
.
apps
.
findFirst
({
...
...
@@ -315,9 +322,9 @@ export function registerAppHandlers() {
const
appPath
=
getDyadAppPath
(
app
.
path
);
try
{
const
currentProcessId
=
await
executeApp
({
appPath
,
appId
,
event
});
await
executeApp
({
appPath
,
appId
,
event
});
return
{
success
:
true
,
processId
:
currentProcessId
}
;
return
;
}
catch
(
error
:
any
)
{
logger
.
error
(
`Error running app
${
appId
}
:`
,
error
);
// Ensure cleanup if error happens during setup but before process events are handled
...
...
@@ -333,7 +340,9 @@ export function registerAppHandlers() {
},
);
ipcMain
.
handle
(
"stop-app"
,
async
(
_
,
{
appId
}:
{
appId
:
number
})
=>
{
ipcMain
.
handle
(
"stop-app"
,
async
(
_
,
{
appId
}:
{
appId
:
number
}):
Promise
<
void
>
=>
{
logger
.
log
(
`Attempting to stop app
${
appId
}
. Current running apps:
${
runningApps
.
size
}
`
,
);
...
...
@@ -344,10 +353,7 @@ export function registerAppHandlers() {
logger
.
log
(
`App
${
appId
}
not found in running apps map. Assuming already stopped.`
,
);
return
{
success
:
true
,
message
:
"App not running."
,
};
return
;
}
const
{
process
,
processId
}
=
appInfo
;
...
...
@@ -361,7 +367,7 @@ export function registerAppHandlers() {
`Process for app
${
appId
}
(PID:
${
process
.
pid
}
) already exited (code:
${
process
.
exitCode
}
, signal:
${
process
.
signalCode
}
). Cleaning up map.`
,
);
runningApps
.
delete
(
appId
);
// Ensure cleanup if somehow missed
return
{
success
:
true
,
message
:
"Process already exited."
}
;
return
;
}
try
{
...
...
@@ -371,7 +377,7 @@ export function registerAppHandlers() {
// Now, safely remove the app from the map *after* confirming closure
removeAppIfCurrentProcess
(
appId
,
process
);
return
{
success
:
true
}
;
return
;
}
catch
(
error
:
any
)
{
logger
.
error
(
`Error stopping app
${
appId
}
(PID:
${
process
.
pid
}
, processId:
${
processId
}
):`
,
...
...
@@ -382,7 +388,8 @@ export function registerAppHandlers() {
throw
new
Error
(
`Failed to stop app
${
appId
}
:
${
error
.
message
}
`
);
}
});
});
},
);
ipcMain
.
handle
(
"restart-app"
,
...
...
@@ -392,7 +399,7 @@ export function registerAppHandlers() {
appId
,
removeNodeModules
,
}:
{
appId
:
number
;
removeNodeModules
?:
boolean
},
)
=>
{
)
:
Promise
<
void
>
=>
{
logger
.
log
(
`Restarting app
${
appId
}
`
);
return
withLock
(
appId
,
async
()
=>
{
try
{
...
...
@@ -447,7 +454,7 @@ export function registerAppHandlers() {
await
executeApp
({
appPath
,
appId
,
event
});
// This will handle starting either mode
return
{
success
:
true
}
;
return
;
}
catch
(
error
)
{
logger
.
error
(
`Error restarting app
${
appId
}
:`
,
error
);
throw
error
;
...
...
@@ -465,7 +472,7 @@ export function registerAppHandlers() {
filePath
,
content
,
}:
{
appId
:
number
;
filePath
:
string
;
content
:
string
},
)
=>
{
)
:
Promise
<
void
>
=>
{
const
app
=
await
db
.
query
.
apps
.
findFirst
({
where
:
eq
(
apps
.
id
,
appId
),
});
...
...
@@ -505,7 +512,7 @@ export function registerAppHandlers() {
});
}
return
{
success
:
true
}
;
return
;
}
catch
(
error
:
any
)
{
logger
.
error
(
`Error writing file
${
filePath
}
for app
${
appId
}
:`
,
error
);
throw
new
Error
(
`Failed to write file:
${
error
.
message
}
`
);
...
...
@@ -513,7 +520,9 @@ export function registerAppHandlers() {
},
);
ipcMain
.
handle
(
"delete-app"
,
async
(
_
,
{
appId
}:
{
appId
:
number
})
=>
{
ipcMain
.
handle
(
"delete-app"
,
async
(
_
,
{
appId
}:
{
appId
:
number
}):
Promise
<
void
>
=>
{
// Static server worker is NOT terminated here anymore
return
withLock
(
appId
,
async
()
=>
{
...
...
@@ -552,13 +561,16 @@ export function registerAppHandlers() {
try
{
await
db
.
delete
(
apps
).
where
(
eq
(
apps
.
id
,
appId
));
// Note: Associated chats will cascade delete if that's set up in the schema
return
{
success
:
true
}
;
return
;
}
catch
(
error
:
any
)
{
logger
.
error
(
`Error deleting app
${
appId
}
from database:`
,
error
);
throw
new
Error
(
`Failed to delete app from database:
${
error
.
message
}
`
);
throw
new
Error
(
`Failed to delete app from database:
${
error
.
message
}
`
,
);
}
});
});
},
);
ipcMain
.
handle
(
"rename-app"
,
...
...
@@ -569,7 +581,7 @@ export function registerAppHandlers() {
appName
,
appPath
,
}:
{
appId
:
number
;
appName
:
string
;
appPath
:
string
},
)
=>
{
)
:
Promise
<
void
>
=>
{
return
withLock
(
appId
,
async
()
=>
{
// Check if app exists
const
app
=
await
db
.
query
.
apps
.
findFirst
({
...
...
@@ -642,7 +654,7 @@ export function registerAppHandlers() {
// Update app in database
try
{
const
[
updatedApp
]
=
await
db
await
db
.
update
(
apps
)
.
set
({
name
:
appName
,
...
...
@@ -651,7 +663,7 @@ export function registerAppHandlers() {
.
where
(
eq
(
apps
.
id
,
appId
))
.
returning
();
return
{
success
:
true
,
app
:
updatedApp
}
;
return
;
}
catch
(
error
:
any
)
{
// Attempt to rollback the file move
if
(
newAppPath
!==
oldAppPath
)
{
...
...
@@ -672,7 +684,7 @@ export function registerAppHandlers() {
},
);
ipcMain
.
handle
(
"reset-all"
,
async
()
=>
{
ipcMain
.
handle
(
"reset-all"
,
async
()
:
Promise
<
void
>
=>
{
logger
.
log
(
"start: resetting all apps and settings."
);
// Stop all running apps first
logger
.
log
(
"stopping all running apps..."
);
...
...
@@ -722,10 +734,9 @@ export function registerAppHandlers() {
}
logger
.
log
(
"all app files removed."
);
logger
.
log
(
"reset all complete."
);
return
{
success
:
true
,
message
:
"Successfully reset everything"
};
});
ipcMain
.
handle
(
"get-app-version"
,
async
()
=>
{
ipcMain
.
handle
(
"get-app-version"
,
async
()
:
Promise
<
{
version
:
string
}
>
=>
{
// Read version from package.json at project root
const
packageJsonPath
=
path
.
resolve
(
__dirname
,
".."
,
".."
,
"package.json"
);
const
packageJson
=
JSON
.
parse
(
fs
.
readFileSync
(
packageJsonPath
,
"utf-8"
));
...
...
src/ipc/handlers/chat_handlers.ts
浏览文件 @
c71638a5
...
...
@@ -5,14 +5,16 @@ import { desc, eq } from "drizzle-orm";
import
type
{
ChatSummary
}
from
"../../lib/schemas"
;
import
*
as
git
from
"isomorphic-git"
;
import
*
as
fs
from
"fs"
;
import
{
createLoggedHandler
}
from
"./safe_handle"
;
import
log
from
"electron-log"
;
import
{
getDyadAppPath
}
from
"../../paths/paths"
;
const
logger
=
log
.
scope
(
"chat_handlers"
);
const
handle
=
createLoggedHandler
(
logger
);
export
function
registerChatHandlers
()
{
ipcMain
.
handle
(
"create-chat"
,
async
(
_
,
appId
:
number
)
=>
{
handle
(
"create-chat"
,
async
(
_
,
appId
:
number
):
Promise
<
number
>
=>
{
// Get the app's path first
const
app
=
await
db
.
query
.
apps
.
findFirst
({
where
:
eq
(
apps
.
id
,
appId
),
...
...
@@ -74,9 +76,7 @@ export function registerChatHandlers() {
return
chat
;
});
ipcMain
.
handle
(
"get-chats"
,
async
(
_
,
appId
?:
number
):
Promise
<
ChatSummary
[]
>
=>
{
handle
(
"get-chats"
,
async
(
_
,
appId
?:
number
):
Promise
<
ChatSummary
[]
>
=>
{
// If appId is provided, filter chats for that app
const
query
=
appId
?
db
.
query
.
chats
.
findMany
({
...
...
@@ -101,27 +101,13 @@ export function registerChatHandlers() {
const
allChats
=
await
query
;
return
allChats
;
},
);
});
ipcMain
.
handle
(
"delete-chat"
,
async
(
_
,
chatId
:
number
)
=>
{
try
{
// Delete the chat and its associated messages
handle
(
"delete-chat"
,
async
(
_
,
chatId
:
number
):
Promise
<
void
>
=>
{
await
db
.
delete
(
chats
).
where
(
eq
(
chats
.
id
,
chatId
));
return
{
success
:
true
};
}
catch
(
error
)
{
logger
.
error
(
"Error deleting chat:"
,
error
);
return
{
success
:
false
,
error
:
(
error
as
Error
).
message
};
}
});
ipcMain
.
handle
(
"delete-messages"
,
async
(
_
,
chatId
:
number
)
=>
{
try
{
handle
(
"delete-messages"
,
async
(
_
,
chatId
:
number
):
Promise
<
void
>
=>
{
await
db
.
delete
(
messages
).
where
(
eq
(
messages
.
chatId
,
chatId
));
return
{
success
:
true
};
}
catch
(
error
)
{
logger
.
error
(
"Error deleting messages:"
,
error
);
return
{
success
:
false
,
error
:
(
error
as
Error
).
message
};
}
});
}
src/ipc/handlers/dependency_handlers.ts
浏览文件 @
c71638a5
import
{
ipcMain
}
from
"electron"
;
import
{
db
}
from
"../../db"
;
import
{
messages
,
apps
,
chats
}
from
"../../db/schema"
;
import
{
eq
}
from
"drizzle-orm"
;
import
{
getDyadAppPath
}
from
"../../paths/paths"
;
import
{
executeAddDependency
}
from
"../processors/executeAddDependency"
;
import
{
createLoggedHandler
}
from
"./safe_handle"
;
import
log
from
"electron-log"
;
const
logger
=
log
.
scope
(
"dependency_handlers"
);
const
handle
=
createLoggedHandler
(
logger
);
export
function
registerDependencyHandlers
()
{
ipcMain
.
handle
(
handle
(
"chat:add-dep"
,
async
(
_event
,
{
chatId
,
packages
}:
{
chatId
:
number
;
packages
:
string
[]
},
)
=>
{
)
:
Promise
<
void
>
=>
{
// Find the message from the database
const
foundMessages
=
await
db
.
query
.
messages
.
findMany
({
where
:
eq
(
messages
.
chatId
,
chatId
),
...
...
src/ipc/handlers/github_handlers.ts
浏览文件 @
c71638a5
...
...
@@ -285,7 +285,7 @@ function handleStartGithubFlow(
async
function
handleIsRepoAvailable
(
event
:
IpcMainInvokeEvent
,
{
org
,
repo
}:
{
org
:
string
;
repo
:
string
},
)
{
)
:
Promise
<
{
available
:
boolean
;
error
?:
string
}
>
{
try
{
// Get access token from settings
const
settings
=
readSettings
();
...
...
@@ -323,13 +323,12 @@ async function handleIsRepoAvailable(
async
function
handleCreateRepo
(
event
:
IpcMainInvokeEvent
,
{
org
,
repo
,
appId
}:
{
org
:
string
;
repo
:
string
;
appId
:
number
},
)
{
try
{
):
Promise
<
void
>
{
// Get access token from settings
const
settings
=
readSettings
();
const
accessToken
=
settings
.
githubAccessToken
?.
value
;
if
(
!
accessToken
)
{
return
{
success
:
false
,
error
:
"Not authenticated with GitHub."
}
;
throw
new
Error
(
"Not authenticated with GitHub."
)
;
}
// If org is empty, create for the authenticated user
let
owner
=
org
;
...
...
@@ -358,14 +357,10 @@ async function handleCreateRepo(
});
if
(
!
res
.
ok
)
{
const
data
=
await
res
.
json
();
return
{
success
:
false
,
error
:
data
.
message
||
"Failed to create repo"
}
;
throw
new
Error
(
data
.
message
||
"Failed to create repo"
)
;
}
// Store org and repo in the app's DB row (apps table)
await
updateAppGithubRepo
(
appId
,
owner
,
repo
);
return
{
success
:
true
};
}
catch
(
err
:
any
)
{
return
{
success
:
false
,
error
:
err
.
message
||
"Unknown error"
};
}
}
// --- GitHub Push Handler ---
...
...
@@ -420,8 +415,7 @@ async function handlePushToGithub(
async
function
handleDisconnectGithubRepo
(
event
:
IpcMainInvokeEvent
,
{
appId
}:
{
appId
:
number
},
)
{
try
{
):
Promise
<
void
>
{
logger
.
log
(
`Disconnecting GitHub repo for appId:
${
appId
}
`
);
// Get the app from the database
...
...
@@ -430,7 +424,7 @@ async function handleDisconnectGithubRepo(
});
if
(
!
app
)
{
return
{
success
:
false
,
error
:
"App not found"
}
;
throw
new
Error
(
"App not found"
)
;
}
// Update app in database to remove GitHub repo and org
...
...
@@ -441,15 +435,6 @@ async function handleDisconnectGithubRepo(
githubOrg
:
null
,
})
.
where
(
eq
(
apps
.
id
,
appId
));
return
{
success
:
true
};
}
catch
(
error
)
{
logger
.
error
(
`Error disconnecting GitHub repo:
${
error
}
`
);
return
{
success
:
false
,
error
:
error
instanceof
Error
?
error
.
message
:
String
(
error
),
};
}
}
// --- Registration ---
...
...
src/ipc/handlers/local_model_lmstudio_handler.ts
浏览文件 @
c71638a5
...
...
@@ -18,7 +18,6 @@ export interface LMStudioModel {
}
export
async
function
fetchLMStudioModels
():
Promise
<
LocalModelListResponse
>
{
try
{
const
modelsResponse
:
Response
=
await
fetch
(
"http://localhost:1234/api/v0/models"
,
);
...
...
@@ -36,10 +35,7 @@ export async function fetchLMStudioModels(): Promise<LocalModelListResponse> {
}));
logger
.
info
(
`Successfully fetched
${
models
.
length
}
models from LM Studio`
);
return
{
models
,
error
:
null
};
}
catch
{
return
{
models
:
[],
error
:
"Failed to fetch models from LM Studio"
};
}
return
{
models
};
}
export
function
registerLMStudioHandlers
()
{
...
...
src/ipc/handlers/local_model_ollama_handler.ts
浏览文件 @
c71638a5
...
...
@@ -47,20 +47,17 @@ export async function fetchOllamaModels(): Promise<LocalModelListResponse> {
};
});
logger
.
info
(
`Successfully fetched
${
models
.
length
}
models from Ollama`
);
return
{
models
,
error
:
null
};
return
{
models
};
}
catch
(
error
)
{
if
(
error
instanceof
TypeError
&&
(
error
as
Error
).
message
.
includes
(
"fetch failed"
)
)
{
logger
.
error
(
"Could not connect to Ollama"
);
return
{
models
:
[],
error
:
throw
new
Error
(
"Could not connect to Ollama. Make sure it's running at http://localhost:11434"
,
}
;
)
;
}
return
{
models
:
[],
error
:
"Failed to fetch models from Ollama"
}
;
throw
new
Error
(
"Failed to fetch models from Ollama"
)
;
}
}
...
...
src/ipc/handlers/proposal_handlers.ts
浏览文件 @
c71638a5
import
{
ipcMain
,
type
IpcMainInvokeEvent
}
from
"electron"
;
import
{
type
IpcMainInvokeEvent
}
from
"electron"
;
import
type
{
CodeProposal
,
ProposalResult
,
...
...
@@ -29,9 +29,9 @@ import {
import
{
extractCodebase
}
from
"../../utils/codebase"
;
import
{
getDyadAppPath
}
from
"../../paths/paths"
;
import
{
withLock
}
from
"../utils/lock_utils"
;
import
{
createLoggedHandler
}
from
"./safe_handle"
;
const
logger
=
log
.
scope
(
"proposal_handlers"
);
const
handle
=
createLoggedHandler
(
logger
);
// Cache for codebase token counts
interface
CodebaseTokenCache
{
chatId
:
number
;
...
...
@@ -317,15 +317,8 @@ const approveProposalHandler = async (
_event
:
IpcMainInvokeEvent
,
{
chatId
,
messageId
}:
{
chatId
:
number
;
messageId
:
number
},
):
Promise
<
{
success
:
boolean
;
error
?:
string
;
uncommittedFiles
?:
string
[];
}
>
=>
{
logger
.
log
(
`IPC: approve-proposal called for chatId:
${
chatId
}
, messageId:
${
messageId
}
`
,
);
try
{
// 1. Fetch the specific assistant message
const
messageToApprove
=
await
db
.
query
.
messages
.
findFirst
({
where
:
and
(
...
...
@@ -339,10 +332,9 @@ const approveProposalHandler = async (
});
if
(
!
messageToApprove
?.
content
)
{
logger
.
e
rror
(
throw
new
E
rror
(
`Assistant message not found for chatId:
${
chatId
}
, messageId:
${
messageId
}
`
,
);
return
{
success
:
false
,
error
:
"Assistant message not found."
};
}
// 2. Process the actions defined in the message content
...
...
@@ -357,38 +349,23 @@ const approveProposalHandler = async (
);
if
(
processResult
.
error
)
{
logger
.
error
(
`Error processing actions for message
${
messageId
}
:`
,
processResult
.
error
,
throw
new
Error
(
`Error processing actions for message
${
messageId
}
:
${
processResult
.
error
}
`
,
);
// Optionally: Update message state to 'error' or similar?
// For now, just return error to frontend
return
{
success
:
false
,
error
:
`Action processing failed:
${
processResult
.
error
}
`
,
};
}
return
{
success
:
true
,
uncommittedFiles
:
processResult
.
uncommittedFiles
};
}
catch
(
error
)
{
logger
.
error
(
`Error approving proposal for messageId
${
messageId
}
:`
,
error
);
return
{
success
:
false
,
error
:
(
error
as
Error
)?.
message
||
"Unknown error"
,
};
}
return
{
uncommittedFiles
:
processResult
.
uncommittedFiles
};
};
// Handler to reject a proposal (just update message state)
const
rejectProposalHandler
=
async
(
_event
:
IpcMainInvokeEvent
,
{
chatId
,
messageId
}:
{
chatId
:
number
;
messageId
:
number
},
):
Promise
<
{
success
:
boolean
;
error
?:
string
}
>
=>
{
):
Promise
<
void
>
=>
{
logger
.
log
(
`IPC: reject-proposal called for chatId:
${
chatId
}
, messageId:
${
messageId
}
`
,
);
try
{
// 1. Verify the message exists and is an assistant message
const
messageToReject
=
await
db
.
query
.
messages
.
findFirst
({
where
:
and
(
...
...
@@ -400,10 +377,9 @@ const rejectProposalHandler = async (
});
if
(
!
messageToReject
)
{
logger
.
e
rror
(
throw
new
E
rror
(
`Assistant message not found for chatId:
${
chatId
}
, messageId:
${
messageId
}
`
,
);
return
{
success
:
false
,
error
:
"Assistant message not found."
};
}
// 2. Update the message's approval state to 'rejected'
...
...
@@ -413,19 +389,11 @@ const rejectProposalHandler = async (
.
where
(
eq
(
messages
.
id
,
messageId
));
logger
.
log
(
`Message
${
messageId
}
marked as rejected.`
);
return
{
success
:
true
};
}
catch
(
error
)
{
logger
.
error
(
`Error rejecting proposal for messageId
${
messageId
}
:`
,
error
);
return
{
success
:
false
,
error
:
(
error
as
Error
)?.
message
||
"Unknown error"
,
};
}
};
// Function to register proposal-related handlers
export
function
registerProposalHandlers
()
{
ipcMain
.
handle
(
"get-proposal"
,
getProposalHandler
);
ipcMain
.
handle
(
"approve-proposal"
,
approveProposalHandler
);
ipcMain
.
handle
(
"reject-proposal"
,
rejectProposalHandler
);
handle
(
"get-proposal"
,
getProposalHandler
);
handle
(
"approve-proposal"
,
approveProposalHandler
);
handle
(
"reject-proposal"
,
rejectProposalHandler
);
}
src/ipc/handlers/safe_handle.ts
浏览文件 @
c71638a5
import
{
ipcMain
,
IpcMainInvokeEvent
}
from
"electron"
;
import
log
from
"electron-log"
;
export
function
create
Safe
Handler
(
logger
:
log
.
LogFunctions
)
{
export
function
create
Logged
Handler
(
logger
:
log
.
LogFunctions
)
{
return
(
channel
:
string
,
fn
:
(
event
:
IpcMainInvokeEvent
,
...
args
:
any
[])
=>
Promise
<
any
>
,
...
...
@@ -9,8 +9,11 @@ export function createSafeHandler(logger: log.LogFunctions) {
ipcMain
.
handle
(
channel
,
async
(
event
:
IpcMainInvokeEvent
,
...
args
:
any
[])
=>
{
logger
.
log
(
`IPC:
${
channel
}
called with args:
${
JSON
.
stringify
(
args
)}
`
);
try
{
return
await
fn
(
event
,
...
args
);
const
result
=
await
fn
(
event
,
...
args
);
logger
.
log
(
`IPC:
${
channel
}
returned:
${
JSON
.
stringify
(
result
)}
`
);
return
result
;
}
catch
(
error
)
{
logger
.
error
(
`Error in
${
fn
.
name
}
: args:
${
JSON
.
stringify
(
args
)}
`
,
...
...
src/ipc/handlers/settings_handlers.ts
浏览文件 @
c71638a5
...
...
@@ -4,11 +4,13 @@ import { writeSettings } from "../../main/settings";
import
{
readSettings
}
from
"../../main/settings"
;
export
function
registerSettingsHandlers
()
{
// Intentionally do NOT use handle because it could log sensitive data from the return value.
ipcMain
.
handle
(
"get-user-settings"
,
async
()
=>
{
const
settings
=
readSettings
();
return
settings
;
});
// Intentionally do NOT use handle because it could log sensitive data from the args.
ipcMain
.
handle
(
"set-user-settings"
,
async
(
_
,
settings
:
Partial
<
UserSettings
>
)
=>
{
...
...
src/ipc/handlers/shell_handler.ts
浏览文件 @
c71638a5
import
{
ipcMain
,
shell
}
from
"electron"
;
import
{
shell
}
from
"electron"
;
import
log
from
"electron-log"
;
import
{
createLoggedHandler
}
from
"./safe_handle"
;
const
logger
=
log
.
scope
(
"shell_handlers"
);
const
handle
=
createLoggedHandler
(
logger
);
export
function
registerShellHandlers
()
{
ipcMain
.
handle
(
"open-external-url"
,
async
(
_event
,
url
:
string
)
=>
{
try
{
// Basic validation to ensure it's a http/https url
if
(
url
&&
(
url
.
startsWith
(
"http://"
)
||
url
.
startsWith
(
"https://"
)))
{
await
shell
.
openExternal
(
url
);
logger
.
debug
(
"Opened external URL:"
,
url
);
return
{
success
:
true
};
handle
(
"open-external-url"
,
async
(
_event
,
url
:
string
)
=>
{
if
(
!
url
)
{
throw
new
Error
(
"No URL provided."
);
}
logger
.
error
(
"Attempted to open invalid or non-http URL:"
,
url
);
return
{
success
:
false
,
error
:
"Invalid URL provided. Only http/https URLs are allowed."
,
};
}
catch
(
error
)
{
logger
.
error
(
`Failed to open external URL
${
url
}
:`
,
error
);
return
{
success
:
false
,
error
:
(
error
as
Error
).
message
};
if
(
!
url
.
startsWith
(
"http://"
)
&&
!
url
.
startsWith
(
"https://"
))
{
throw
new
Error
(
"Attempted to open invalid or non-http URL: "
+
url
);
}
await
shell
.
openExternal
(
url
);
logger
.
debug
(
"Opened external URL:"
,
url
);
});
ipcMain
.
handle
(
"show-item-in-folder"
,
async
(
_event
,
fullPath
:
string
)
=>
{
try
{
handle
(
"show-item-in-folder"
,
async
(
_event
,
fullPath
:
string
)
=>
{
// Validate that a path was provided
if
(
!
fullPath
)
{
logger
.
error
(
"Attempted to show item with empty path"
);
return
{
success
:
false
,
error
:
"No file path provided."
,
};
throw
new
Error
(
"No file path provided."
);
}
shell
.
showItemInFolder
(
fullPath
);
logger
.
debug
(
"Showed item in folder:"
,
fullPath
);
return
{
success
:
true
};
}
catch
(
error
)
{
logger
.
error
(
`Failed to show item in folder
${
fullPath
}
:`
,
error
);
return
{
success
:
false
,
error
:
(
error
as
Error
).
message
};
}
});
}
src/ipc/handlers/supabase_handlers.ts
浏览文件 @
c71638a5
import
{
ipcMain
}
from
"electron"
;
import
log
from
"electron-log"
;
import
{
db
}
from
"../../db"
;
import
{
eq
}
from
"drizzle-orm"
;
import
{
apps
}
from
"../../db/schema"
;
import
{
getSupabaseClient
}
from
"../../supabase_admin/supabase_management_client"
;
import
{
createLoggedHandler
}
from
"./safe_handle"
;
const
logger
=
log
.
scope
(
"supabase_handlers"
);
const
handle
=
createLoggedHandler
(
logger
);
export
function
registerSupabaseHandlers
()
{
// List all Supabase projects
ipcMain
.
handle
(
"supabase:list-projects"
,
async
()
=>
{
try
{
handle
(
"supabase:list-projects"
,
async
()
=>
{
const
supabase
=
await
getSupabaseClient
();
// Call the API according to supabase-management-js structure
const
projects
=
await
supabase
.
getProjects
();
return
projects
;
}
catch
(
error
)
{
logger
.
error
(
"Error listing Supabase projects:"
,
error
);
throw
error
;
}
return
supabase
.
getProjects
();
});
// Set app project - links a Dyad app to a Supabase project
ipcMain
.
handle
(
handle
(
"supabase:set-app-project"
,
async
(
_
,
{
project
,
app
}:
{
project
:
string
;
app
:
number
})
=>
{
try
{
// Here you could store the project-app association in your database
// For example:
await
db
.
update
(
apps
)
.
set
({
supabaseProjectId
:
project
})
.
where
(
eq
(
apps
.
id
,
app
));
logger
.
info
(
`Associated app
${
app
}
with Supabase project
${
project
}
`
);
return
{
success
:
true
,
appId
:
app
,
projectId
:
project
};
}
catch
(
error
)
{
logger
.
error
(
"Error setting Supabase project for app:"
,
error
);
throw
error
;
}
},
);
// Unset app project - removes the link between a Dyad app and a Supabase project
ipcMain
.
handle
(
"supabase:unset-app-project"
,
async
(
_
,
{
app
}:
{
app
:
number
})
=>
{
try
{
handle
(
"supabase:unset-app-project"
,
async
(
_
,
{
app
}:
{
app
:
number
})
=>
{
await
db
.
update
(
apps
)
.
set
({
supabaseProjectId
:
null
})
.
where
(
eq
(
apps
.
id
,
app
));
logger
.
info
(
`Removed Supabase project association for app
${
app
}
`
);
return
{
success
:
true
,
appId
:
app
};
}
catch
(
error
)
{
logger
.
error
(
"Error unsetting Supabase project for app:"
,
error
);
throw
error
;
}
},
);
});
}
src/ipc/handlers/token_count_handlers.ts
浏览文件 @
c71638a5
import
{
ipcMain
}
from
"electron"
;
import
{
db
}
from
"../../db"
;
import
{
chats
}
from
"../../db/schema"
;
import
{
eq
}
from
"drizzle-orm"
;
...
...
@@ -15,15 +14,16 @@ import { getSupabaseContext } from "../../supabase_admin/supabase_context";
import
{
TokenCountParams
}
from
"../ipc_types"
;
import
{
TokenCountResult
}
from
"../ipc_types"
;
import
{
estimateTokens
,
getContextWindow
}
from
"../utils/token_utils"
;
import
{
createLoggedHandler
}
from
"./safe_handle"
;
const
logger
=
log
.
scope
(
"token_count_handlers"
);
const
handle
=
createLoggedHandler
(
logger
);
export
function
registerTokenCountHandlers
()
{
ipcMain
.
handle
(
handle
(
"chat:count-tokens"
,
async
(
event
,
req
:
TokenCountParams
):
Promise
<
TokenCountResult
>
=>
{
try
{
// Get the chat with messages
const
chat
=
await
db
.
query
.
chats
.
findFirst
({
where
:
eq
(
chats
.
id
,
req
.
chatId
),
with
:
{
...
...
@@ -60,9 +60,7 @@ export function registerTokenCountHandlers() {
systemPrompt
+=
"
\
n
\
n"
+
SUPABASE_NOT_AVAILABLE_SYSTEM_PROMPT
;
}
const
systemPromptTokens
=
estimateTokens
(
systemPrompt
+
supabaseContext
,
);
const
systemPromptTokens
=
estimateTokens
(
systemPrompt
+
supabaseContext
);
// Extract codebase information if app is associated with the chat
let
codebaseInfo
=
""
;
...
...
@@ -70,15 +68,11 @@ export function registerTokenCountHandlers() {
if
(
chat
.
app
)
{
const
appPath
=
getDyadAppPath
(
chat
.
app
.
path
);
try
{
codebaseInfo
=
await
extractCodebase
(
appPath
);
codebaseTokens
=
estimateTokens
(
codebaseInfo
);
logger
.
log
(
`Extracted codebase information from
${
appPath
}
, tokens:
${
codebaseTokens
}
`
,
);
}
catch
(
error
)
{
logger
.
error
(
"Error extracting codebase:"
,
error
);
}
}
// Calculate total tokens
...
...
@@ -96,10 +90,6 @@ export function registerTokenCountHandlers() {
systemPromptTokens
,
contextWindow
:
getContextWindow
(),
};
}
catch
(
error
)
{
logger
.
error
(
"Error counting tokens:"
,
error
);
throw
error
;
}
},
);
}
src/ipc/handlers/upload_handlers.ts
浏览文件 @
c71638a5
import
{
ipcMain
}
from
"electron"
;
import
log
from
"electron-log"
;
import
fetch
from
"node-fetch"
;
import
{
createLoggedHandler
}
from
"./safe_handle"
;
const
logger
=
log
.
scope
(
"upload_handlers"
);
const
handle
=
createLoggedHandler
(
logger
);
interface
UploadToSignedUrlParams
{
url
:
string
;
contentType
:
string
;
...
...
@@ -11,13 +13,10 @@ interface UploadToSignedUrlParams {
}
export
function
registerUploadHandlers
()
{
ipcMain
.
handle
(
"upload-to-signed-url"
,
async
(
_
,
params
:
UploadToSignedUrlParams
)
=>
{
handle
(
"upload-to-signed-url"
,
async
(
_
,
params
:
UploadToSignedUrlParams
)
=>
{
const
{
url
,
contentType
,
data
}
=
params
;
logger
.
debug
(
"IPC: upload-to-signed-url called"
);
try
{
// Validate the signed URL
if
(
!
url
||
typeof
url
!==
"string"
||
!
url
.
startsWith
(
"https://"
))
{
throw
new
Error
(
"Invalid signed URL provided"
);
...
...
@@ -44,16 +43,7 @@ export function registerUploadHandlers() {
}
logger
.
debug
(
"Successfully uploaded data to signed URL"
);
return
{
success
:
true
};
}
catch
(
error
)
{
logger
.
error
(
"Failed to upload to signed URL:"
,
error
);
return
{
success
:
false
,
error
:
error
instanceof
Error
?
error
.
message
:
String
(
error
),
};
}
},
);
});
logger
.
debug
(
"Registered upload IPC handlers"
);
}
src/ipc/handlers/version_handlers.ts
浏览文件 @
c71638a5
...
...
@@ -10,11 +10,11 @@ import { promises as fsPromises } from "node:fs";
import
{
withLock
}
from
"../utils/lock_utils"
;
import
{
getGitAuthor
}
from
"../utils/git_author"
;
import
log
from
"electron-log"
;
import
{
create
Safe
Handler
}
from
"./safe_handle"
;
import
{
create
Logged
Handler
}
from
"./safe_handle"
;
const
logger
=
log
.
scope
(
"version_handlers"
);
const
handle
=
create
Safe
Handler
(
logger
);
const
handle
=
create
Logged
Handler
(
logger
);
export
function
registerVersionHandlers
()
{
handle
(
"list-versions"
,
async
(
_
,
{
appId
}:
{
appId
:
number
})
=>
{
...
...
src/ipc/ipc_client.ts
浏览文件 @
c71638a5
差异被折叠。
点击展开。
src/ipc/ipc_types.ts
浏览文件 @
c71638a5
...
...
@@ -111,7 +111,6 @@ export interface LocalModel {
export
type
LocalModelListResponse
=
{
models
:
LocalModel
[];
error
:
string
|
null
;
};
export
interface
TokenCountParams
{
...
...
src/pages/app-details.tsx
浏览文件 @
c71638a5
...
...
@@ -28,6 +28,7 @@ import {
}
from
"@/components/ui/dialog"
;
import
{
GitHubConnector
}
from
"@/components/GitHubConnector"
;
import
{
SupabaseConnector
}
from
"@/components/SupabaseConnector"
;
import
{
showError
}
from
"@/lib/toast"
;
export
default
function
AppDetailsPage
()
{
const
navigate
=
useNavigate
();
...
...
@@ -62,7 +63,7 @@ export default function AppDetailsPage() {
await
refreshApps
();
navigate
({
to
:
"/"
,
search
:
{}
});
}
catch
(
error
)
{
console
.
error
(
"Failed to delete app:"
,
error
);
showError
(
error
);
}
finally
{
setIsDeleting
(
false
);
}
...
...
src/pages/settings.tsx
浏览文件 @
c71638a5
...
...
@@ -27,12 +27,8 @@ export default function SettingsPage() {
setIsResetting
(
true
);
try
{
const
ipcClient
=
IpcClient
.
getInstance
();
const
result
=
await
ipcClient
.
resetAll
();
if
(
result
.
success
)
{
await
ipcClient
.
resetAll
();
showSuccess
(
"Successfully reset everything. Restart the application."
);
}
else
{
showError
(
result
.
message
||
"Failed to reset everything."
);
}
}
catch
(
error
)
{
console
.
error
(
"Error resetting:"
,
error
);
showError
(
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论