fix: add --all to cargo fmt in script/test and autoformat codebase
cargo fmt without --all fails with "Failed to find targets" in workspace repos. This was blocking every story's gates. Also ran cargo fmt --all to fix all existing formatting issues. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -6,8 +6,8 @@ pub mod project;
|
||||
pub mod scaffold;
|
||||
|
||||
pub use files::{
|
||||
create_directory_absolute, list_directory, list_directory_absolute, list_project_files,
|
||||
read_file, write_file, FileEntry,
|
||||
FileEntry, create_directory_absolute, list_directory, list_directory_absolute,
|
||||
list_project_files, read_file, write_file,
|
||||
};
|
||||
pub use paths::{find_story_kit_root, get_home_directory, resolve_cli_path};
|
||||
pub use preferences::{get_model_preference, set_model_preference};
|
||||
|
||||
+67
-22
@@ -180,7 +180,13 @@ mod tests {
|
||||
let store = make_store(&dir);
|
||||
let state = SessionState::default();
|
||||
|
||||
let result = open_project(project_dir.to_string_lossy().to_string(), &state, &store, 3001).await;
|
||||
let result = open_project(
|
||||
project_dir.to_string_lossy().to_string(),
|
||||
&state,
|
||||
&store,
|
||||
3001,
|
||||
)
|
||||
.await;
|
||||
|
||||
assert!(result.is_ok());
|
||||
let root = state.get_project_root().unwrap();
|
||||
@@ -201,9 +207,14 @@ mod tests {
|
||||
let store = make_store(&dir);
|
||||
let state = SessionState::default();
|
||||
|
||||
open_project(project_dir.to_string_lossy().to_string(), &state, &store, 3001)
|
||||
.await
|
||||
.unwrap();
|
||||
open_project(
|
||||
project_dir.to_string_lossy().to_string(),
|
||||
&state,
|
||||
&store,
|
||||
3001,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
fs::read_to_string(&mcp_path).unwrap(),
|
||||
@@ -220,15 +231,29 @@ mod tests {
|
||||
let store = make_store(&dir);
|
||||
let state = SessionState::default();
|
||||
|
||||
open_project(project_dir.to_string_lossy().to_string(), &state, &store, 3001)
|
||||
.await
|
||||
.unwrap();
|
||||
open_project(
|
||||
project_dir.to_string_lossy().to_string(),
|
||||
&state,
|
||||
&store,
|
||||
3001,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mcp_path = project_dir.join(".mcp.json");
|
||||
assert!(mcp_path.exists(), "open_project should write .mcp.json for new projects");
|
||||
assert!(
|
||||
mcp_path.exists(),
|
||||
"open_project should write .mcp.json for new projects"
|
||||
);
|
||||
let content = fs::read_to_string(&mcp_path).unwrap();
|
||||
assert!(content.contains("3001"), "mcp.json should reference the server port");
|
||||
assert!(content.contains("localhost"), "mcp.json should reference localhost");
|
||||
assert!(
|
||||
content.contains("3001"),
|
||||
"mcp.json should reference the server port"
|
||||
);
|
||||
assert!(
|
||||
content.contains("localhost"),
|
||||
"mcp.json should reference localhost"
|
||||
);
|
||||
}
|
||||
|
||||
/// Regression test for bug 371: no-arg `huskies` in empty directory skips scaffold.
|
||||
@@ -242,9 +267,14 @@ mod tests {
|
||||
let store = make_store(&dir);
|
||||
let state = SessionState::default();
|
||||
|
||||
open_project(project_dir.to_string_lossy().to_string(), &state, &store, 3001)
|
||||
.await
|
||||
.unwrap();
|
||||
open_project(
|
||||
project_dir.to_string_lossy().to_string(),
|
||||
&state,
|
||||
&store,
|
||||
3001,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert!(
|
||||
project_dir.join(".huskies/project.toml").exists(),
|
||||
@@ -316,9 +346,14 @@ mod tests {
|
||||
let store = make_store(&dir);
|
||||
let state = SessionState::default();
|
||||
|
||||
open_project(project_dir.to_string_lossy().to_string(), &state, &store, 3001)
|
||||
.await
|
||||
.unwrap();
|
||||
open_project(
|
||||
project_dir.to_string_lossy().to_string(),
|
||||
&state,
|
||||
&store,
|
||||
3001,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let projects = get_known_projects(&store).unwrap();
|
||||
assert_eq!(projects.len(), 1);
|
||||
@@ -383,9 +418,14 @@ mod tests {
|
||||
let store = make_store(&dir);
|
||||
let state = SessionState::default();
|
||||
|
||||
open_project(project_dir.to_string_lossy().to_string(), &state, &store, 3001)
|
||||
.await
|
||||
.unwrap();
|
||||
open_project(
|
||||
project_dir.to_string_lossy().to_string(),
|
||||
&state,
|
||||
&store,
|
||||
3001,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// .huskies/ should have been created automatically
|
||||
assert!(project_dir.join(".huskies").is_dir());
|
||||
@@ -402,9 +442,14 @@ mod tests {
|
||||
let store = make_store(&dir);
|
||||
let state = SessionState::default();
|
||||
|
||||
open_project(project_dir.to_string_lossy().to_string(), &state, &store, 3001)
|
||||
.await
|
||||
.unwrap();
|
||||
open_project(
|
||||
project_dir.to_string_lossy().to_string(),
|
||||
&state,
|
||||
&store,
|
||||
3001,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Existing .huskies/ content should not be overwritten
|
||||
assert_eq!(fs::read_to_string(&readme).unwrap(), "custom content");
|
||||
|
||||
@@ -4,8 +4,7 @@ use std::path::Path;
|
||||
|
||||
const STORY_KIT_README: &str = include_str!("../../../../.huskies/README.md");
|
||||
|
||||
const BOT_TOML_MATRIX_EXAMPLE: &str =
|
||||
include_str!("../../../../.huskies/bot.toml.matrix.example");
|
||||
const BOT_TOML_MATRIX_EXAMPLE: &str = include_str!("../../../../.huskies/bot.toml.matrix.example");
|
||||
const BOT_TOML_WHATSAPP_META_EXAMPLE: &str =
|
||||
include_str!("../../../../.huskies/bot.toml.whatsapp-meta.example");
|
||||
const BOT_TOML_WHATSAPP_TWILIO_EXAMPLE: &str =
|
||||
@@ -194,9 +193,7 @@ pub fn detect_components_toml(root: &Path) -> String {
|
||||
// No tech stack markers detected — emit a single generic component
|
||||
// with an empty setup list. The ONBOARDING_PROMPT instructs the chat
|
||||
// agent to inspect the project and replace this with real definitions.
|
||||
sections.push(
|
||||
"[[component]]\nname = \"app\"\npath = \".\"\nsetup = []\n".to_string(),
|
||||
);
|
||||
sections.push("[[component]]\nname = \"app\"\npath = \".\"\nsetup = []\n".to_string());
|
||||
}
|
||||
|
||||
sections.join("\n")
|
||||
@@ -826,9 +823,18 @@ mod tests {
|
||||
let mcp_path = dir.path().join(".mcp.json");
|
||||
assert!(mcp_path.exists(), ".mcp.json should be created by scaffold");
|
||||
let content = fs::read_to_string(&mcp_path).unwrap();
|
||||
assert!(content.contains("4242"), ".mcp.json should reference the given port");
|
||||
assert!(content.contains("localhost"), ".mcp.json should reference localhost");
|
||||
assert!(content.contains("huskies"), ".mcp.json should name the huskies server");
|
||||
assert!(
|
||||
content.contains("4242"),
|
||||
".mcp.json should reference the given port"
|
||||
);
|
||||
assert!(
|
||||
content.contains("localhost"),
|
||||
".mcp.json should reference localhost"
|
||||
);
|
||||
assert!(
|
||||
content.contains("huskies"),
|
||||
".mcp.json should name the huskies server"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -976,7 +982,10 @@ mod tests {
|
||||
fs::write(dir.path().join("go.mod"), "module example.com/app\n").unwrap();
|
||||
|
||||
let toml = detect_components_toml(dir.path());
|
||||
assert!(!toml.contains("cargo"), "go project must not contain cargo commands");
|
||||
assert!(
|
||||
!toml.contains("cargo"),
|
||||
"go project must not contain cargo commands"
|
||||
);
|
||||
assert!(toml.contains("go build"), "go project must use Go tooling");
|
||||
}
|
||||
|
||||
@@ -986,8 +995,14 @@ mod tests {
|
||||
fs::write(dir.path().join("package.json"), "{}").unwrap();
|
||||
|
||||
let toml = detect_components_toml(dir.path());
|
||||
assert!(!toml.contains("cargo"), "node project must not contain cargo commands");
|
||||
assert!(toml.contains("npm install"), "node project must use npm tooling");
|
||||
assert!(
|
||||
!toml.contains("cargo"),
|
||||
"node project must not contain cargo commands"
|
||||
);
|
||||
assert!(
|
||||
toml.contains("npm install"),
|
||||
"node project must use npm tooling"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -995,9 +1010,15 @@ mod tests {
|
||||
let dir = tempdir().unwrap();
|
||||
|
||||
let toml = detect_components_toml(dir.path());
|
||||
assert!(!toml.contains("cargo"), "unknown stack must not contain cargo commands");
|
||||
assert!(
|
||||
!toml.contains("cargo"),
|
||||
"unknown stack must not contain cargo commands"
|
||||
);
|
||||
// setup list must be empty
|
||||
assert!(toml.contains("setup = []"), "unknown stack must have empty setup list");
|
||||
assert!(
|
||||
toml.contains("setup = []"),
|
||||
"unknown stack must have empty setup list"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1047,7 +1068,10 @@ mod tests {
|
||||
fs::write(dir.path().join("Cargo.toml"), "[package]\nname = \"x\"\n").unwrap();
|
||||
|
||||
let script = detect_script_test(dir.path());
|
||||
assert!(script.contains("cargo test"), "Rust project should run cargo test");
|
||||
assert!(
|
||||
script.contains("cargo test"),
|
||||
"Rust project should run cargo test"
|
||||
);
|
||||
assert!(!script.contains("No tests configured"));
|
||||
}
|
||||
|
||||
@@ -1057,7 +1081,10 @@ mod tests {
|
||||
fs::write(dir.path().join("package.json"), "{}").unwrap();
|
||||
|
||||
let script = detect_script_test(dir.path());
|
||||
assert!(script.contains("npm test"), "Node project without pnpm-lock should run npm test");
|
||||
assert!(
|
||||
script.contains("npm test"),
|
||||
"Node project without pnpm-lock should run npm test"
|
||||
);
|
||||
assert!(!script.contains("No tests configured"));
|
||||
}
|
||||
|
||||
@@ -1068,18 +1095,31 @@ mod tests {
|
||||
fs::write(dir.path().join("pnpm-lock.yaml"), "").unwrap();
|
||||
|
||||
let script = detect_script_test(dir.path());
|
||||
assert!(script.contains("pnpm test"), "Node project with pnpm-lock should run pnpm test");
|
||||
assert!(
|
||||
script.contains("pnpm test"),
|
||||
"Node project with pnpm-lock should run pnpm test"
|
||||
);
|
||||
// "pnpm test" is a substring of itself; verify there's no bare "npm test" line
|
||||
assert!(!script.lines().any(|l| l.trim() == "npm test"), "should not use npm when pnpm-lock.yaml is present");
|
||||
assert!(
|
||||
!script.lines().any(|l| l.trim() == "npm test"),
|
||||
"should not use npm when pnpm-lock.yaml is present"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn detect_script_test_pyproject_toml_adds_pytest() {
|
||||
let dir = tempdir().unwrap();
|
||||
fs::write(dir.path().join("pyproject.toml"), "[project]\nname = \"x\"\n").unwrap();
|
||||
fs::write(
|
||||
dir.path().join("pyproject.toml"),
|
||||
"[project]\nname = \"x\"\n",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let script = detect_script_test(dir.path());
|
||||
assert!(script.contains("pytest"), "Python project should run pytest");
|
||||
assert!(
|
||||
script.contains("pytest"),
|
||||
"Python project should run pytest"
|
||||
);
|
||||
assert!(!script.contains("No tests configured"));
|
||||
}
|
||||
|
||||
@@ -1089,7 +1129,10 @@ mod tests {
|
||||
fs::write(dir.path().join("requirements.txt"), "flask\n").unwrap();
|
||||
|
||||
let script = detect_script_test(dir.path());
|
||||
assert!(script.contains("pytest"), "Python project (requirements.txt) should run pytest");
|
||||
assert!(
|
||||
script.contains("pytest"),
|
||||
"Python project (requirements.txt) should run pytest"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1098,7 +1141,10 @@ mod tests {
|
||||
fs::write(dir.path().join("go.mod"), "module example.com/app\n").unwrap();
|
||||
|
||||
let script = detect_script_test(dir.path());
|
||||
assert!(script.contains("go test ./..."), "Go project should run go test ./...");
|
||||
assert!(
|
||||
script.contains("go test ./..."),
|
||||
"Go project should run go test ./..."
|
||||
);
|
||||
assert!(!script.contains("No tests configured"));
|
||||
}
|
||||
|
||||
@@ -1109,8 +1155,14 @@ mod tests {
|
||||
fs::write(dir.path().join("package.json"), "{}").unwrap();
|
||||
|
||||
let script = detect_script_test(dir.path());
|
||||
assert!(script.contains("go test ./..."), "multi-stack should include Go test command");
|
||||
assert!(script.contains("npm test"), "multi-stack should include Node test command");
|
||||
assert!(
|
||||
script.contains("go test ./..."),
|
||||
"multi-stack should include Go test command"
|
||||
);
|
||||
assert!(
|
||||
script.contains("npm test"),
|
||||
"multi-stack should include Node test command"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1128,13 +1180,23 @@ mod tests {
|
||||
#[test]
|
||||
fn scaffold_script_test_contains_detected_commands_for_rust() {
|
||||
let dir = tempdir().unwrap();
|
||||
fs::write(dir.path().join("Cargo.toml"), "[package]\nname = \"myapp\"\n").unwrap();
|
||||
fs::write(
|
||||
dir.path().join("Cargo.toml"),
|
||||
"[package]\nname = \"myapp\"\n",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
scaffold_story_kit(dir.path(), 3001).unwrap();
|
||||
|
||||
let content = fs::read_to_string(dir.path().join("script/test")).unwrap();
|
||||
assert!(content.contains("cargo test"), "Rust project scaffold should set cargo test in script/test");
|
||||
assert!(!content.contains("No tests configured"), "should not use stub when stack is detected");
|
||||
assert!(
|
||||
content.contains("cargo test"),
|
||||
"Rust project scaffold should set cargo test in script/test"
|
||||
);
|
||||
assert!(
|
||||
!content.contains("No tests configured"),
|
||||
"should not use stub when stack is detected"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1143,7 +1205,10 @@ mod tests {
|
||||
scaffold_story_kit(dir.path(), 3001).unwrap();
|
||||
|
||||
let content = fs::read_to_string(dir.path().join("script/test")).unwrap();
|
||||
assert!(content.contains("No tests configured"), "unknown stack should use the generic stub");
|
||||
assert!(
|
||||
content.contains("No tests configured"),
|
||||
"unknown stack should use the generic stub"
|
||||
);
|
||||
}
|
||||
|
||||
// --- generate_project_toml ---
|
||||
|
||||
@@ -4,7 +4,7 @@ pub mod onboarding;
|
||||
pub mod search;
|
||||
pub mod shell;
|
||||
pub mod story_metadata;
|
||||
pub mod watcher;
|
||||
pub mod wizard;
|
||||
#[cfg(test)]
|
||||
pub(crate) mod test_helpers;
|
||||
pub mod watcher;
|
||||
pub mod wizard;
|
||||
|
||||
@@ -159,7 +159,9 @@ mod tests {
|
||||
let state = SessionState::default();
|
||||
*state.project_root.lock().unwrap() = Some(dir.path().to_path_buf());
|
||||
|
||||
let results = search_files("target_text".to_string(), &state).await.unwrap();
|
||||
let results = search_files("target_text".to_string(), &state)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(results.len(), 1);
|
||||
assert_eq!(results[0].path, "found.txt");
|
||||
|
||||
+4
-13
@@ -75,12 +75,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn exec_shell_impl_runs_allowed_command() {
|
||||
let dir = tempdir().unwrap();
|
||||
let result = exec_shell_impl(
|
||||
"ls".to_string(),
|
||||
Vec::new(),
|
||||
dir.path().to_path_buf(),
|
||||
)
|
||||
.await;
|
||||
let result = exec_shell_impl("ls".to_string(), Vec::new(), dir.path().to_path_buf()).await;
|
||||
|
||||
assert!(result.is_ok());
|
||||
let output = result.unwrap();
|
||||
@@ -92,13 +87,9 @@ mod tests {
|
||||
let dir = tempdir().unwrap();
|
||||
std::fs::write(dir.path().join("hello.txt"), "").unwrap();
|
||||
|
||||
let result = exec_shell_impl(
|
||||
"ls".to_string(),
|
||||
Vec::new(),
|
||||
dir.path().to_path_buf(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let result = exec_shell_impl("ls".to_string(), Vec::new(), dir.path().to_path_buf())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert!(result.stdout.contains("hello.txt"));
|
||||
}
|
||||
|
||||
@@ -142,7 +142,10 @@ pub fn write_merge_failure(path: &Path, reason: &str) -> Result<(), String> {
|
||||
fs::read_to_string(path).map_err(|e| format!("Failed to read story file: {e}"))?;
|
||||
|
||||
// Produce a YAML-safe inline quoted string: collapse newlines, escape inner quotes.
|
||||
let escaped = reason.replace('"', "\\\"").replace('\n', " ").replace('\r', "");
|
||||
let escaped = reason
|
||||
.replace('"', "\\\"")
|
||||
.replace('\n', " ")
|
||||
.replace('\r', "");
|
||||
let yaml_value = format!("\"{escaped}\"");
|
||||
|
||||
let updated = set_front_matter_field(&contents, "merge_failure", &yaml_value);
|
||||
@@ -288,7 +291,10 @@ pub fn check_unmet_deps(project_root: &Path, stage_dir: &str, story_id: &str) ->
|
||||
Ok(c) => c,
|
||||
Err(_) => return Vec::new(),
|
||||
};
|
||||
let deps = match parse_front_matter(&contents).ok().and_then(|m| m.depends_on) {
|
||||
let deps = match parse_front_matter(&contents)
|
||||
.ok()
|
||||
.and_then(|m| m.depends_on)
|
||||
{
|
||||
Some(d) => d,
|
||||
None => return Vec::new(),
|
||||
};
|
||||
@@ -333,7 +339,10 @@ fn dep_is_done(project_root: &Path, dep_number: u32) -> bool {
|
||||
fn dep_is_archived(project_root: &Path, dep_number: u32) -> bool {
|
||||
let prefix = format!("{dep_number}_");
|
||||
let exact = dep_number.to_string();
|
||||
let dir = project_root.join(".huskies").join("work").join("6_archived");
|
||||
let dir = project_root
|
||||
.join(".huskies")
|
||||
.join("work")
|
||||
.join("6_archived");
|
||||
if let Ok(entries) = fs::read_dir(&dir) {
|
||||
for entry in entries.flatten() {
|
||||
let path = entry.path();
|
||||
@@ -365,7 +374,10 @@ pub fn check_archived_deps(project_root: &Path, stage_dir: &str, story_id: &str)
|
||||
Ok(c) => c,
|
||||
Err(_) => return Vec::new(),
|
||||
};
|
||||
let deps = match parse_front_matter(&contents).ok().and_then(|m| m.depends_on) {
|
||||
let deps = match parse_front_matter(&contents)
|
||||
.ok()
|
||||
.and_then(|m| m.depends_on)
|
||||
{
|
||||
Some(d) => d,
|
||||
None => return Vec::new(),
|
||||
};
|
||||
@@ -434,7 +446,10 @@ pub fn write_blocked_in_content(contents: &str) -> String {
|
||||
|
||||
/// Write or update `merge_failure` in story content (pure function).
|
||||
pub fn write_merge_failure_in_content(contents: &str, reason: &str) -> String {
|
||||
let escaped = reason.replace('"', "\\\"").replace('\n', " ").replace('\r', "");
|
||||
let escaped = reason
|
||||
.replace('"', "\\\"")
|
||||
.replace('\n', " ")
|
||||
.replace('\r', "");
|
||||
let yaml_value = format!("\"{escaped}\"");
|
||||
set_front_matter_field(contents, "merge_failure", &yaml_value)
|
||||
}
|
||||
@@ -465,9 +480,7 @@ pub fn parse_unchecked_todos(contents: &str) -> Vec<String> {
|
||||
.lines()
|
||||
.filter_map(|line| {
|
||||
let trimmed = line.trim();
|
||||
trimmed
|
||||
.strip_prefix("- [ ] ")
|
||||
.map(|text| text.to_string())
|
||||
trimmed.strip_prefix("- [ ] ").map(|text| text.to_string())
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
@@ -486,7 +499,10 @@ workflow: tdd
|
||||
"#;
|
||||
|
||||
let meta = parse_front_matter(input).expect("front matter");
|
||||
assert_eq!(meta.name.as_deref(), Some("Establish the TDD Workflow and Gates"));
|
||||
assert_eq!(
|
||||
meta.name.as_deref(),
|
||||
Some("Establish the TDD Workflow and Gates")
|
||||
);
|
||||
assert_eq!(meta.coverage_baseline, None);
|
||||
}
|
||||
|
||||
@@ -566,7 +582,11 @@ workflow: tdd
|
||||
fn clear_front_matter_field_updates_file() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let path = tmp.path().join("story.md");
|
||||
std::fs::write(&path, "---\nname: Test\nmerge_failure: \"bad\"\n---\n# Story\n").unwrap();
|
||||
std::fs::write(
|
||||
&path,
|
||||
"---\nname: Test\nmerge_failure: \"bad\"\n---\n# Story\n",
|
||||
)
|
||||
.unwrap();
|
||||
clear_front_matter_field(&path, "merge_failure").unwrap();
|
||||
let contents = std::fs::read_to_string(&path).unwrap();
|
||||
assert!(!contents.contains("merge_failure"));
|
||||
@@ -854,5 +874,4 @@ workflow: tdd
|
||||
// 99 doesn't exist anywhere.
|
||||
assert!(!dep_is_archived(tmp.path(), 99));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+13
-14
@@ -301,10 +301,7 @@ fn flush_pending(
|
||||
pending
|
||||
.iter()
|
||||
.filter(|(path, _)| !path.exists())
|
||||
.find(|(path, _)| {
|
||||
path.file_stem()
|
||||
.and_then(|s| s.to_str()) == Some(item_id.as_str())
|
||||
})
|
||||
.find(|(path, _)| path.file_stem().and_then(|s| s.to_str()) == Some(item_id.as_str()))
|
||||
.map(|(_, stage)| stage.clone())
|
||||
} else {
|
||||
None
|
||||
@@ -327,7 +324,7 @@ fn flush_pending(
|
||||
/// All state is read from and written to CRDT — no filesystem access.
|
||||
/// Worktree pruning is handled separately by the CRDT event subscriber.
|
||||
pub(crate) fn sweep_done_to_archived(done_retention: Duration) {
|
||||
use crate::pipeline_state::{PipelineEvent, Stage, stage_dir_name, transition, read_all_typed};
|
||||
use crate::pipeline_state::{PipelineEvent, Stage, read_all_typed, stage_dir_name, transition};
|
||||
|
||||
for item in read_all_typed() {
|
||||
if let Stage::Done { merged_at, .. } = &item.stage {
|
||||
@@ -374,10 +371,7 @@ pub(crate) fn sweep_done_to_archived(done_retention: Duration) {
|
||||
/// `git_root` — project root (passed to `git` commands and config loading).
|
||||
/// `event_tx` — broadcast sender for `ConfigChanged` events.
|
||||
/// `watcher_config` — initial sweep configuration loaded from `project.toml`.
|
||||
pub fn start_watcher(
|
||||
git_root: PathBuf,
|
||||
event_tx: broadcast::Sender<WatcherEvent>,
|
||||
) {
|
||||
pub fn start_watcher(git_root: PathBuf, event_tx: broadcast::Sender<WatcherEvent>) {
|
||||
std::thread::spawn(move || {
|
||||
let (notify_tx, notify_rx) = mpsc::channel::<notify::Result<notify::Event>>();
|
||||
|
||||
@@ -1080,7 +1074,9 @@ mod tests {
|
||||
|
||||
// Verify the item was moved to 6_archived in the CRDT.
|
||||
let items = crate::pipeline_state::read_all_typed();
|
||||
let item = items.iter().find(|i| i.story_id.0 == "9880_story_sweep_old");
|
||||
let item = items
|
||||
.iter()
|
||||
.find(|i| i.story_id.0 == "9880_story_sweep_old");
|
||||
assert!(
|
||||
item.is_some_and(|i| matches!(i.stage, crate::pipeline_state::Stage::Archived { .. })),
|
||||
"item should be archived after sweep"
|
||||
@@ -1100,7 +1096,9 @@ mod tests {
|
||||
sweep_done_to_archived(Duration::from_secs(999_999));
|
||||
|
||||
let items = crate::pipeline_state::read_all_typed();
|
||||
let item = items.iter().find(|i| i.story_id.0 == "9881_story_sweep_new");
|
||||
let item = items
|
||||
.iter()
|
||||
.find(|i| i.story_id.0 == "9881_story_sweep_new");
|
||||
assert!(
|
||||
item.is_some_and(|i| matches!(i.stage, crate::pipeline_state::Stage::Done { .. })),
|
||||
"item should remain in Done with long retention"
|
||||
@@ -1120,7 +1118,9 @@ mod tests {
|
||||
sweep_done_to_archived(Duration::ZERO);
|
||||
|
||||
let items = crate::pipeline_state::read_all_typed();
|
||||
let item = items.iter().find(|i| i.story_id.0 == "9882_story_sweep_custom");
|
||||
let item = items
|
||||
.iter()
|
||||
.find(|i| i.story_id.0 == "9882_story_sweep_custom");
|
||||
assert!(
|
||||
item.is_some_and(|i| matches!(i.stage, crate::pipeline_state::Stage::Archived { .. })),
|
||||
"item should be archived with zero retention"
|
||||
@@ -1172,8 +1172,7 @@ mod tests {
|
||||
fn sweep_keeps_item_newer_than_retention() {
|
||||
crate::db::ensure_content_store();
|
||||
|
||||
let one_second_ago =
|
||||
(chrono::Utc::now() - chrono::Duration::seconds(1)).timestamp() as f64;
|
||||
let one_second_ago = (chrono::Utc::now() - chrono::Duration::seconds(1)).timestamp() as f64;
|
||||
|
||||
crate::crdt_state::write_item(
|
||||
"9884_story_sweep_recent",
|
||||
|
||||
@@ -380,10 +380,7 @@ mod tests {
|
||||
Some("generated content".to_string()),
|
||||
);
|
||||
assert_eq!(state.steps[1].status, StepStatus::AwaitingConfirmation);
|
||||
assert_eq!(
|
||||
state.steps[1].content.as_deref(),
|
||||
Some("generated content")
|
||||
);
|
||||
assert_eq!(state.steps[1].content.as_deref(), Some("generated content"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user