story-kit: merge 217_story_scaffold_generates_claude_md

This commit is contained in:
Dave
2026-02-26 18:29:32 +00:00
parent 0135d74bbc
commit 733b92337e
2 changed files with 87 additions and 1 deletions

View File

@@ -52,6 +52,14 @@ TODO: List approved libraries and their purpose.\n";
const STORY_KIT_SCRIPT_TEST: &str = "#!/usr/bin/env bash\nset -euo pipefail\n\n# Add your project's test commands here.\n# Story Kit agents invoke this script as the canonical test runner.\n# Exit 0 on success, non-zero on failure.\necho \"No tests configured\"\n";
const STORY_KIT_CLAUDE_MD: &str = "<!-- story-kit:scaffold-template -->\n\
Never chain shell commands with `&&`, `||`, or `;` in a single Bash call. \
The permission system validates the entire command string, and chained commands \
won't match allow rules like `Bash(git *)`. Use separate Bash calls instead — \
parallel calls work fine.\n\
\n\
Read .story_kit/README.md to see our dev process.\n";
const DEFAULT_PROJECT_TOML: &str = r#"[[agent]]
name = "coder-1"
stage = "coder"
@@ -253,6 +261,7 @@ fn scaffold_story_kit(root: &Path) -> Result<(), String> {
write_file_if_missing(&specs_root.join("00_CONTEXT.md"), STORY_KIT_CONTEXT)?;
write_file_if_missing(&tech_root.join("STACK.md"), STORY_KIT_STACK)?;
write_script_if_missing(&script_root.join("test"), STORY_KIT_SCRIPT_TEST)?;
write_file_if_missing(&root.join("CLAUDE.md"), STORY_KIT_CLAUDE_MD)?;
append_gitignore_entries(root)?;
@@ -268,7 +277,7 @@ fn scaffold_story_kit(root: &Path) -> Result<(), String> {
}
let add_output = std::process::Command::new("git")
.args(["add", ".story_kit", "script", ".gitignore"])
.args(["add", ".story_kit", "script", ".gitignore", "CLAUDE.md"])
.current_dir(root)
.output()
.map_err(|e| format!("Failed to run git add: {}", e))?;
@@ -1074,6 +1083,46 @@ mod tests {
assert!(content.contains("store.json"));
}
// --- CLAUDE.md scaffold ---
#[test]
fn scaffold_creates_claude_md_at_project_root() {
let dir = tempdir().unwrap();
scaffold_story_kit(dir.path()).unwrap();
let claude_md = dir.path().join("CLAUDE.md");
assert!(claude_md.exists(), "CLAUDE.md should be created at project root");
let content = fs::read_to_string(&claude_md).unwrap();
assert!(
content.contains("<!-- story-kit:scaffold-template -->"),
"CLAUDE.md should contain the scaffold sentinel"
);
assert!(
content.contains("Read .story_kit/README.md"),
"CLAUDE.md should include directive to read .story_kit/README.md"
);
assert!(
content.contains("Never chain shell commands"),
"CLAUDE.md should include command chaining rule"
);
}
#[test]
fn scaffold_does_not_overwrite_existing_claude_md() {
let dir = tempdir().unwrap();
let claude_md = dir.path().join("CLAUDE.md");
fs::write(&claude_md, "custom CLAUDE.md content").unwrap();
scaffold_story_kit(dir.path()).unwrap();
assert_eq!(
fs::read_to_string(&claude_md).unwrap(),
"custom CLAUDE.md content",
"scaffold should not overwrite an existing CLAUDE.md"
);
}
// --- open_project scaffolding ---
#[tokio::test]