Skip to main content

speccoder_runtime/format/speckit/
bench.rs

1//! The Spec Kit project `speccoder bench import` writes around an issue.
2
3use std::fs;
4use std::path::{Path, PathBuf};
5
6use crate::bench::Issue;
7
8/// Writes a Spec Kit project into `project`: the issue as the user story of
9/// `spec.md`, a plan naming the test command, and one task to resolve it.
10pub fn scaffold(
11    project: &Path,
12    slug: &str,
13    issue: &Issue<'_>,
14    test_cmd: &[String],
15) -> Result<(), String> {
16    let feature = format!("001-{slug}");
17    let fdir = project.join("specs").join(&feature);
18    fs::create_dir_all(&fdir).map_err(|e| e.to_string())?;
19    fs::create_dir_all(project.join(".specify/memory")).map_err(|e| e.to_string())?;
20    let write = |p: PathBuf, text: String| fs::write(p, text).map_err(|e| e.to_string());
21    write(
22        project.join(".specify/init-options.json"),
23        "{\"speckit_version\": \"1.2.3\", \"integration\": \"claude\", \"script\": \"sh\"}\n"
24            .to_owned(),
25    )?;
26    write(
27        project.join(".specify/memory/constitution.md"),
28        "# Constitution\n\n### I. Minimal\nChange only what the issue needs; keep existing behaviour and tests.\n\n### II. Honest\nA requirement that cannot be met as written is reported, never worked around.\n".to_owned(),
29    )?;
30    let first_line = issue
31        .statement
32        .lines()
33        .find(|l| !l.trim().is_empty())
34        .unwrap_or("Resolve the issue");
35    let title: String = first_line
36        .trim()
37        .trim_start_matches('#')
38        .trim()
39        .chars()
40        .take(70)
41        .collect();
42    write(
43        fdir.join("spec.md"),
44        format!(
45            "# Feature Specification: {}\n\n## User Scenarios & Testing\n\n### User Story 1 - {title} (Priority: P1)\n\nAn issue reported against `{}`:\n\n{}\n\n## Requirements\n\n- **FR-001**: The behaviour the issue asks for works.\n- **FR-002**: Existing behaviour and tests are unchanged.\n",
46            issue.id,
47            issue.repo,
48            issue.statement.trim()
49        ),
50    )?;
51    write(
52        fdir.join("plan.md"),
53        format!(
54            "# Implementation Plan: {}\n\nExisting repository `{}` at `{}`. Find the code the issue concerns and change it there; do not rewrite unrelated code. Tests: `{}`.\n",
55            issue.id,
56            issue.repo,
57            issue.base_commit,
58            test_cmd.join(" ")
59        ),
60    )?;
61    write(
62        fdir.join("tasks.md"),
63        format!(
64            "# Tasks: {}\n\n## Phase 1: User Story 1 - {title} (Priority: P1)\n\n- [ ] T001 [US1] Resolve the issue described in spec.md, with a test that fails before the change and passes after\n",
65            issue.id
66        ),
67    )?;
68    Ok(())
69}