Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
B
bit-pm
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
燕伟桐
bit-pm
Commits
5db0b044
Unverified
提交
5db0b044
authored
8月 05, 2025
作者:
Will Chen
提交者:
GitHub
8月 05, 2025
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Support exclude paths in manual context management (#774)
上级
74ada705
全部展开
隐藏空白字符变更
内嵌
并排
正在显示
16 个修改的文件
包含
441 行增加
和
23 行删除
+441
-23
context_manage.spec.ts
e2e-tests/context_manage.spec.ts
+61
-0
test_helper.ts
e2e-tests/helpers/test_helper.ts
+12
-0
context_manage.spec.ts_exclude-paths-basic
...ests/snapshots/context_manage.spec.ts_exclude-paths-basic
+0
-0
context_manage.spec.ts_exclude-paths-precedence
...snapshots/context_manage.spec.ts_exclude-paths-precedence
+0
-0
context_manage.spec.ts_exclude-paths-with-smart-context
...s/context_manage.spec.ts_exclude-paths-with-smart-context
+0
-0
context_manage.spec.ts_manage-context---exclude-paths-1.aria.yml
..._manage.spec.ts_manage-context---exclude-paths-1.aria.yml
+15
-0
context_manage.spec.ts_manage-context---exclude-paths-2.aria.yml
..._manage.spec.ts_manage-context---exclude-paths-2.aria.yml
+26
-0
context_manage.spec.ts_manage-context---exclude-paths-3.aria.yml
..._manage.spec.ts_manage-context---exclude-paths-3.aria.yml
+26
-0
context_manage.spec.ts_manage-context---exclude-paths-with-smart-context-1.aria.yml
...age-context---exclude-paths-with-smart-context-1.aria.yml
+21
-0
context_manage.spec.ts_manage-context---exclude-paths-with-smart-context-2.aria.yml
...age-context---exclude-paths-with-smart-context-2.aria.yml
+38
-0
ContextFilesPicker.tsx
src/components/ContextFilesPicker.tsx
+132
-11
useContextPaths.ts
src/hooks/useContextPaths.ts
+56
-7
context_paths_handlers.ts
src/ipc/handlers/context_paths_handlers.ts
+20
-3
context_paths_utils.ts
src/ipc/utils/context_paths_utils.ts
+2
-0
schemas.ts
src/lib/schemas.ts
+2
-0
codebase.ts
src/utils/codebase.ts
+30
-2
没有找到文件。
e2e-tests/context_manage.spec.ts
浏览文件 @
5db0b044
...
...
@@ -74,3 +74,64 @@ test("manage context - smart context - auto-includes only", async ({ po }) => {
await
po
.
snapshotServerDump
(
"request"
);
});
test
(
"manage context - exclude paths"
,
async
({
po
})
=>
{
await
po
.
setUp
();
await
po
.
importApp
(
"context-manage"
);
const
dialog
=
await
po
.
openContextFilesPicker
();
await
po
.
snapshotDialog
();
// Add some include paths first
await
dialog
.
addManualContextFile
(
"src/**/*.ts"
);
await
dialog
.
addManualContextFile
(
"manual/**"
);
// Add exclude paths
await
dialog
.
addExcludeContextFile
(
"src/components/**"
);
await
dialog
.
addExcludeContextFile
(
"manual/exclude/**"
);
await
po
.
snapshotDialog
();
await
dialog
.
close
();
await
po
.
sendPrompt
(
"[dump]"
);
await
po
.
snapshotServerDump
(
"all-messages"
,
{
name
:
"exclude-paths-basic"
});
// Test that exclude paths take precedence over include paths
const
dialog2
=
await
po
.
openContextFilesPicker
();
await
dialog2
.
removeExcludeContextFile
();
// Remove src/components/**
await
dialog2
.
addExcludeContextFile
(
"src/**"
);
// This should exclude everything from src
await
po
.
snapshotDialog
();
await
dialog2
.
close
();
await
po
.
sendPrompt
(
"[dump]"
);
await
po
.
snapshotServerDump
(
"all-messages"
,
{
name
:
"exclude-paths-precedence"
,
});
});
test
(
"manage context - exclude paths with smart context"
,
async
({
po
})
=>
{
await
po
.
setUpDyadPro
();
await
po
.
selectModel
({
provider
:
"Google"
,
model
:
"Gemini 2.5 Pro"
});
await
po
.
importApp
(
"context-manage"
);
const
dialog
=
await
po
.
openContextFilesPicker
();
await
po
.
snapshotDialog
();
// Add manual context files
await
dialog
.
addManualContextFile
(
"src/**/*.ts"
);
await
dialog
.
addManualContextFile
(
"manual/**"
);
// Add smart context auto-includes
await
dialog
.
addAutoIncludeContextFile
(
"a.ts"
);
await
dialog
.
addAutoIncludeContextFile
(
"exclude/**"
);
// Add exclude paths that should filter out some of the above
await
dialog
.
addExcludeContextFile
(
"src/components/**"
);
await
dialog
.
addExcludeContextFile
(
"exclude/exclude.ts"
);
await
po
.
snapshotDialog
();
await
dialog
.
close
();
await
po
.
sendPrompt
(
"[dump]"
);
await
po
.
snapshotServerDump
(
"all-messages"
,
{
name
:
"exclude-paths-with-smart-context"
,
});
});
e2e-tests/helpers/test_helper.ts
浏览文件 @
5db0b044
...
...
@@ -47,6 +47,18 @@ export class ContextFilesPickerDialog {
.
first
()
.
click
();
}
async
addExcludeContextFile
(
path
:
string
)
{
await
this
.
page
.
getByTestId
(
"exclude-context-files-input"
).
fill
(
path
);
await
this
.
page
.
getByTestId
(
"exclude-context-files-add-button"
).
click
();
}
async
removeExcludeContextFile
()
{
await
this
.
page
.
getByTestId
(
"exclude-context-files-remove-button"
)
.
first
()
.
click
();
}
}
class
ProModesDialog
{
...
...
e2e-tests/snapshots/context_manage.spec.ts_exclude-paths-basic
0 → 100644
浏览文件 @
5db0b044
差异被折叠。
点击展开。
e2e-tests/snapshots/context_manage.spec.ts_exclude-paths-precedence
0 → 100644
浏览文件 @
5db0b044
差异被折叠。
点击展开。
e2e-tests/snapshots/context_manage.spec.ts_exclude-paths-with-smart-context
0 → 100644
浏览文件 @
5db0b044
差异被折叠。
点击展开。
e2e-tests/snapshots/context_manage.spec.ts_manage-context---exclude-paths-1.aria.yml
0 → 100644
浏览文件 @
5db0b044
-
dialog
:
-
heading "Codebase Context" [level=3]
-
paragraph
:
-
text
:
Select the files to use as context.
-
img
-
textbox "src/**/*.tsx"
-
button "Add"
-
paragraph
:
Dyad will use the entire codebase as context.
-
heading "Exclude Paths" [level=3]
-
paragraph
:
-
text
:
These files will be excluded from the context.
-
img
-
textbox "node_modules/**/*"
-
button "Add"
\ No newline at end of file
e2e-tests/snapshots/context_manage.spec.ts_manage-context---exclude-paths-2.aria.yml
0 → 100644
浏览文件 @
5db0b044
-
dialog
:
-
heading "Codebase Context" [level=3]
-
paragraph
:
-
text
:
Select the files to use as context.
-
img
-
textbox "src/**/*.tsx"
-
button "Add"
-
text
:
/src\/\*\*\/\*\.ts 4 files, ~\d+ tokens/
-
button
:
-
img
-
text
:
/manual\/\*\* 3 files, ~\d+ tokens/
-
button
:
-
img
-
heading "Exclude Paths" [level=3]
-
paragraph
:
-
text
:
These files will be excluded from the context.
-
img
-
textbox "node_modules/**/*"
-
button "Add"
-
text
:
/src\/components\/\*\* 2 files, ~\d+ tokens/
-
button
:
-
img
-
text
:
manual/exclude/** 0 files, ~0 tokens
-
button
:
-
img
\ No newline at end of file
e2e-tests/snapshots/context_manage.spec.ts_manage-context---exclude-paths-3.aria.yml
0 → 100644
浏览文件 @
5db0b044
-
dialog
:
-
heading "Codebase Context" [level=3]
-
paragraph
:
-
text
:
Select the files to use as context.
-
img
-
textbox "src/**/*.tsx"
-
button "Add"
-
text
:
/src\/\*\*\/\*\.ts 4 files, ~\d+ tokens/
-
button
:
-
img
-
text
:
/manual\/\*\* 3 files, ~\d+ tokens/
-
button
:
-
img
-
heading "Exclude Paths" [level=3]
-
paragraph
:
-
text
:
These files will be excluded from the context.
-
img
-
textbox "node_modules/**/*"
-
button "Add"
-
text
:
manual/exclude/** 0 files, ~0 tokens
-
button
:
-
img
-
text
:
/src\/\*\* 7 files, ~\d+ tokens/
-
button
:
-
img
\ No newline at end of file
e2e-tests/snapshots/context_manage.spec.ts_manage-context---exclude-paths-with-smart-context-1.aria.yml
0 → 100644
浏览文件 @
5db0b044
-
dialog
:
-
heading "Codebase Context" [level=3]
-
paragraph
:
-
text
:
Select the files to use as context.
-
img
-
textbox "src/**/*.tsx"
-
button "Add"
-
paragraph
:
Dyad will use Smart Context to automatically find the most relevant files to use as context.
-
heading "Exclude Paths" [level=3]
-
paragraph
:
-
text
:
These files will be excluded from the context.
-
img
-
textbox "node_modules/**/*"
-
button "Add"
-
heading "Smart Context Auto-includes" [level=3]
-
paragraph
:
-
text
:
These files will always be included in the context.
-
img
-
textbox "src/**/*.config.ts"
-
button "Add"
\ No newline at end of file
e2e-tests/snapshots/context_manage.spec.ts_manage-context---exclude-paths-with-smart-context-2.aria.yml
0 → 100644
浏览文件 @
5db0b044
-
dialog
:
-
heading "Codebase Context" [level=3]
-
paragraph
:
-
text
:
Select the files to use as context.
-
img
-
textbox "src/**/*.tsx"
-
button "Add"
-
text
:
/src\/\*\*\/\*\.ts 4 files, ~\d+ tokens/
-
button
:
-
img
-
text
:
/manual\/\*\* 3 files, ~\d+ tokens/
-
button
:
-
img
-
heading "Exclude Paths" [level=3]
-
paragraph
:
-
text
:
These files will be excluded from the context.
-
img
-
textbox "node_modules/**/*"
-
button "Add"
-
text
:
/src\/components\/\*\* 2 files, ~\d+ tokens/
-
button
:
-
img
-
text
:
/exclude\/exclude\.ts 1 files, ~\d+ tokens/
-
button
:
-
img
-
heading "Smart Context Auto-includes" [level=3]
-
paragraph
:
-
text
:
These files will always be included in the context.
-
img
-
textbox "src/**/*.config.ts"
-
button "Add"
-
text
:
/a\.ts 1 files, ~\d+ tokens/
-
button
:
-
img
-
text
:
/exclude\/\*\* 2 files, ~\d+ tokens/
-
button
:
-
img
\ No newline at end of file
src/components/ContextFilesPicker.tsx
浏览文件 @
5db0b044
...
...
@@ -16,29 +16,33 @@ import {
}
from
"./ui/tooltip"
;
import
{
useSettings
}
from
"@/hooks/useSettings"
;
import
{
useContextPaths
}
from
"@/hooks/useContextPaths"
;
import
type
{
ContextPathResult
}
from
"@/lib/schemas"
;
export
function
ContextFilesPicker
()
{
const
{
settings
}
=
useSettings
();
const
{
contextPaths
,
smartContextAutoIncludes
,
excludePaths
,
updateContextPaths
,
updateSmartContextAutoIncludes
,
updateExcludePaths
,
}
=
useContextPaths
();
const
[
isOpen
,
setIsOpen
]
=
useState
(
false
);
const
[
newPath
,
setNewPath
]
=
useState
(
""
);
const
[
newAutoIncludePath
,
setNewAutoIncludePath
]
=
useState
(
""
);
const
[
newExcludePath
,
setNewExcludePath
]
=
useState
(
""
);
const
addPath
=
()
=>
{
if
(
newPath
.
trim
()
===
""
||
contextPaths
.
find
((
p
)
=>
p
.
globPath
===
newPath
)
contextPaths
.
find
((
p
:
ContextPathResult
)
=>
p
.
globPath
===
newPath
)
)
{
setNewPath
(
""
);
return
;
}
const
newPaths
=
[
...
contextPaths
.
map
(({
globPath
})
=>
({
globPath
})),
...
contextPaths
.
map
(({
globPath
}
:
ContextPathResult
)
=>
({
globPath
})),
{
globPath
:
newPath
,
},
...
...
@@ -49,21 +53,25 @@ export function ContextFilesPicker() {
const
removePath
=
(
pathToRemove
:
string
)
=>
{
const
newPaths
=
contextPaths
.
filter
((
p
)
=>
p
.
globPath
!==
pathToRemove
)
.
map
(({
globPath
})
=>
({
globPath
}));
.
filter
((
p
:
ContextPathResult
)
=>
p
.
globPath
!==
pathToRemove
)
.
map
(({
globPath
}
:
ContextPathResult
)
=>
({
globPath
}));
updateContextPaths
(
newPaths
);
};
const
addAutoIncludePath
=
()
=>
{
if
(
newAutoIncludePath
.
trim
()
===
""
||
smartContextAutoIncludes
.
find
((
p
)
=>
p
.
globPath
===
newAutoIncludePath
)
smartContextAutoIncludes
.
find
(
(
p
:
ContextPathResult
)
=>
p
.
globPath
===
newAutoIncludePath
,
)
)
{
setNewAutoIncludePath
(
""
);
return
;
}
const
newPaths
=
[
...
smartContextAutoIncludes
.
map
(({
globPath
})
=>
({
globPath
})),
...
smartContextAutoIncludes
.
map
(({
globPath
}:
ContextPathResult
)
=>
({
globPath
,
})),
{
globPath
:
newAutoIncludePath
,
},
...
...
@@ -74,11 +82,36 @@ export function ContextFilesPicker() {
const
removeAutoIncludePath
=
(
pathToRemove
:
string
)
=>
{
const
newPaths
=
smartContextAutoIncludes
.
filter
((
p
)
=>
p
.
globPath
!==
pathToRemove
)
.
map
(({
globPath
})
=>
({
globPath
}));
.
filter
((
p
:
ContextPathResult
)
=>
p
.
globPath
!==
pathToRemove
)
.
map
(({
globPath
}
:
ContextPathResult
)
=>
({
globPath
}));
updateSmartContextAutoIncludes
(
newPaths
);
};
const
addExcludePath
=
()
=>
{
if
(
newExcludePath
.
trim
()
===
""
||
excludePaths
.
find
((
p
:
ContextPathResult
)
=>
p
.
globPath
===
newExcludePath
)
)
{
setNewExcludePath
(
""
);
return
;
}
const
newPaths
=
[
...
excludePaths
.
map
(({
globPath
}:
ContextPathResult
)
=>
({
globPath
})),
{
globPath
:
newExcludePath
,
},
];
updateExcludePaths
(
newPaths
);
setNewExcludePath
(
""
);
};
const
removeExcludePath
=
(
pathToRemove
:
string
)
=>
{
const
newPaths
=
excludePaths
.
filter
((
p
:
ContextPathResult
)
=>
p
.
globPath
!==
pathToRemove
)
.
map
(({
globPath
}:
ContextPathResult
)
=>
({
globPath
}));
updateExcludePaths
(
newPaths
);
};
const
isSmartContextEnabled
=
settings
?.
enableDyadPro
&&
settings
?.
enableProSmartFilesContextMode
;
...
...
@@ -100,7 +133,10 @@ export function ContextFilesPicker() {
<
TooltipContent
>
Codebase Context
</
TooltipContent
>
</
Tooltip
>
<
PopoverContent
className=
"w-96"
align=
"start"
>
<
PopoverContent
className=
"w-96 max-h-[80vh] overflow-y-auto"
align=
"start"
>
<
div
className=
"relative space-y-4"
>
<
div
>
<
h3
className=
"font-medium"
>
Codebase Context
</
h3
>
...
...
@@ -153,7 +189,7 @@ export function ContextFilesPicker() {
<
TooltipProvider
>
{
contextPaths
.
length
>
0
?
(
<
div
className=
"space-y-2"
>
{
contextPaths
.
map
((
p
)
=>
(
{
contextPaths
.
map
((
p
:
ContextPathResult
)
=>
(
<
div
key=
{
p
.
globPath
}
className=
"flex items-center justify-between gap-2 rounded-md border p-2"
...
...
@@ -197,6 +233,91 @@ export function ContextFilesPicker() {
)
}
</
TooltipProvider
>
<
div
className=
"pt-2"
>
<
div
>
<
h3
className=
"font-medium"
>
Exclude Paths
</
h3
>
<
p
className=
"text-sm text-muted-foreground"
>
<
TooltipProvider
>
<
Tooltip
>
<
TooltipTrigger
asChild
>
<
span
className=
"flex items-center gap-1 cursor-help"
>
These files will be excluded from the context.
{
" "
}
<
InfoIcon
className=
"ml-2 size-4"
/>
</
span
>
</
TooltipTrigger
>
<
TooltipContent
className=
"max-w-[300px]"
>
<
p
>
Exclude paths take precedence - files that match both
include and exclude patterns will be excluded.
</
p
>
</
TooltipContent
>
</
Tooltip
>
</
TooltipProvider
>
</
p
>
</
div
>
<
div
className=
"flex w-full max-w-sm items-center space-x-2 mt-4"
>
<
Input
data
-
testid=
"exclude-context-files-input"
type=
"text"
placeholder=
"node_modules/**/*"
value=
{
newExcludePath
}
onChange=
{
(
e
)
=>
setNewExcludePath
(
e
.
target
.
value
)
}
onKeyDown=
{
(
e
)
=>
{
if
(
e
.
key
===
"Enter"
)
{
addExcludePath
();
}
}
}
/>
<
Button
type=
"submit"
onClick=
{
addExcludePath
}
data
-
testid=
"exclude-context-files-add-button"
>
Add
</
Button
>
</
div
>
<
TooltipProvider
>
{
excludePaths
.
length
>
0
&&
(
<
div
className=
"space-y-2 mt-4"
>
{
excludePaths
.
map
((
p
:
ContextPathResult
)
=>
(
<
div
key=
{
p
.
globPath
}
className=
"flex items-center justify-between gap-2 rounded-md border p-2 border-red-200"
>
<
div
className=
"flex flex-1 flex-col overflow-hidden"
>
<
Tooltip
>
<
TooltipTrigger
asChild
>
<
span
className=
"truncate font-mono text-sm text-red-600"
>
{
p
.
globPath
}
</
span
>
</
TooltipTrigger
>
<
TooltipContent
>
<
p
>
{
p
.
globPath
}
</
p
>
</
TooltipContent
>
</
Tooltip
>
<
span
className=
"text-xs text-muted-foreground"
>
{
p
.
files
}
files, ~
{
p
.
tokens
}
tokens
</
span
>
</
div
>
<
div
className=
"flex items-center gap-2"
>
<
Button
variant=
"ghost"
size=
"icon"
onClick=
{
()
=>
removeExcludePath
(
p
.
globPath
)
}
data
-
testid=
"exclude-context-files-remove-button"
>
<
Trash2
className=
"size-4"
/>
</
Button
>
</
div
>
</
div
>
))
}
</
div
>
)
}
</
TooltipProvider
>
</
div
>
{
isSmartContextEnabled
&&
(
<
div
className=
"pt-2"
>
<
div
>
...
...
@@ -247,7 +368,7 @@ export function ContextFilesPicker() {
<
TooltipProvider
>
{
smartContextAutoIncludes
.
length
>
0
&&
(
<
div
className=
"space-y-2 mt-4"
>
{
smartContextAutoIncludes
.
map
((
p
)
=>
(
{
smartContextAutoIncludes
.
map
((
p
:
ContextPathResult
)
=>
(
<
div
key=
{
p
.
globPath
}
className=
"flex items-center justify-between gap-2 rounded-md border p-2"
...
...
src/hooks/useContextPaths.ts
浏览文件 @
5db0b044
...
...
@@ -15,7 +15,12 @@ export function useContextPaths() {
}
=
useQuery
<
ContextPathResults
,
Error
>
({
queryKey
:
[
"context-paths"
,
appId
],
queryFn
:
async
()
=>
{
if
(
!
appId
)
return
{
contextPaths
:
[],
smartContextAutoIncludes
:
[]
};
if
(
!
appId
)
return
{
contextPaths
:
[],
smartContextAutoIncludes
:
[],
excludePaths
:
[],
};
const
ipcClient
=
IpcClient
.
getInstance
();
return
ipcClient
.
getChatContextResults
({
appId
});
},
...
...
@@ -25,9 +30,17 @@ export function useContextPaths() {
const
updateContextPathsMutation
=
useMutation
<
unknown
,
Error
,
{
contextPaths
:
GlobPath
[];
smartContextAutoIncludes
?:
GlobPath
[]
}
{
contextPaths
:
GlobPath
[];
smartContextAutoIncludes
?:
GlobPath
[];
excludePaths
?:
GlobPath
[];
}
>
({
mutationFn
:
async
({
contextPaths
,
smartContextAutoIncludes
})
=>
{
mutationFn
:
async
({
contextPaths
,
smartContextAutoIncludes
,
excludePaths
,
})
=>
{
if
(
!
appId
)
throw
new
Error
(
"No app selected"
);
const
ipcClient
=
IpcClient
.
getInstance
();
return
ipcClient
.
setChatContext
({
...
...
@@ -35,6 +48,7 @@ export function useContextPaths() {
chatContext
:
{
contextPaths
,
smartContextAutoIncludes
:
smartContextAutoIncludes
||
[],
excludePaths
:
excludePaths
||
[],
},
});
},
...
...
@@ -46,28 +60,63 @@ export function useContextPaths() {
const
updateContextPaths
=
async
(
paths
:
GlobPath
[])
=>
{
const
currentAutoIncludes
=
contextPathsData
?.
smartContextAutoIncludes
||
[];
const
currentExcludePaths
=
contextPathsData
?.
excludePaths
||
[];
return
updateContextPathsMutation
.
mutateAsync
({
contextPaths
:
paths
,
smartContextAutoIncludes
:
currentAutoIncludes
.
map
(({
globPath
})
=>
({
globPath
,
})),
smartContextAutoIncludes
:
currentAutoIncludes
.
map
(
({
globPath
}:
{
globPath
:
string
})
=>
({
globPath
,
}),
),
excludePaths
:
currentExcludePaths
.
map
(
({
globPath
}:
{
globPath
:
string
})
=>
({
globPath
,
}),
),
});
};
const
updateSmartContextAutoIncludes
=
async
(
paths
:
GlobPath
[])
=>
{
const
currentContextPaths
=
contextPathsData
?.
contextPaths
||
[];
const
currentExcludePaths
=
contextPathsData
?.
excludePaths
||
[];
return
updateContextPathsMutation
.
mutateAsync
({
contextPaths
:
currentContextPaths
.
map
(({
globPath
})
=>
({
globPath
})),
contextPaths
:
currentContextPaths
.
map
(
({
globPath
}:
{
globPath
:
string
})
=>
({
globPath
}),
),
smartContextAutoIncludes
:
paths
,
excludePaths
:
currentExcludePaths
.
map
(
({
globPath
}:
{
globPath
:
string
})
=>
({
globPath
,
}),
),
});
};
const
updateExcludePaths
=
async
(
paths
:
GlobPath
[])
=>
{
const
currentContextPaths
=
contextPathsData
?.
contextPaths
||
[];
const
currentAutoIncludes
=
contextPathsData
?.
smartContextAutoIncludes
||
[];
return
updateContextPathsMutation
.
mutateAsync
({
contextPaths
:
currentContextPaths
.
map
(
({
globPath
}:
{
globPath
:
string
})
=>
({
globPath
}),
),
smartContextAutoIncludes
:
currentAutoIncludes
.
map
(
({
globPath
}:
{
globPath
:
string
})
=>
({
globPath
,
}),
),
excludePaths
:
paths
,
});
};
return
{
contextPaths
:
contextPathsData
?.
contextPaths
||
[],
smartContextAutoIncludes
:
contextPathsData
?.
smartContextAutoIncludes
||
[],
excludePaths
:
contextPathsData
?.
excludePaths
||
[],
isLoading
,
error
,
updateContextPaths
,
updateSmartContextAutoIncludes
,
updateExcludePaths
,
};
}
src/ipc/handlers/context_paths_handlers.ts
浏览文件 @
5db0b044
...
...
@@ -39,10 +39,10 @@ export function registerContextPathsHandlers() {
const
results
:
ContextPathResults
=
{
contextPaths
:
[],
smartContextAutoIncludes
:
[],
excludePaths
:
[],
};
const
{
contextPaths
,
smartContextAutoIncludes
}
=
validateChatContext
(
app
.
chatContext
,
);
const
{
contextPaths
,
smartContextAutoIncludes
,
excludePaths
}
=
validateChatContext
(
app
.
chatContext
);
for
(
const
contextPath
of
contextPaths
)
{
const
{
formattedOutput
,
files
}
=
await
extractCodebase
({
appPath
,
...
...
@@ -76,6 +76,23 @@ export function registerContextPathsHandlers() {
tokens
:
totalTokens
,
});
}
for
(
const
excludePath
of
excludePaths
||
[])
{
const
{
formattedOutput
,
files
}
=
await
extractCodebase
({
appPath
,
chatContext
:
{
contextPaths
:
[
excludePath
],
smartContextAutoIncludes
:
[],
},
});
const
totalTokens
=
estimateTokens
(
formattedOutput
);
results
.
excludePaths
.
push
({
...
excludePath
,
files
:
files
.
length
,
tokens
:
totalTokens
,
});
}
return
results
;
},
);
...
...
src/ipc/utils/context_paths_utils.ts
浏览文件 @
5db0b044
...
...
@@ -8,6 +8,7 @@ export function validateChatContext(chatContext: unknown): AppChatContext {
return
{
contextPaths
:
[],
smartContextAutoIncludes
:
[],
excludePaths
:
[],
};
}
...
...
@@ -20,6 +21,7 @@ export function validateChatContext(chatContext: unknown): AppChatContext {
return
{
contextPaths
:
[],
smartContextAutoIncludes
:
[],
excludePaths
:
[],
};
}
}
src/lib/schemas.ts
浏览文件 @
5db0b044
...
...
@@ -120,6 +120,7 @@ export type GlobPath = z.infer<typeof GlobPathSchema>;
export
const
AppChatContextSchema
=
z
.
object
({
contextPaths
:
z
.
array
(
GlobPathSchema
),
smartContextAutoIncludes
:
z
.
array
(
GlobPathSchema
),
excludePaths
:
z
.
array
(
GlobPathSchema
).
optional
(),
});
export
type
AppChatContext
=
z
.
infer
<
typeof
AppChatContextSchema
>
;
...
...
@@ -131,6 +132,7 @@ export type ContextPathResult = GlobPath & {
export
type
ContextPathResults
=
{
contextPaths
:
ContextPathResult
[];
smartContextAutoIncludes
:
ContextPathResult
[];
excludePaths
:
ContextPathResult
[];
};
export
const
ReleaseChannelSchema
=
z
.
enum
([
"stable"
,
"beta"
]);
...
...
src/utils/codebase.ts
浏览文件 @
5db0b044
...
...
@@ -472,9 +472,10 @@ export async function extractCodebase({
}
// Collect files from contextPaths and smartContextAutoIncludes
const
{
contextPaths
,
smartContextAutoIncludes
}
=
chatContext
;
const
{
contextPaths
,
smartContextAutoIncludes
,
excludePaths
}
=
chatContext
;
const
includedFiles
=
new
Set
<
string
>
();
const
autoIncludedFiles
=
new
Set
<
string
>
();
const
excludedFiles
=
new
Set
<
string
>
();
// Add files from contextPaths
if
(
contextPaths
&&
contextPaths
.
length
>
0
)
{
...
...
@@ -509,6 +510,7 @@ export async function extractCodebase({
const
matches
=
await
glob
(
pattern
,
{
nodir
:
true
,
absolute
:
true
,
ignore
:
"**/node_modules/**"
,
});
matches
.
forEach
((
file
)
=>
{
const
normalizedFile
=
path
.
normalize
(
file
);
...
...
@@ -518,12 +520,36 @@ export async function extractCodebase({
}
}
// Add files from excludePaths
if
(
excludePaths
&&
excludePaths
.
length
>
0
)
{
for
(
const
p
of
excludePaths
)
{
const
pattern
=
createFullGlobPath
({
appPath
,
globPath
:
p
.
globPath
,
});
const
matches
=
await
glob
(
pattern
,
{
nodir
:
true
,
absolute
:
true
,
ignore
:
"**/node_modules/**"
,
});
matches
.
forEach
((
file
)
=>
{
const
normalizedFile
=
path
.
normalize
(
file
);
excludedFiles
.
add
(
normalizedFile
);
});
}
}
// Only filter files if contextPaths are provided
// If only smartContextAutoIncludes are provided, keep all files and just mark auto-includes as forced
if
(
contextPaths
&&
contextPaths
.
length
>
0
)
{
files
=
files
.
filter
((
file
)
=>
includedFiles
.
has
(
path
.
normalize
(
file
)));
}
// Filter out excluded files (this takes precedence over include paths)
if
(
excludedFiles
.
size
>
0
)
{
files
=
files
.
filter
((
file
)
=>
!
excludedFiles
.
has
(
path
.
normalize
(
file
)));
}
// Sort files by modification time (oldest first)
// This is important for cache-ability.
const
sortedFiles
=
await
sortFilesByModificationTime
([...
new
Set
(
files
)]);
...
...
@@ -543,7 +569,9 @@ export async function extractCodebase({
virtualFileSystem
,
});
const
isForced
=
autoIncludedFiles
.
has
(
path
.
normalize
(
file
));
const
isForced
=
autoIncludedFiles
.
has
(
path
.
normalize
(
file
))
&&
!
excludedFiles
.
has
(
path
.
normalize
(
file
));
// Determine file content based on whether we should read it
let
fileContent
:
string
;
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论