推进本地优先迁移与资源闭环
- 补齐共享只读页面 AI 浏览器 smoke,并回填当前优先级 checklist 的 P4/P5/P6 证据。
- 为 OnlyOffice 资源增加 /office/{documentId}/{assetId} 对象壳,固定 resource identity 与侧边栏打开路径。
- 扩展 Convex 导出脚本,支持 dry-run、manifest、冲突报告、索引刷新与 rollback,并补充 smoke。
- 补充资源 AI 工具合同与 Convex 导出 Web 入口设计。
This commit is contained in:
@@ -4163,12 +4163,6 @@ fn local_agent_audit_should_skip(path: &FsPath) -> bool {
|
||||
)
|
||||
}
|
||||
|
||||
fn local_agent_audit_hash(text: &str) -> u64 {
|
||||
let mut hasher = std::collections::hash_map::DefaultHasher::new();
|
||||
text.hash(&mut hasher);
|
||||
hasher.finish()
|
||||
}
|
||||
|
||||
fn local_agent_audit_snapshot_entry(
|
||||
path: &FsPath,
|
||||
) -> Result<LocalAgentAuditFileSnapshot, WebError> {
|
||||
@@ -4185,18 +4179,22 @@ fn local_agent_audit_snapshot_entry(
|
||||
.map(|duration| duration.as_millis())
|
||||
.unwrap_or_default();
|
||||
let size = metadata.len();
|
||||
let content = fs::read_to_string(path).ok();
|
||||
let hash = content
|
||||
.as_deref()
|
||||
.map(local_agent_audit_hash)
|
||||
.unwrap_or_default();
|
||||
let markdown_content = content.and_then(|content| {
|
||||
if path.extension().and_then(|value| value.to_str()) == Some("md") {
|
||||
Some(content)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
let bytes = fs::read(path).map_err(|error| {
|
||||
WebError::bad_request_code(
|
||||
"local_ai_audit_snapshot_failed",
|
||||
format!("无法读取本地文件快照内容: {error}"),
|
||||
)
|
||||
})?;
|
||||
let hash = {
|
||||
let mut hasher = std::collections::hash_map::DefaultHasher::new();
|
||||
bytes.hash(&mut hasher);
|
||||
hasher.finish()
|
||||
};
|
||||
let markdown_content = if path.extension().and_then(|value| value.to_str()) == Some("md") {
|
||||
String::from_utf8(bytes).ok()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
Ok(LocalAgentAuditFileSnapshot {
|
||||
size,
|
||||
modified_ms,
|
||||
@@ -5593,6 +5591,38 @@ mod tests {
|
||||
let _ = std::fs::remove_dir_all(&root);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn local_agent_audit_snapshot_detects_resource_files() {
|
||||
let root = std::env::temp_dir().join(format!(
|
||||
"mnote-local-agent-audit-resources-{}",
|
||||
std::process::id()
|
||||
));
|
||||
let _ = std::fs::remove_dir_all(&root);
|
||||
std::fs::create_dir_all(root.join("maps")).expect("create maps dir");
|
||||
std::fs::create_dir_all(root.join("office")).expect("create office dir");
|
||||
std::fs::write(root.join("maps/a.mindmap.json"), r#"{"root":"old"}"#)
|
||||
.expect("write mindmap");
|
||||
std::fs::write(root.join("office/a.docx"), [0xff, 1, 2, 3]).expect("write office");
|
||||
let root_uri = format!("file://{}", root.display());
|
||||
let before = local_agent_audit_collect_snapshot(&root_uri).expect("before snapshot");
|
||||
|
||||
std::fs::write(root.join("maps/a.mindmap.json"), r#"{"root":"new"}"#)
|
||||
.expect("modify mindmap");
|
||||
std::fs::write(root.join("office/a.docx"), [0xfe, 1, 2, 3]).expect("modify office");
|
||||
let after = local_agent_audit_collect_snapshot(&root_uri).expect("after snapshot");
|
||||
let changed = local_agent_audit_change_files(&before, &after);
|
||||
let files = changed.as_array().expect("changed files");
|
||||
|
||||
assert!(files.iter().any(|file| {
|
||||
file["path"] == "maps/a.mindmap.json" && file["changeType"] == "modified"
|
||||
}));
|
||||
assert!(files
|
||||
.iter()
|
||||
.any(|file| { file["path"] == "office/a.docx" && file["changeType"] == "modified" }));
|
||||
|
||||
let _ = std::fs::remove_dir_all(&root);
|
||||
}
|
||||
|
||||
fn app() -> axum::Router {
|
||||
app_with_config(AppConfig {
|
||||
service_name: "mnote-web".into(),
|
||||
|
||||
Reference in New Issue
Block a user