导出工作目录 .export 只排除在快照同步之外

- filesystem.rs 新增 PROJECT_SNAPSHOT_SYNC_ONLY_EXCLUDED_COMPONENTS(当前只有 .export):导出注册表、打包脚本拷贝、icon 与 zip 产物都能从项目源码重跑出来,不进项目快照同步。
- 刻意不并入通用排除列表:那份列表同时是 Agent 的写入门禁(agent/direct_patch.rs 直接拿它拒绝路径,agc_apply_patch 报「不得修改受保护或排除路径」),并进去会让 code agent 写不了 .export/ 下的适配脚本。
- project_snapshot 测试补齐两侧口径:.export/* 必须被同步排除,且不得被通用口径排除。
This commit is contained in:
2026-10-05 16:30:32 +08:00
parent 95323ce542
commit 3369f76b16
2 changed files with 34 additions and 1 deletions
@@ -416,6 +416,9 @@ pub(crate) fn should_skip_project_snapshot_path(relative_path: &str) -> bool {
*
* 其余排除项在 `.agent` 内同样生效:版本库、依赖与构建目录、凭据目录、敏感后缀、
* `.env*` 与凭据类文件名一律不参与同步;符号链接与重解析点在扫描阶段单独跳过。
*
* 另外,同步还多认 `PROJECT_SNAPSHOT_SYNC_ONLY_EXCLUDED_COMPONENTS`(`.export`):本机派生
* 的导出工作目录不进同步,但 Agent 仍要能读写它。
*/
pub(crate) fn should_skip_project_snapshot_sync_path(relative_path: &str) -> bool {
project_snapshot_path_is_excluded(relative_path, true)
@@ -488,6 +491,18 @@ const PROJECT_SNAPSHOT_EXCLUDED_SUFFIXES: &[&str] = &[
/// 随快照同步;其它数据库与转储后缀仍然排除。
const PROJECT_AGENT_STATE_DATABASE_SUFFIXES: &[&str] = &[".db", ".db-wal", ".db-shm"];
/**
* 只对快照同步生效的排除组件。
*
* 不能并进上面的通用列表:那份列表同时是 Agent 的写入门禁(`agent/direct_patch.rs` 直接拿它
* 拒绝路径),而 `.export` 恰恰必须让 code agent 能写——导出注册表、打包脚本拷贝都由它生成。
* 放进去会让 `agc_apply_patch` 回「不得修改受保护或排除路径」,首次适配直接卡死。
*
* `.export` 是本机派生的导出工作目录:注册表、脚本拷贝、icon 与 zip 产物都能从项目源码重跑
* 出来,zip 动辄数 MB,因此不进快照同步;换机或恢复后重新适配即可。
*/
const PROJECT_SNAPSHOT_SYNC_ONLY_EXCLUDED_COMPONENTS: &[&str] = &[".export"];
fn project_snapshot_path_is_excluded(relative_path: &str, include_agent_state: bool) -> bool {
let components = relative_path
.split('/')
@@ -497,7 +512,11 @@ fn project_snapshot_path_is_excluded(relative_path: &str, include_agent_state: b
if components.iter().any(|component| {
PROJECT_SNAPSHOT_EXCLUDED_COMPONENTS.contains(&component.as_str())
&& !(include_agent_state && component == ".agent")
}) {
}) || (include_agent_state
&& components.iter().any(|component| {
PROJECT_SNAPSHOT_SYNC_ONLY_EXCLUDED_COMPONENTS.contains(&component.as_str())
}))
{
return true;
}
let Some(file_name) = components.last() else {
@@ -214,6 +214,11 @@ fn project_snapshot_sync_policy_keeps_agent_state_and_still_blocks_credentials()
"node_modules/pkg/index.js",
"game/dist/bundle.js",
"secrets/key.pem",
// 导出工作目录整体不进快照:zip 与脚本拷贝都能从项目源码重新跑出来。
".export/xhs-minitool.zip",
".export/xhs-minitool.json",
".export/xhs-minitool.pack.mjs",
".EXPORT/xhs-minitool.zip",
"",
] {
assert!(
@@ -226,6 +231,15 @@ fn project_snapshot_sync_policy_keeps_agent_state_and_still_blocks_credentials()
assert!(should_skip_project_snapshot_path(".agent/manifest.json"));
assert!(should_skip_project_index_path(".agent/manifest.json"));
assert!(should_skip_project_index_path(".agent/agent.db"));
// `.export/` 只排除在快照同步之外:通用口径同时是 Agent 的写入门禁
// (`agc_apply_patch` 直接拿它拒路径),一并拒掉会让 code agent 写不了适配脚本。
assert!(!should_skip_project_snapshot_path(
".export/xhs-minitool.pack.mjs"
));
assert!(!should_skip_project_snapshot_path(
".export/xhs-minitool.json"
));
}
#[test]