story-kit: merge 217_story_scaffold_generates_claude_md
This commit is contained in:
@@ -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_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]]
|
const DEFAULT_PROJECT_TOML: &str = r#"[[agent]]
|
||||||
name = "coder-1"
|
name = "coder-1"
|
||||||
stage = "coder"
|
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(&specs_root.join("00_CONTEXT.md"), STORY_KIT_CONTEXT)?;
|
||||||
write_file_if_missing(&tech_root.join("STACK.md"), STORY_KIT_STACK)?;
|
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_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)?;
|
append_gitignore_entries(root)?;
|
||||||
|
|
||||||
@@ -268,7 +277,7 @@ fn scaffold_story_kit(root: &Path) -> Result<(), String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let add_output = std::process::Command::new("git")
|
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)
|
.current_dir(root)
|
||||||
.output()
|
.output()
|
||||||
.map_err(|e| format!("Failed to run git add: {}", e))?;
|
.map_err(|e| format!("Failed to run git add: {}", e))?;
|
||||||
@@ -1074,6 +1083,46 @@ mod tests {
|
|||||||
assert!(content.contains("store.json"));
|
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 ---
|
// --- open_project scaffolding ---
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|||||||
@@ -254,6 +254,43 @@ mod tests {
|
|||||||
assert!(!status.needs_project_toml);
|
assert!(!status.needs_project_toml);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── CLAUDE.md is not an onboarding step ──────────────────────
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn onboarding_status_does_not_check_claude_md() {
|
||||||
|
let dir = TempDir::new().unwrap();
|
||||||
|
let root = setup_project(&dir);
|
||||||
|
|
||||||
|
// Write real content for the required onboarding files
|
||||||
|
fs::write(
|
||||||
|
root.join(".story_kit/specs/00_CONTEXT.md"),
|
||||||
|
"# My Project\n\nReal project context.",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
fs::write(
|
||||||
|
root.join(".story_kit/specs/tech/STACK.md"),
|
||||||
|
"# My Stack\n\nReal stack content.",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// CLAUDE.md is absent — should NOT affect onboarding result
|
||||||
|
assert!(!root.join("CLAUDE.md").exists());
|
||||||
|
|
||||||
|
let status = check_onboarding_status(&root);
|
||||||
|
assert!(
|
||||||
|
!status.needs_context,
|
||||||
|
"needs_context should be false with real content"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
!status.needs_stack,
|
||||||
|
"needs_stack should be false with real content"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
!status.needs_onboarding(),
|
||||||
|
"needs_onboarding() should be false regardless of CLAUDE.md presence"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// ── partial onboarding ────────────────────────────────────────
|
// ── partial onboarding ────────────────────────────────────────
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
Reference in New Issue
Block a user