Crate renames: - zesdex-entities::seaorm → domain (misleading name, no SeaORM used) - zesdex-dto → merged into zesdex-entities (100% re-exports) - zesdex-libs → zesdex-infra (vague name) Module renames: - app/harness → guard (misleading: safety gatekeeper, not test harness) - runtime/commands → action_dispatch (name clashed with controller/command) - resources → prompts (embedded prompt text, not general resources) - tool/seqthink → sequential_think (unreadable abbreviation) - msglog/query → insert (module only inserts, never queries) Dead code removal: - app/mode/help.rs (orphaned — not declared in mod.rs) - app/mode/loading.rs (orphaned — not declared in mod.rs) File splitting (71 new files, avg ~115 lines/file): - app/runtime/actions/: 1→8 files (was 2030 lines) - view/overlays/: 1→16 files (was 1167 lines) - tool/lsp/: 1→8 per-tool files (was 909 lines) - main.rs: 1→5 files (session, daemon, attach, event_loop) - workflow/engine + hive_mind: 2→10 files - subagent/engine + auto: 2→9 files - lsp/provisioner: 1→5 files - review/: 1→6 files - guard/: 1→2 files (extracted patterns) - state/misc: 1→3 files (input, scroll) - mcp/: 1→3 files (transport, adapter) - stream/json_repair extracted from turn.rs DRY: - Pattern constants (STUB_PATTERNS etc) in guard/patterns shared with subagent - 3 near-identical background spawners → 1 generic + thin wrappers - Shared spawn_subagent_with_drain() extracted - Shared create_session() in main - write_osc52 deduplicated Bug fixes: - archive_message(): sess.db → db (wrong variable name) - execute_one_tool(): wrong parameter name - check_credential_read() function was missing (restored from test expectations)
125 lines
4.0 KiB
Rust
125 lines
4.0 KiB
Rust
//! Path classification helpers for auto-subagent orchestration.
|
|
//!
|
|
//! Determines whether a file path is reviewable and whether it represents
|
|
//! production code (vs. tests, config, or documentation) — used to decide
|
|
//! which background subagents should fire for a given set of modified files.
|
|
|
|
/// File extensions that should not trigger auto-review (config, lock, data).
|
|
pub(crate) const SKIP_REVIEW_EXTENSIONS: &[&str] = &[
|
|
".lock",
|
|
".md",
|
|
".txt",
|
|
".json",
|
|
".toml",
|
|
".yaml",
|
|
".yml",
|
|
".svg",
|
|
".png",
|
|
".jpg",
|
|
".ico",
|
|
".woff",
|
|
".woff2",
|
|
];
|
|
|
|
/// File names that should not trigger auto-review.
|
|
pub(crate) const SKIP_REVIEW_FILES: &[&str] = &[
|
|
"Cargo.lock",
|
|
"yarn.lock",
|
|
"package-lock.json",
|
|
".gitignore",
|
|
".env",
|
|
".env.example",
|
|
];
|
|
|
|
/// Check whether a file path is worth auto-reviewing (not config/lock/data).
|
|
///
|
|
/// Vendored/generated directories are matched by path *segment* rather than
|
|
/// a `/target/`-style substring check — the substring form misses paths
|
|
/// where the directory is the first component (e.g. `target/debug/build.rs`,
|
|
/// which has no leading slash), the same class of bug fixed in
|
|
/// `is_production_code` below.
|
|
pub fn is_reviewable_path(path: &str) -> bool {
|
|
let lower = path.to_lowercase();
|
|
if SKIP_REVIEW_FILES.iter().any(|f| lower.ends_with(f)) {
|
|
return false;
|
|
}
|
|
if SKIP_REVIEW_EXTENSIONS.iter().any(|e| lower.ends_with(e)) {
|
|
return false;
|
|
}
|
|
// Skip paths that are clearly generated or vendored
|
|
let in_vendored_dir = std::path::Path::new(&lower).components().any(|c| {
|
|
matches!(
|
|
c,
|
|
std::path::Component::Normal(seg)
|
|
if matches!(seg.to_str(), Some("target" | "node_modules" | ".git" | "vendor"))
|
|
)
|
|
});
|
|
if in_vendored_dir {
|
|
return false;
|
|
}
|
|
true
|
|
}
|
|
|
|
/// Determine whether a file change looks like it modifies production logic
|
|
/// (vs. tests, config, or documentation) — used to decide if a test-gen
|
|
/// or security-review background subagent should fire.
|
|
///
|
|
/// Matches test-ness by path *segment* (a directory literally named
|
|
/// "test"/"tests"/"__tests__") or by filename convention
|
|
/// (`foo_test.rs`, `foo.test.ts`, `test_foo.py`, `foo_spec.rb`), not by a
|
|
/// raw substring check — a plain `.contains("test")` would wrongly exclude
|
|
/// legitimate production files like `src/attestation.rs` or
|
|
/// `src/latest/foo.rs`.
|
|
pub(crate) fn is_production_code(path: &str) -> bool {
|
|
let lower = path.to_lowercase();
|
|
let path_obj = std::path::Path::new(&lower);
|
|
|
|
let in_test_dir = path_obj.components().any(|c| {
|
|
matches!(
|
|
c,
|
|
std::path::Component::Normal(seg)
|
|
if matches!(seg.to_str(), Some("test" | "tests" | "__tests__"))
|
|
)
|
|
});
|
|
|
|
let file_stem = path_obj.file_stem().and_then(|s| s.to_str()).unwrap_or("");
|
|
let is_test_filename = file_stem.starts_with("test_")
|
|
|| file_stem.ends_with("_test")
|
|
|| std::path::Path::new(file_stem)
|
|
.extension()
|
|
.is_some_and(|ext| ext.eq_ignore_ascii_case("test"))
|
|
|| file_stem == "spec"
|
|
|| file_stem.ends_with("_spec")
|
|
|| std::path::Path::new(file_stem)
|
|
.extension()
|
|
.is_some_and(|ext| ext.eq_ignore_ascii_case("spec"));
|
|
|
|
if in_test_dir || is_test_filename {
|
|
return false;
|
|
}
|
|
|
|
// Only source files — use Path::extension() to avoid clippy
|
|
// case_sensitive_file_extension_comparisons lint
|
|
path_obj
|
|
.extension()
|
|
.and_then(|ext| ext.to_str())
|
|
.is_some_and(|ext| {
|
|
matches!(
|
|
ext,
|
|
"rs" | "ts"
|
|
| "tsx"
|
|
| "js"
|
|
| "jsx"
|
|
| "go"
|
|
| "py"
|
|
| "java"
|
|
| "kt"
|
|
| "swift"
|
|
| "c"
|
|
| "cpp"
|
|
| "h"
|
|
| "hpp"
|
|
)
|
|
})
|
|
}
|