Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
B
bit-pm
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
燕伟桐
bit-pm
Commits
35296271
Unverified
提交
35296271
authored
5月 02, 2025
作者:
Will Chen
提交者:
GitHub
5月 02, 2025
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Undo chat history (#74)
上级
4fb4e49c
显示空白字符变更
内嵌
并排
正在显示
11 个修改的文件
包含
312 行增加
和
17 行删除
+312
-17
0003_open_bucky.sql
drizzle/0003_open_bucky.sql
+2
-0
0003_snapshot.json
drizzle/meta/0003_snapshot.json
+214
-0
_journal.json
drizzle/meta/_journal.json
+8
-0
ChatList.tsx
src/components/ChatList.tsx
+1
-0
ChatHeader.tsx
src/components/chat/ChatHeader.tsx
+2
-2
VersionPane.tsx
src/components/chat/VersionPane.tsx
+5
-6
schema.ts
src/db/schema.ts
+1
-0
useStreamChat.ts
src/hooks/useStreamChat.ts
+2
-2
useVersions.ts
src/hooks/useVersions.ts
+28
-4
app_handlers.ts
src/ipc/handlers/app_handlers.ts
+40
-2
response_processor.ts
src/ipc/processors/response_processor.ts
+9
-1
没有找到文件。
drizzle/0003_open_bucky.sql
0 → 100644
浏览文件 @
35296271
ALTER
TABLE
`messages`
ADD
`commit_hash`
text
;
\ No newline at end of file
drizzle/meta/0003_snapshot.json
0 → 100644
浏览文件 @
35296271
{
"version"
:
"6"
,
"dialect"
:
"sqlite"
,
"id"
:
"859942b1-88b8-4a16-b2d0-77c9ece76693"
,
"prevId"
:
"e1d700a4-d507-4e2a-80dc-8dbbfd91edfd"
,
"tables"
:
{
"apps"
:
{
"name"
:
"apps"
,
"columns"
:
{
"id"
:
{
"name"
:
"id"
,
"type"
:
"integer"
,
"primaryKey"
:
true
,
"notNull"
:
true
,
"autoincrement"
:
true
},
"name"
:
{
"name"
:
"name"
,
"type"
:
"text"
,
"primaryKey"
:
false
,
"notNull"
:
true
,
"autoincrement"
:
false
},
"path"
:
{
"name"
:
"path"
,
"type"
:
"text"
,
"primaryKey"
:
false
,
"notNull"
:
true
,
"autoincrement"
:
false
},
"created_at"
:
{
"name"
:
"created_at"
,
"type"
:
"integer"
,
"primaryKey"
:
false
,
"notNull"
:
true
,
"autoincrement"
:
false
,
"default"
:
"(unixepoch())"
},
"updated_at"
:
{
"name"
:
"updated_at"
,
"type"
:
"integer"
,
"primaryKey"
:
false
,
"notNull"
:
true
,
"autoincrement"
:
false
,
"default"
:
"(unixepoch())"
},
"github_org"
:
{
"name"
:
"github_org"
,
"type"
:
"text"
,
"primaryKey"
:
false
,
"notNull"
:
false
,
"autoincrement"
:
false
},
"github_repo"
:
{
"name"
:
"github_repo"
,
"type"
:
"text"
,
"primaryKey"
:
false
,
"notNull"
:
false
,
"autoincrement"
:
false
},
"supabase_project_id"
:
{
"name"
:
"supabase_project_id"
,
"type"
:
"text"
,
"primaryKey"
:
false
,
"notNull"
:
false
,
"autoincrement"
:
false
}
},
"indexes"
:
{},
"foreignKeys"
:
{},
"compositePrimaryKeys"
:
{},
"uniqueConstraints"
:
{},
"checkConstraints"
:
{}
},
"chats"
:
{
"name"
:
"chats"
,
"columns"
:
{
"id"
:
{
"name"
:
"id"
,
"type"
:
"integer"
,
"primaryKey"
:
true
,
"notNull"
:
true
,
"autoincrement"
:
true
},
"app_id"
:
{
"name"
:
"app_id"
,
"type"
:
"integer"
,
"primaryKey"
:
false
,
"notNull"
:
true
,
"autoincrement"
:
false
},
"title"
:
{
"name"
:
"title"
,
"type"
:
"text"
,
"primaryKey"
:
false
,
"notNull"
:
false
,
"autoincrement"
:
false
},
"created_at"
:
{
"name"
:
"created_at"
,
"type"
:
"integer"
,
"primaryKey"
:
false
,
"notNull"
:
true
,
"autoincrement"
:
false
,
"default"
:
"(unixepoch())"
}
},
"indexes"
:
{},
"foreignKeys"
:
{
"chats_app_id_apps_id_fk"
:
{
"name"
:
"chats_app_id_apps_id_fk"
,
"tableFrom"
:
"chats"
,
"tableTo"
:
"apps"
,
"columnsFrom"
:
[
"app_id"
],
"columnsTo"
:
[
"id"
],
"onDelete"
:
"cascade"
,
"onUpdate"
:
"no action"
}
},
"compositePrimaryKeys"
:
{},
"uniqueConstraints"
:
{},
"checkConstraints"
:
{}
},
"messages"
:
{
"name"
:
"messages"
,
"columns"
:
{
"id"
:
{
"name"
:
"id"
,
"type"
:
"integer"
,
"primaryKey"
:
true
,
"notNull"
:
true
,
"autoincrement"
:
true
},
"chat_id"
:
{
"name"
:
"chat_id"
,
"type"
:
"integer"
,
"primaryKey"
:
false
,
"notNull"
:
true
,
"autoincrement"
:
false
},
"role"
:
{
"name"
:
"role"
,
"type"
:
"text"
,
"primaryKey"
:
false
,
"notNull"
:
true
,
"autoincrement"
:
false
},
"content"
:
{
"name"
:
"content"
,
"type"
:
"text"
,
"primaryKey"
:
false
,
"notNull"
:
true
,
"autoincrement"
:
false
},
"approval_state"
:
{
"name"
:
"approval_state"
,
"type"
:
"text"
,
"primaryKey"
:
false
,
"notNull"
:
false
,
"autoincrement"
:
false
},
"commit_hash"
:
{
"name"
:
"commit_hash"
,
"type"
:
"text"
,
"primaryKey"
:
false
,
"notNull"
:
false
,
"autoincrement"
:
false
},
"created_at"
:
{
"name"
:
"created_at"
,
"type"
:
"integer"
,
"primaryKey"
:
false
,
"notNull"
:
true
,
"autoincrement"
:
false
,
"default"
:
"(unixepoch())"
}
},
"indexes"
:
{},
"foreignKeys"
:
{
"messages_chat_id_chats_id_fk"
:
{
"name"
:
"messages_chat_id_chats_id_fk"
,
"tableFrom"
:
"messages"
,
"tableTo"
:
"chats"
,
"columnsFrom"
:
[
"chat_id"
],
"columnsTo"
:
[
"id"
],
"onDelete"
:
"cascade"
,
"onUpdate"
:
"no action"
}
},
"compositePrimaryKeys"
:
{},
"uniqueConstraints"
:
{},
"checkConstraints"
:
{}
}
},
"views"
:
{},
"enums"
:
{},
"_meta"
:
{
"schemas"
:
{},
"tables"
:
{},
"columns"
:
{}
},
"internal"
:
{
"indexes"
:
{}
}
}
\ No newline at end of file
drizzle/meta/_journal.json
浏览文件 @
35296271
...
...
@@ -22,6 +22,13 @@
"when"
:
1745359640409
,
"tag"
:
"0002_unique_morlocks"
,
"breakpoints"
:
true
},
{
"idx"
:
3
,
"version"
:
"6"
,
"when"
:
1746209201530
,
"tag"
:
"0003_open_bucky"
,
"breakpoints"
:
true
}
]
}
\ No newline at end of file
src/components/ChatList.tsx
浏览文件 @
35296271
...
...
@@ -31,6 +31,7 @@ export function ChatList({ show }: { show?: boolean }) {
if
(
isChatRoute
)
{
const
id
=
routerState
.
location
.
search
.
id
;
if
(
id
)
{
console
.
log
(
"Setting selected chat id to"
,
id
);
setSelectedChatId
(
id
);
}
}
...
...
src/components/chat/ChatHeader.tsx
浏览文件 @
35296271
...
...
@@ -2,7 +2,7 @@ import { PanelRightOpen, History, PlusCircle } from "lucide-react";
import
{
PanelRightClose
}
from
"lucide-react"
;
import
{
useAtomValue
,
useSetAtom
}
from
"jotai"
;
import
{
selectedAppIdAtom
}
from
"@/atoms/appAtoms"
;
import
{
use
LoadVersions
}
from
"@/hooks/useLoad
Versions"
;
import
{
use
Versions
}
from
"@/hooks/use
Versions"
;
import
{
Button
}
from
"../ui/button"
;
import
{
IpcClient
}
from
"@/ipc/ipc_client"
;
import
{
useRouter
}
from
"@tanstack/react-router"
;
...
...
@@ -22,7 +22,7 @@ export function ChatHeader({
onVersionClick
,
}:
ChatHeaderProps
)
{
const
appId
=
useAtomValue
(
selectedAppIdAtom
);
const
{
versions
,
loading
}
=
use
Load
Versions
(
appId
);
const
{
versions
,
loading
}
=
useVersions
(
appId
);
const
{
navigate
}
=
useRouter
();
const
setSelectedChatId
=
useSetAtom
(
selectedChatIdAtom
);
const
{
refreshChats
}
=
useChats
(
appId
);
...
...
src/components/chat/VersionPane.tsx
浏览文件 @
35296271
import
{
useAtom
,
useAtomValue
}
from
"jotai"
;
import
{
selectedAppIdAtom
,
selectedVersionIdAtom
}
from
"@/atoms/appAtoms"
;
import
{
use
LoadVersions
}
from
"@/hooks/useLoad
Versions"
;
import
{
use
Versions
}
from
"@/hooks/use
Versions"
;
import
{
formatDistanceToNow
}
from
"date-fns"
;
import
{
RotateCcw
,
X
}
from
"lucide-react"
;
import
type
{
Version
}
from
"@/ipc/ipc_types"
;
...
...
@@ -15,7 +15,8 @@ interface VersionPaneProps {
export
function
VersionPane
({
isVisible
,
onClose
}:
VersionPaneProps
)
{
const
appId
=
useAtomValue
(
selectedAppIdAtom
);
const
{
versions
,
loading
,
refreshVersions
}
=
useLoadVersions
(
appId
);
const
{
versions
,
loading
,
refreshVersions
,
revertVersion
}
=
useVersions
(
appId
);
const
[
selectedVersionId
,
setSelectedVersionId
]
=
useAtom
(
selectedVersionIdAtom
);
...
...
@@ -108,11 +109,9 @@ export function VersionPane({ isVisible, onClose }: VersionPaneProps) {
onClick=
{
async
(
e
)
=>
{
e
.
stopPropagation
();
setSelectedVersionId
(
null
);
await
IpcClient
.
getInstance
().
revertVersion
({
appId
:
appId
!
,
previousVersionId
:
version
.
oid
,
await
revertVersion
({
versionId
:
version
.
oid
,
});
refreshVersions
();
}
}
className=
{
cn
(
"invisible mt-1 flex items-center gap-1 px-2 py-0.5 text-sm font-medium bg-(--primary) text-(--primary-foreground) hover:bg-background-lightest rounded-md transition-colors"
,
...
...
src/db/schema.ts
浏览文件 @
35296271
...
...
@@ -38,6 +38,7 @@ export const messages = sqliteTable("messages", {
approvalState
:
text
(
"approval_state"
,
{
enum
:
[
"approved"
,
"rejected"
],
}),
commitHash
:
text
(
"commit_hash"
),
createdAt
:
integer
(
"created_at"
,
{
mode
:
"timestamp"
})
.
notNull
()
.
default
(
sql
`(unixepoch())`
),
...
...
src/hooks/useStreamChat.ts
浏览文件 @
35296271
...
...
@@ -13,7 +13,7 @@ import type { ChatResponseEnd } from "@/ipc/ipc_types";
import
{
useChats
}
from
"./useChats"
;
import
{
useLoadApp
}
from
"./useLoadApp"
;
import
{
selectedAppIdAtom
}
from
"@/atoms/appAtoms"
;
import
{
use
LoadVersions
}
from
"./useLoad
Versions"
;
import
{
use
Versions
}
from
"./use
Versions"
;
import
{
showError
}
from
"@/lib/toast"
;
import
{
useProposal
}
from
"./useProposal"
;
import
{
useSearch
}
from
"@tanstack/react-router"
;
...
...
@@ -35,7 +35,7 @@ export function useStreamChat({
const
{
refreshChats
}
=
useChats
(
selectedAppId
);
const
{
refreshApp
}
=
useLoadApp
(
selectedAppId
);
const
setStreamCount
=
useSetAtom
(
chatStreamCountAtom
);
const
{
refreshVersions
}
=
use
Load
Versions
(
selectedAppId
);
const
{
refreshVersions
}
=
useVersions
(
selectedAppId
);
const
{
refreshAppIframe
}
=
useRunApp
();
const
{
countTokens
}
=
useCountTokens
();
...
...
src/hooks/use
Load
Versions.ts
→
src/hooks/useVersions.ts
浏览文件 @
35296271
import
{
useState
,
useEffect
,
useCallback
}
from
"react"
;
import
{
useAtom
}
from
"jotai"
;
import
{
useAtom
,
useAtomValue
}
from
"jotai"
;
import
{
versionsListAtom
}
from
"@/atoms/appAtoms"
;
import
{
IpcClient
}
from
"@/ipc/ipc_client"
;
import
{
showError
}
from
"@/lib/toast"
;
import
{
chatMessagesAtom
,
selectedChatIdAtom
}
from
"@/atoms/chatAtoms"
;
export
function
use
Load
Versions
(
appId
:
number
|
null
)
{
export
function
useVersions
(
appId
:
number
|
null
)
{
const
[
versions
,
setVersions
]
=
useAtom
(
versionsListAtom
);
const
[
loading
,
setLoading
]
=
useState
(
true
);
const
[
error
,
setError
]
=
useState
<
Error
|
null
>
(
null
);
const
selectedChatId
=
useAtomValue
(
selectedChatIdAtom
);
const
[
messages
,
setMessages
]
=
useAtom
(
chatMessagesAtom
);
useEffect
(()
=>
{
const
loadVersions
=
async
()
=>
{
// If no app is selected, clear versions and return
...
...
@@ -50,5 +53,26 @@ export function useLoadVersions(appId: number | null) {
}
},
[
appId
,
setVersions
,
setError
]);
return
{
versions
,
loading
,
error
,
refreshVersions
};
const
revertVersion
=
useCallback
(
async
({
versionId
}:
{
versionId
:
string
})
=>
{
if
(
appId
===
null
)
{
return
;
}
try
{
const
ipcClient
=
IpcClient
.
getInstance
();
await
ipcClient
.
revertVersion
({
appId
,
previousVersionId
:
versionId
});
await
refreshVersions
();
if
(
selectedChatId
)
{
const
chat
=
await
IpcClient
.
getInstance
().
getChat
(
selectedChatId
);
setMessages
(
chat
.
messages
);
}
}
catch
(
error
)
{
showError
(
error
);
}
},
[
appId
,
setVersions
,
setError
,
selectedChatId
,
setMessages
]
);
return
{
versions
,
loading
,
error
,
refreshVersions
,
revertVersion
};
}
src/ipc/handlers/app_handlers.ts
浏览文件 @
35296271
import
{
ipcMain
}
from
"electron"
;
import
{
db
,
getDatabasePath
}
from
"../../db"
;
import
{
apps
,
chats
}
from
"../../db/schema"
;
import
{
desc
,
eq
}
from
"drizzle-orm"
;
import
{
apps
,
chats
,
messages
}
from
"../../db/schema"
;
import
{
desc
,
eq
,
and
,
gte
,
sql
,
gt
}
from
"drizzle-orm"
;
import
type
{
App
,
CreateAppParams
,
...
...
@@ -572,6 +572,44 @@ export function registerAppHandlers() {
author
:
await
getGitAuthor
(),
});
// Find the chat and message associated with the commit hash
const
messageWithCommit
=
await
db
.
query
.
messages
.
findFirst
({
where
:
eq
(
messages
.
commitHash
,
previousVersionId
),
with
:
{
chat
:
true
,
},
});
// If we found a message with this commit hash, delete all subsequent messages (but keep this message)
if
(
messageWithCommit
)
{
const
chatId
=
messageWithCommit
.
chatId
;
// Find all messages in this chat with IDs > the one with our commit hash
const
messagesToDelete
=
await
db
.
query
.
messages
.
findMany
({
where
:
and
(
eq
(
messages
.
chatId
,
chatId
),
gt
(
messages
.
id
,
messageWithCommit
.
id
)
),
orderBy
:
desc
(
messages
.
id
),
});
logger
.
log
(
`Deleting
${
messagesToDelete
.
length
}
messages after commit
${
previousVersionId
}
from chat
${
chatId
}
`
);
// Delete the messages
if
(
messagesToDelete
.
length
>
0
)
{
await
db
.
delete
(
messages
)
.
where
(
and
(
eq
(
messages
.
chatId
,
chatId
),
gt
(
messages
.
id
,
messageWithCommit
.
id
)
)
);
}
}
return
{
success
:
true
};
}
catch
(
error
:
any
)
{
logger
.
error
(
...
...
src/ipc/processors/response_processor.ts
浏览文件 @
35296271
...
...
@@ -435,7 +435,7 @@ export async function processFullResponseActions(
changes
.
push
(
`executed
${
dyadExecuteSqlQueries
.
length
}
SQL queries`
);
// Use chat summary, if provided, or default for commit message
await
git
.
commit
({
const
commitHash
=
await
git
.
commit
({
fs
,
dir
:
appPath
,
message
:
chatSummary
...
...
@@ -444,6 +444,14 @@ export async function processFullResponseActions(
author
:
await
getGitAuthor
(),
});
logger
.
log
(
`Successfully committed changes:
${
changes
.
join
(
", "
)}
`
);
// Save the commit hash to the message
await
db
.
update
(
messages
)
.
set
({
commitHash
:
commitHash
,
})
.
where
(
eq
(
messages
.
id
,
messageId
));
}
logger
.
log
(
"mark as approved: hasChanges"
,
hasChanges
);
// Update the message to approved
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论