rename .story_kit directory to .storkit and update all references

Renames the config directory and updates 514 references across 42 Rust
source files, plus CLAUDE.md, .gitignore, Makefile, script/release,
and .mcp.json files. All 1205 tests pass.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dave
2026-03-20 11:34:53 +00:00
parent 375277f86e
commit 9581e5d51a
406 changed files with 531 additions and 530 deletions

View File

@@ -18,12 +18,12 @@ pub(super) fn item_type_from_id(item_id: &str) -> &'static str {
/// Return the source directory path for a work item (always work/1_backlog/).
fn item_source_dir(project_root: &Path, _item_id: &str) -> PathBuf {
project_root.join(".story_kit").join("work").join("1_backlog")
project_root.join(".storkit").join("work").join("1_backlog")
}
/// Return the done directory path for a work item (always work/5_done/).
fn item_archive_dir(project_root: &Path, _item_id: &str) -> PathBuf {
project_root.join(".story_kit").join("work").join("5_done")
project_root.join(".storkit").join("work").join("5_done")
}
/// Move a work item (story, bug, or spike) from `work/1_backlog/` to `work/2_current/`.
@@ -31,7 +31,7 @@ fn item_archive_dir(project_root: &Path, _item_id: &str) -> PathBuf {
/// Idempotent: if the item is already in `2_current/`, returns Ok without committing.
/// If the item is not found in `1_backlog/`, logs a warning and returns Ok.
pub fn move_story_to_current(project_root: &Path, story_id: &str) -> Result<(), String> {
let sk = project_root.join(".story_kit").join("work");
let sk = project_root.join(".storkit").join("work");
let current_dir = sk.join("2_current");
let current_path = current_dir.join(format!("{story_id}.md"));
@@ -103,7 +103,7 @@ pub fn feature_branch_has_unmerged_changes(project_root: &Path, story_id: &str)
/// * If the story is already in `5_done/` or `6_archived/`, this is a no-op (idempotent).
/// * If the story is not found in `2_current/`, `4_merge/`, `5_done/`, or `6_archived/`, an error is returned.
pub fn move_story_to_archived(project_root: &Path, story_id: &str) -> Result<(), String> {
let sk = project_root.join(".story_kit").join("work");
let sk = project_root.join(".storkit").join("work");
let current_path = sk.join("2_current").join(format!("{story_id}.md"));
let merge_path = sk.join("4_merge").join(format!("{story_id}.md"));
let done_dir = sk.join("5_done");
@@ -153,7 +153,7 @@ pub fn move_story_to_archived(project_root: &Path, story_id: &str) -> Result<(),
/// This stages a work item as ready for the mergemaster to pick up and merge into master.
/// Idempotent: if already in `4_merge/`, returns Ok without committing.
pub fn move_story_to_merge(project_root: &Path, story_id: &str) -> Result<(), String> {
let sk = project_root.join(".story_kit").join("work");
let sk = project_root.join(".storkit").join("work");
let current_path = sk.join("2_current").join(format!("{story_id}.md"));
let qa_path = sk.join("3_qa").join(format!("{story_id}.md"));
let merge_dir = sk.join("4_merge");
@@ -203,7 +203,7 @@ pub fn move_story_to_merge(project_root: &Path, story_id: &str) -> Result<(), St
/// This stages a work item for QA review before merging to master.
/// Idempotent: if already in `3_qa/`, returns Ok without committing.
pub fn move_story_to_qa(project_root: &Path, story_id: &str) -> Result<(), String> {
let sk = project_root.join(".story_kit").join("work");
let sk = project_root.join(".storkit").join("work");
let current_path = sk.join("2_current").join(format!("{story_id}.md"));
let qa_dir = sk.join("3_qa");
let qa_path = qa_dir.join(format!("{story_id}.md"));
@@ -246,7 +246,7 @@ pub fn reject_story_from_qa(
story_id: &str,
notes: &str,
) -> Result<(), String> {
let sk = project_root.join(".story_kit").join("work");
let sk = project_root.join(".storkit").join("work");
let qa_path = sk.join("3_qa").join(format!("{story_id}.md"));
let current_dir = sk.join("2_current");
let current_path = current_dir.join(format!("{story_id}.md"));
@@ -311,7 +311,7 @@ pub fn move_story_to_stage(
)
})?;
let sk = project_root.join(".story_kit").join("work");
let sk = project_root.join(".storkit").join("work");
let target_dir = sk.join(target_dir_name);
let target_path = target_dir.join(format!("{story_id}.md"));
@@ -362,7 +362,7 @@ pub fn move_story_to_stage(
/// * If the bug is already in `5_done/`, this is a no-op (idempotent).
/// * If the bug is not found anywhere, an error is returned.
pub fn close_bug_to_archive(project_root: &Path, bug_id: &str) -> Result<(), String> {
let sk = project_root.join(".story_kit").join("work");
let sk = project_root.join(".storkit").join("work");
let current_path = sk.join("2_current").join(format!("{bug_id}.md"));
let backlog_path = sk.join("1_backlog").join(format!("{bug_id}.md"));
let archive_dir = item_archive_dir(project_root, bug_id);
@@ -405,8 +405,8 @@ mod tests {
use std::fs;
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let backlog = root.join(".story_kit/work/1_backlog");
let current = root.join(".story_kit/work/2_current");
let backlog = root.join(".storkit/work/1_backlog");
let current = root.join(".storkit/work/2_current");
fs::create_dir_all(&backlog).unwrap();
fs::create_dir_all(&current).unwrap();
fs::write(backlog.join("10_story_foo.md"), "test").unwrap();
@@ -422,7 +422,7 @@ mod tests {
use std::fs;
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let current = root.join(".story_kit/work/2_current");
let current = root.join(".storkit/work/2_current");
fs::create_dir_all(&current).unwrap();
fs::write(current.join("11_story_foo.md"), "test").unwrap();
@@ -441,8 +441,8 @@ mod tests {
use std::fs;
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let backlog = root.join(".story_kit/work/1_backlog");
let current = root.join(".story_kit/work/2_current");
let backlog = root.join(".storkit/work/1_backlog");
let current = root.join(".storkit/work/2_current");
fs::create_dir_all(&backlog).unwrap();
fs::create_dir_all(&current).unwrap();
fs::write(backlog.join("1_bug_test.md"), "# Bug 1\n").unwrap();
@@ -460,14 +460,14 @@ mod tests {
use std::fs;
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let current = root.join(".story_kit/work/2_current");
let current = root.join(".storkit/work/2_current");
fs::create_dir_all(&current).unwrap();
fs::write(current.join("2_bug_test.md"), "# Bug 2\n").unwrap();
close_bug_to_archive(root, "2_bug_test").unwrap();
assert!(!current.join("2_bug_test.md").exists());
assert!(root.join(".story_kit/work/5_done/2_bug_test.md").exists());
assert!(root.join(".storkit/work/5_done/2_bug_test.md").exists());
}
#[test]
@@ -475,14 +475,14 @@ mod tests {
use std::fs;
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let backlog = root.join(".story_kit/work/1_backlog");
let backlog = root.join(".storkit/work/1_backlog");
fs::create_dir_all(&backlog).unwrap();
fs::write(backlog.join("3_bug_test.md"), "# Bug 3\n").unwrap();
close_bug_to_archive(root, "3_bug_test").unwrap();
assert!(!backlog.join("3_bug_test.md").exists());
assert!(root.join(".story_kit/work/5_done/3_bug_test.md").exists());
assert!(root.join(".storkit/work/5_done/3_bug_test.md").exists());
}
// ── item_type_from_id tests ────────────────────────────────────────────────
@@ -502,14 +502,14 @@ mod tests {
use std::fs;
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let current = root.join(".story_kit/work/2_current");
let current = root.join(".storkit/work/2_current");
fs::create_dir_all(&current).unwrap();
fs::write(current.join("20_story_foo.md"), "test").unwrap();
move_story_to_merge(root, "20_story_foo").unwrap();
assert!(!current.join("20_story_foo.md").exists());
assert!(root.join(".story_kit/work/4_merge/20_story_foo.md").exists());
assert!(root.join(".storkit/work/4_merge/20_story_foo.md").exists());
}
#[test]
@@ -517,14 +517,14 @@ mod tests {
use std::fs;
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let qa_dir = root.join(".story_kit/work/3_qa");
let qa_dir = root.join(".storkit/work/3_qa");
fs::create_dir_all(&qa_dir).unwrap();
fs::write(qa_dir.join("40_story_test.md"), "test").unwrap();
move_story_to_merge(root, "40_story_test").unwrap();
assert!(!qa_dir.join("40_story_test.md").exists());
assert!(root.join(".story_kit/work/4_merge/40_story_test.md").exists());
assert!(root.join(".storkit/work/4_merge/40_story_test.md").exists());
}
#[test]
@@ -532,7 +532,7 @@ mod tests {
use std::fs;
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let merge_dir = root.join(".story_kit/work/4_merge");
let merge_dir = root.join(".storkit/work/4_merge");
fs::create_dir_all(&merge_dir).unwrap();
fs::write(merge_dir.join("21_story_test.md"), "test").unwrap();
@@ -554,14 +554,14 @@ mod tests {
use std::fs;
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let current = root.join(".story_kit/work/2_current");
let current = root.join(".storkit/work/2_current");
fs::create_dir_all(&current).unwrap();
fs::write(current.join("30_story_qa.md"), "test").unwrap();
move_story_to_qa(root, "30_story_qa").unwrap();
assert!(!current.join("30_story_qa.md").exists());
assert!(root.join(".story_kit/work/3_qa/30_story_qa.md").exists());
assert!(root.join(".storkit/work/3_qa/30_story_qa.md").exists());
}
#[test]
@@ -569,7 +569,7 @@ mod tests {
use std::fs;
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let qa_dir = root.join(".story_kit/work/3_qa");
let qa_dir = root.join(".storkit/work/3_qa");
fs::create_dir_all(&qa_dir).unwrap();
fs::write(qa_dir.join("31_story_test.md"), "test").unwrap();
@@ -591,14 +591,14 @@ mod tests {
use std::fs;
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let merge_dir = root.join(".story_kit/work/4_merge");
let merge_dir = root.join(".storkit/work/4_merge");
fs::create_dir_all(&merge_dir).unwrap();
fs::write(merge_dir.join("22_story_test.md"), "test").unwrap();
move_story_to_archived(root, "22_story_test").unwrap();
assert!(!merge_dir.join("22_story_test.md").exists());
assert!(root.join(".story_kit/work/5_done/22_story_test.md").exists());
assert!(root.join(".storkit/work/5_done/22_story_test.md").exists());
}
#[test]
@@ -696,8 +696,8 @@ mod tests {
use std::fs;
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let qa_dir = root.join(".story_kit/work/3_qa");
let current_dir = root.join(".story_kit/work/2_current");
let qa_dir = root.join(".storkit/work/3_qa");
let current_dir = root.join(".storkit/work/2_current");
fs::create_dir_all(&qa_dir).unwrap();
fs::create_dir_all(&current_dir).unwrap();
fs::write(
@@ -728,7 +728,7 @@ mod tests {
use std::fs;
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let current_dir = root.join(".story_kit/work/2_current");
let current_dir = root.join(".storkit/work/2_current");
fs::create_dir_all(&current_dir).unwrap();
fs::write(current_dir.join("51_story_test.md"), "---\nname: Test\n---\n# Story\n").unwrap();
@@ -743,8 +743,8 @@ mod tests {
use std::fs;
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let backlog = root.join(".story_kit/work/1_backlog");
let current = root.join(".story_kit/work/2_current");
let backlog = root.join(".storkit/work/1_backlog");
let current = root.join(".storkit/work/2_current");
fs::create_dir_all(&backlog).unwrap();
fs::create_dir_all(&current).unwrap();
fs::write(backlog.join("60_story_move.md"), "test").unwrap();
@@ -762,8 +762,8 @@ mod tests {
use std::fs;
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let current = root.join(".story_kit/work/2_current");
let backlog = root.join(".story_kit/work/1_backlog");
let current = root.join(".storkit/work/2_current");
let backlog = root.join(".storkit/work/1_backlog");
fs::create_dir_all(&current).unwrap();
fs::create_dir_all(&backlog).unwrap();
fs::write(current.join("61_story_back.md"), "test").unwrap();
@@ -781,7 +781,7 @@ mod tests {
use std::fs;
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let current = root.join(".story_kit/work/2_current");
let current = root.join(".storkit/work/2_current");
fs::create_dir_all(&current).unwrap();
fs::write(current.join("62_story_idem.md"), "test").unwrap();
@@ -813,8 +813,8 @@ mod tests {
use std::fs;
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let qa_dir = root.join(".story_kit/work/3_qa");
let backlog = root.join(".story_kit/work/1_backlog");
let qa_dir = root.join(".storkit/work/3_qa");
let backlog = root.join(".storkit/work/1_backlog");
fs::create_dir_all(&qa_dir).unwrap();
fs::create_dir_all(&backlog).unwrap();
fs::write(qa_dir.join("63_story_qa.md"), "test").unwrap();

View File

@@ -10,7 +10,7 @@ use super::gates::run_project_tests;
/// Global lock ensuring only one squash-merge runs at a time.
///
/// The merge pipeline uses a shared `.story_kit/merge_workspace` directory and
/// The merge pipeline uses a shared `.storkit/merge_workspace` directory and
/// temporary `merge-queue/{story_id}` branches. If two merges run concurrently,
/// the second call's initial cleanup destroys the first call's branch mid-flight,
/// causing `git cherry-pick merge-queue/…` to fail with "bad revision".
@@ -89,7 +89,7 @@ pub(crate) fn run_squash_merge(
let mut all_output = String::new();
let merge_branch = format!("merge-queue/{story_id}");
let merge_wt_path = project_root
.join(".story_kit")
.join(".storkit")
.join("merge_workspace");
// Ensure we start clean: remove any leftover merge workspace.
@@ -250,7 +250,7 @@ pub(crate) fn run_squash_merge(
}
// ── Bug 226: Verify the commit contains real code changes ─────
// If the merge only brought in .story_kit/ files (pipeline file moves),
// If the merge only brought in .storkit/ files (pipeline file moves),
// there are no actual code changes to land on master. Abort.
{
let diff_check = Command::new("git")
@@ -261,10 +261,10 @@ pub(crate) fn run_squash_merge(
let changed_files = String::from_utf8_lossy(&diff_check.stdout);
let has_code_changes = changed_files
.lines()
.any(|f| !f.starts_with(".story_kit/"));
.any(|f| !f.starts_with(".storkit/"));
if !has_code_changes {
all_output.push_str(
"=== Merge commit contains only .story_kit/ file moves, no code changes ===\n",
"=== Merge commit contains only .storkit/ file moves, no code changes ===\n",
);
cleanup_merge_workspace(project_root, &merge_wt_path, &merge_branch);
return Ok(SquashMergeResult {
@@ -272,7 +272,7 @@ pub(crate) fn run_squash_merge(
had_conflicts,
conflicts_resolved,
conflict_details: Some(
"Feature branch has no code changes outside .story_kit/ — only \
"Feature branch has no code changes outside .storkit/ — only \
pipeline file moves were found."
.to_string(),
),
@@ -960,7 +960,7 @@ after\n";
// Verify no leftover merge workspace directory.
assert!(
!repo.join(".story_kit/merge_workspace").exists(),
!repo.join(".storkit/merge_workspace").exists(),
"merge workspace should be cleaned up"
);
}
@@ -1076,7 +1076,7 @@ after\n";
.current_dir(repo)
.output()
.unwrap();
let sk_dir = repo.join(".story_kit/work/4_merge");
let sk_dir = repo.join(".storkit/work/4_merge");
fs::create_dir_all(&sk_dir).unwrap();
fs::write(
sk_dir.join("diverge_test.md"),
@@ -1135,7 +1135,7 @@ after\n";
"merge-queue branch should be cleaned up, got: {branch_list}"
);
assert!(
!repo.join(".story_kit/merge_workspace").exists(),
!repo.join(".storkit/merge_workspace").exists(),
"merge workspace should be cleaned up"
);
}
@@ -1188,13 +1188,13 @@ after\n";
// Cleanup should still happen.
assert!(
!repo.join(".story_kit/merge_workspace").exists(),
!repo.join(".storkit/merge_workspace").exists(),
"merge workspace should be cleaned up"
);
}
/// Bug 226: Verifies that `run_squash_merge` fails when the feature branch
/// only contains .story_kit/ file moves with no real code changes.
/// only contains .storkit/ file moves with no real code changes.
#[tokio::test]
async fn squash_merge_md_only_changes_fails() {
use std::fs;
@@ -1204,13 +1204,13 @@ after\n";
let repo = tmp.path();
init_git_repo(repo);
// Create a feature branch that only moves a .story_kit/ file.
// Create a feature branch that only moves a .storkit/ file.
Command::new("git")
.args(["checkout", "-b", "feature/story-md_only_test"])
.current_dir(repo)
.output()
.unwrap();
let sk_dir = repo.join(".story_kit/work/2_current");
let sk_dir = repo.join(".storkit/work/2_current");
fs::create_dir_all(&sk_dir).unwrap();
fs::write(
sk_dir.join("md_only_test.md"),
@@ -1236,17 +1236,17 @@ after\n";
let result =
run_squash_merge(repo, "feature/story-md_only_test", "md_only_test").unwrap();
// The squash merge will commit the .story_kit/ file, but should fail because
// there are no code changes outside .story_kit/.
// The squash merge will commit the .storkit/ file, but should fail because
// there are no code changes outside .storkit/.
assert!(
!result.success,
"merge with only .story_kit/ changes must fail: {}",
"merge with only .storkit/ changes must fail: {}",
result.output
);
// Cleanup should still happen.
assert!(
!repo.join(".story_kit/merge_workspace").exists(),
!repo.join(".storkit/merge_workspace").exists(),
"merge workspace should be cleaned up"
);
}
@@ -1359,7 +1359,7 @@ after\n";
"merge-queue branch must be cleaned up"
);
assert!(
!repo.join(".story_kit/merge_workspace").exists(),
!repo.join(".storkit/merge_workspace").exists(),
"merge workspace must be cleaned up"
);
}
@@ -1463,7 +1463,7 @@ after\n";
// Cleanup must still happen.
assert!(
!repo.join(".story_kit/merge_workspace").exists(),
!repo.join(".storkit/merge_workspace").exists(),
"merge workspace must be cleaned up even on gate failure"
);
}
@@ -1503,7 +1503,7 @@ after\n";
.unwrap();
// Simulate a stale merge workspace left from a previous failed merge.
let stale_ws = repo.join(".story_kit/merge_workspace");
let stale_ws = repo.join(".storkit/merge_workspace");
fs::create_dir_all(&stale_ws).unwrap();
fs::write(stale_ws.join("leftover.txt"), "stale").unwrap();
@@ -1524,7 +1524,7 @@ after\n";
// ── story 216: merge worktree uses project.toml component setup ───────────
/// When the project has `[[component]]` entries in `.story_kit/project.toml`,
/// When the project has `[[component]]` entries in `.storkit/project.toml`,
/// `run_squash_merge` must run their setup commands in the merge worktree
/// before quality gates — matching the behaviour of `create_worktree`.
#[cfg(unix)]
@@ -1537,9 +1537,9 @@ after\n";
let repo = tmp.path();
init_git_repo(repo);
// Add a .story_kit/project.toml with a component whose setup writes a
// Add a .storkit/project.toml with a component whose setup writes a
// sentinel file so we can confirm the command ran.
let sk_dir = repo.join(".story_kit");
let sk_dir = repo.join(".storkit");
fs::create_dir_all(&sk_dir).unwrap();
fs::write(
sk_dir.join("project.toml"),
@@ -1612,7 +1612,7 @@ after\n";
let repo = tmp.path();
init_git_repo(repo);
// No .story_kit/project.toml — no component setup.
// No .storkit/project.toml — no component setup.
fs::write(repo.join("file.txt"), "initial").unwrap();
Command::new("git")
.args(["add", "."])

View File

@@ -72,7 +72,7 @@ impl AgentPool {
on feature branch. Writing merge_failure and blocking."
);
let story_path = project_root
.join(".story_kit/work")
.join(".storkit/work")
.join(stage_dir)
.join(format!("{story_id}.md"));
let _ = crate::io::story_metadata::write_merge_failure(
@@ -209,7 +209,7 @@ impl AgentPool {
/// (called immediately after) picks up the right next-stage agents.
///
/// Algorithm:
/// 1. List all worktree directories under `{project_root}/.story_kit/worktrees/`.
/// 1. List all worktree directories under `{project_root}/.storkit/worktrees/`.
/// 2. For each worktree, check whether its feature branch has commits ahead of the
/// base branch (`master` / `main`).
/// 3. If committed work is found AND the story is in `2_current/` or `3_qa/`:
@@ -344,7 +344,7 @@ impl AgentPool {
.unwrap_or_default()
.default_qa_mode();
let story_path = project_root
.join(".story_kit/work/2_current")
.join(".storkit/work/2_current")
.join(format!("{story_id}.md"));
crate::io::story_metadata::resolve_qa_mode(&story_path, default_qa)
}
@@ -395,7 +395,7 @@ impl AgentPool {
});
} else {
let story_path = project_root
.join(".story_kit/work/3_qa")
.join(".storkit/work/3_qa")
.join(format!("{story_id}.md"));
if let Err(e) = crate::io::story_metadata::write_review_hold(&story_path) {
eprintln!(
@@ -451,7 +451,7 @@ impl AgentPool {
true
} else {
let story_path = project_root
.join(".story_kit/work/3_qa")
.join(".storkit/work/3_qa")
.join(format!("{story_id}.md"));
let default_qa = crate::config::ProjectConfig::load(project_root)
.unwrap_or_default()
@@ -465,7 +465,7 @@ impl AgentPool {
if needs_human_review {
let story_path = project_root
.join(".story_kit/work/3_qa")
.join(".storkit/work/3_qa")
.join(format!("{story_id}.md"));
if let Err(e) = crate::io::story_metadata::write_review_hold(&story_path) {
eprintln!(
@@ -567,7 +567,7 @@ fn read_story_front_matter_agent(
) -> Option<String> {
use crate::io::story_metadata::parse_front_matter;
let path = project_root
.join(".story_kit")
.join(".storkit")
.join("work")
.join(stage_dir)
.join(format!("{story_id}.md"));
@@ -579,7 +579,7 @@ fn read_story_front_matter_agent(
fn has_review_hold(project_root: &Path, stage_dir: &str, story_id: &str) -> bool {
use crate::io::story_metadata::parse_front_matter;
let path = project_root
.join(".story_kit")
.join(".storkit")
.join("work")
.join(stage_dir)
.join(format!("{story_id}.md"));
@@ -597,7 +597,7 @@ fn has_review_hold(project_root: &Path, stage_dir: &str, story_id: &str) -> bool
fn is_story_blocked(project_root: &Path, stage_dir: &str, story_id: &str) -> bool {
use crate::io::story_metadata::parse_front_matter;
let path = project_root
.join(".story_kit")
.join(".storkit")
.join("work")
.join(stage_dir)
.join(format!("{story_id}.md"));
@@ -615,7 +615,7 @@ fn is_story_blocked(project_root: &Path, stage_dir: &str, story_id: &str) -> boo
fn has_merge_failure(project_root: &Path, stage_dir: &str, story_id: &str) -> bool {
use crate::io::story_metadata::parse_front_matter;
let path = project_root
.join(".story_kit")
.join(".storkit")
.join("work")
.join(stage_dir)
.join(format!("{story_id}.md"));
@@ -638,7 +638,7 @@ pub(super) fn is_agent_free(agents: &HashMap<String, StoryAgent>, agent_name: &s
}
fn scan_stage_items(project_root: &Path, stage_dir: &str) -> Vec<String> {
let dir = project_root.join(".story_kit").join("work").join(stage_dir);
let dir = project_root.join(".storkit").join("work").join(stage_dir);
if !dir.is_dir() {
return Vec::new();
}
@@ -875,7 +875,7 @@ mod tests {
fn scan_stage_items_returns_sorted_story_ids() {
use std::fs;
let tmp = tempfile::tempdir().unwrap();
let stage_dir = tmp.path().join(".story_kit").join("work").join("2_current");
let stage_dir = tmp.path().join(".storkit").join("work").join("2_current");
fs::create_dir_all(&stage_dir).unwrap();
fs::write(stage_dir.join("42_story_foo.md"), "---\nname: foo\n---").unwrap();
fs::write(stage_dir.join("10_story_bar.md"), "---\nname: bar\n---").unwrap();
@@ -1199,7 +1199,7 @@ stage = "coder"
#[tokio::test]
async fn auto_assign_picks_up_story_queued_in_current() {
let tmp = tempfile::tempdir().unwrap();
let sk = tmp.path().join(".story_kit");
let sk = tmp.path().join(".storkit");
let current = sk.join("work/2_current");
std::fs::create_dir_all(&current).unwrap();
std::fs::write(
@@ -1238,7 +1238,7 @@ stage = "coder"
let root = tmp.path();
// Create project.toml with a QA agent.
let sk = root.join(".story_kit");
let sk = root.join(".storkit");
std::fs::create_dir_all(&sk).unwrap();
std::fs::write(
sk.join("project.toml"),
@@ -1247,7 +1247,7 @@ stage = "coder"
.unwrap();
// Put a spike in 3_qa/ with review_hold: true.
let qa_dir = root.join(".story_kit/work/3_qa");
let qa_dir = root.join(".storkit/work/3_qa");
std::fs::create_dir_all(&qa_dir).unwrap();
std::fs::write(
qa_dir.join("20_spike_test.md"),
@@ -1276,7 +1276,7 @@ stage = "coder"
#[tokio::test]
async fn auto_assign_ignores_coder_preference_when_story_is_in_qa_stage() {
let tmp = tempfile::tempdir().unwrap();
let sk = tmp.path().join(".story_kit");
let sk = tmp.path().join(".storkit");
let qa_dir = sk.join("work/3_qa");
std::fs::create_dir_all(&qa_dir).unwrap();
std::fs::write(
@@ -1323,7 +1323,7 @@ stage = "coder"
#[tokio::test]
async fn auto_assign_respects_coder_preference_when_story_is_in_current_stage() {
let tmp = tempfile::tempdir().unwrap();
let sk = tmp.path().join(".story_kit");
let sk = tmp.path().join(".storkit");
let current_dir = sk.join("work/2_current");
std::fs::create_dir_all(&current_dir).unwrap();
std::fs::write(
@@ -1370,7 +1370,7 @@ stage = "coder"
#[tokio::test]
async fn auto_assign_stage_mismatch_with_no_fallback_starts_no_agent() {
let tmp = tempfile::tempdir().unwrap();
let sk = tmp.path().join(".story_kit");
let sk = tmp.path().join(".storkit");
let qa_dir = sk.join("work/3_qa");
std::fs::create_dir_all(&qa_dir).unwrap();
// Only a coder agent is configured — no QA agent exists.
@@ -1409,7 +1409,7 @@ stage = "coder"
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path().to_path_buf();
let sk_dir = root.join(".story_kit");
let sk_dir = root.join(".storkit");
// Two stories waiting in 2_current, one coder agent.
fs::create_dir_all(sk_dir.join("work/2_current")).unwrap();
fs::write(
@@ -1463,7 +1463,7 @@ stage = "coder"
#[test]
fn has_review_hold_returns_true_when_set() {
let tmp = tempfile::tempdir().unwrap();
let qa_dir = tmp.path().join(".story_kit/work/3_qa");
let qa_dir = tmp.path().join(".storkit/work/3_qa");
std::fs::create_dir_all(&qa_dir).unwrap();
let spike_path = qa_dir.join("10_spike_research.md");
std::fs::write(
@@ -1477,7 +1477,7 @@ stage = "coder"
#[test]
fn has_review_hold_returns_false_when_not_set() {
let tmp = tempfile::tempdir().unwrap();
let qa_dir = tmp.path().join(".story_kit/work/3_qa");
let qa_dir = tmp.path().join(".storkit/work/3_qa");
std::fs::create_dir_all(&qa_dir).unwrap();
let spike_path = qa_dir.join("10_spike_research.md");
std::fs::write(&spike_path, "---\nname: Research spike\n---\n# Spike\n").unwrap();
@@ -1702,13 +1702,13 @@ stage = "coder"
let root = tmp.path();
// Set up story in 2_current/.
let current = root.join(".story_kit/work/2_current");
let current = root.join(".storkit/work/2_current");
fs::create_dir_all(&current).unwrap();
fs::write(current.join("60_story_test.md"), "test").unwrap();
// Create a worktree directory that is a fresh git repo with no commits
// ahead of its own base branch (simulates a worktree where no work was done).
let wt_dir = root.join(".story_kit/worktrees/60_story_test");
let wt_dir = root.join(".storkit/worktrees/60_story_test");
fs::create_dir_all(&wt_dir).unwrap();
init_git_repo(&wt_dir);
@@ -1733,7 +1733,7 @@ stage = "coder"
init_git_repo(root);
// Set up story in 2_current/ and commit it so the project root is clean.
let current = root.join(".story_kit/work/2_current");
let current = root.join(".storkit/work/2_current");
fs::create_dir_all(&current).unwrap();
fs::write(current.join("61_story_test.md"), "test").unwrap();
Command::new("git")
@@ -1756,7 +1756,7 @@ stage = "coder"
.unwrap();
// Create a real git worktree for the story.
let wt_dir = root.join(".story_kit/worktrees/61_story_test");
let wt_dir = root.join(".storkit/worktrees/61_story_test");
fs::create_dir_all(wt_dir.parent().unwrap()).unwrap();
Command::new("git")
.args([
@@ -1804,7 +1804,7 @@ stage = "coder"
// and the story stays in 2_current/. The important assertion is that
// reconcile ran without panicking and the story is in a consistent state.
let in_current = current.join("61_story_test.md").exists();
let in_qa = root.join(".story_kit/work/3_qa/61_story_test.md").exists();
let in_qa = root.join(".storkit/work/3_qa/61_story_test.md").exists();
assert!(
in_current || in_qa,
"story should be in 2_current/ or 3_qa/ after reconciliation"

View File

@@ -1037,7 +1037,7 @@ fn find_active_story_stage(project_root: &Path, story_id: &str) -> Option<&'stat
const STAGES: [&str; 3] = ["2_current", "3_qa", "4_merge"];
for stage in &STAGES {
let path = project_root
.join(".story_kit")
.join(".storkit")
.join("work")
.join(stage)
.join(format!("{story_id}.md"));
@@ -1301,7 +1301,7 @@ stage = "coder"
#[tokio::test]
async fn start_agent_auto_selects_second_coder_when_first_busy() {
let tmp = tempfile::tempdir().unwrap();
let sk = tmp.path().join(".story_kit");
let sk = tmp.path().join(".storkit");
std::fs::create_dir_all(&sk).unwrap();
std::fs::write(
sk.join("project.toml"),
@@ -1347,7 +1347,7 @@ stage = "coder"
#[tokio::test]
async fn start_agent_returns_busy_when_all_coders_occupied() {
let tmp = tempfile::tempdir().unwrap();
let sk = tmp.path().join(".story_kit");
let sk = tmp.path().join(".storkit");
std::fs::create_dir_all(&sk).unwrap();
std::fs::write(
sk.join("project.toml"),
@@ -1379,7 +1379,7 @@ stage = "coder"
#[tokio::test]
async fn start_agent_moves_story_to_current_when_coders_busy() {
let tmp = tempfile::tempdir().unwrap();
let sk = tmp.path().join(".story_kit");
let sk = tmp.path().join(".storkit");
let backlog = sk.join("work/1_backlog");
std::fs::create_dir_all(&backlog).unwrap();
std::fs::write(
@@ -1424,7 +1424,7 @@ stage = "coder"
#[tokio::test]
async fn start_agent_story_already_in_current_is_noop() {
let tmp = tempfile::tempdir().unwrap();
let sk = tmp.path().join(".story_kit");
let sk = tmp.path().join(".storkit");
let current = sk.join("work/2_current");
std::fs::create_dir_all(&current).unwrap();
std::fs::write(
@@ -1451,7 +1451,7 @@ stage = "coder"
#[tokio::test]
async fn start_agent_explicit_name_unchanged_when_busy() {
let tmp = tempfile::tempdir().unwrap();
let sk = tmp.path().join(".story_kit");
let sk = tmp.path().join(".storkit");
std::fs::create_dir_all(&sk).unwrap();
std::fs::write(
sk.join("project.toml"),
@@ -1490,7 +1490,7 @@ stage = "coder"
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let sk_dir = root.join(".story_kit");
let sk_dir = root.join(".storkit");
fs::create_dir_all(&sk_dir).unwrap();
fs::write(sk_dir.join("project.toml"), "[[agent]]\nname = \"qa\"\n").unwrap();
@@ -1517,7 +1517,7 @@ stage = "coder"
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let sk_dir = root.join(".story_kit");
let sk_dir = root.join(".storkit");
fs::create_dir_all(&sk_dir).unwrap();
fs::write(sk_dir.join("project.toml"), "[[agent]]\nname = \"qa\"\n").unwrap();
@@ -1543,7 +1543,7 @@ stage = "coder"
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let sk_dir = root.join(".story_kit");
let sk_dir = root.join(".storkit");
fs::create_dir_all(&sk_dir).unwrap();
fs::write(
sk_dir.join("project.toml"),
@@ -1551,7 +1551,7 @@ stage = "coder"
)
.unwrap();
let upcoming = root.join(".story_kit/work/1_backlog");
let upcoming = root.join(".storkit/work/1_backlog");
fs::create_dir_all(&upcoming).unwrap();
fs::write(upcoming.join("50_story_test.md"), "---\nname: Test\n---\n").unwrap();
@@ -1609,7 +1609,7 @@ stage = "coder"
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let sk_dir = root.join(".story_kit");
let sk_dir = root.join(".storkit");
fs::create_dir_all(&sk_dir).unwrap();
fs::write(sk_dir.join("project.toml"), "[[agent]]\nname = \"qa\"\n").unwrap();
@@ -1635,7 +1635,7 @@ stage = "coder"
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let sk_dir = root.join(".story_kit");
let sk_dir = root.join(".storkit");
fs::create_dir_all(&sk_dir).unwrap();
fs::write(
sk_dir.join("project.toml"),
@@ -1666,20 +1666,20 @@ stage = "coder"
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path().to_path_buf();
let sk_dir = root.join(".story_kit");
let sk_dir = root.join(".storkit");
fs::create_dir_all(sk_dir.join("work/1_backlog")).unwrap();
fs::write(
root.join(".story_kit/project.toml"),
root.join(".storkit/project.toml"),
"[[agent]]\nname = \"coder-1\"\n",
)
.unwrap();
fs::write(
root.join(".story_kit/work/1_backlog/86_story_foo.md"),
root.join(".storkit/work/1_backlog/86_story_foo.md"),
"---\nname: Foo\n---\n",
)
.unwrap();
fs::write(
root.join(".story_kit/work/1_backlog/130_story_bar.md"),
root.join(".storkit/work/1_backlog/130_story_bar.md"),
"---\nname: Bar\n---\n",
)
.unwrap();
@@ -1731,7 +1731,7 @@ stage = "coder"
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let sk_dir = root.join(".story_kit");
let sk_dir = root.join(".storkit");
fs::create_dir_all(&sk_dir).unwrap();
fs::write(
sk_dir.join("project.toml"),
@@ -1768,7 +1768,7 @@ stage = "coder"
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let sk_dir = root.join(".story_kit");
let sk_dir = root.join(".storkit");
fs::create_dir_all(&sk_dir).unwrap();
fs::write(
sk_dir.join("project.toml"),
@@ -1800,15 +1800,15 @@ stage = "coder"
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path().to_path_buf();
let sk_dir = root.join(".story_kit");
let sk_dir = root.join(".storkit");
fs::create_dir_all(sk_dir.join("work/2_current")).unwrap();
fs::write(
root.join(".story_kit/project.toml"),
root.join(".storkit/project.toml"),
"[[agent]]\nname = \"coder-1\"\n\n[[agent]]\nname = \"coder-2\"\n",
)
.unwrap();
fs::write(
root.join(".story_kit/work/2_current/42_story_foo.md"),
root.join(".storkit/work/2_current/42_story_foo.md"),
"---\nname: Foo\n---\n",
)
.unwrap();
@@ -1854,15 +1854,15 @@ stage = "coder"
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let sk_dir = root.join(".story_kit");
let sk_dir = root.join(".storkit");
fs::create_dir_all(sk_dir.join("work/1_backlog")).unwrap();
fs::write(
root.join(".story_kit/project.toml"),
root.join(".storkit/project.toml"),
"[[agent]]\nname = \"coder-1\"\n\n[[agent]]\nname = \"coder-2\"\n",
)
.unwrap();
fs::write(
root.join(".story_kit/work/1_backlog/99_story_baz.md"),
root.join(".storkit/work/1_backlog/99_story_baz.md"),
"---\nname: Baz\n---\n",
)
.unwrap();
@@ -1892,7 +1892,7 @@ stage = "coder"
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let sk_dir = root.join(".story_kit");
let sk_dir = root.join(".storkit");
fs::create_dir_all(sk_dir.join("work/2_current")).unwrap();
fs::write(
sk_dir.join("project.toml"),
@@ -1929,7 +1929,7 @@ stage = "coder"
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let sk_dir = root.join(".story_kit");
let sk_dir = root.join(".storkit");
fs::create_dir_all(sk_dir.join("work/3_qa")).unwrap();
fs::write(
sk_dir.join("project.toml"),
@@ -1966,7 +1966,7 @@ stage = "coder"
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let sk_dir = root.join(".story_kit");
let sk_dir = root.join(".storkit");
fs::create_dir_all(sk_dir.join("work/4_merge")).unwrap();
fs::write(
sk_dir.join("project.toml"),
@@ -2003,7 +2003,7 @@ stage = "coder"
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let sk_dir = root.join(".story_kit");
let sk_dir = root.join(".storkit");
fs::create_dir_all(sk_dir.join("work/2_current")).unwrap();
fs::write(
sk_dir.join("project.toml"),
@@ -2039,7 +2039,7 @@ stage = "coder"
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let sk_dir = root.join(".story_kit");
let sk_dir = root.join(".storkit");
fs::create_dir_all(sk_dir.join("work/4_merge")).unwrap();
fs::write(
sk_dir.join("project.toml"),
@@ -2075,7 +2075,7 @@ stage = "coder"
use std::fs;
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let current = root.join(".story_kit/work/2_current");
let current = root.join(".storkit/work/2_current");
fs::create_dir_all(&current).unwrap();
fs::write(current.join("10_story_test.md"), "test").unwrap();
@@ -2090,7 +2090,7 @@ stage = "coder"
use std::fs;
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let qa = root.join(".story_kit/work/3_qa");
let qa = root.join(".storkit/work/3_qa");
fs::create_dir_all(&qa).unwrap();
fs::write(qa.join("11_story_test.md"), "test").unwrap();
@@ -2102,7 +2102,7 @@ stage = "coder"
use std::fs;
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let merge = root.join(".story_kit/work/4_merge");
let merge = root.join(".storkit/work/4_merge");
fs::create_dir_all(&merge).unwrap();
fs::write(merge.join("12_story_test.md"), "test").unwrap();
@@ -2157,7 +2157,7 @@ stage = "coder"
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let current = root.join(".story_kit/work/2_current");
let current = root.join(".storkit/work/2_current");
fs::create_dir_all(&current).unwrap();
fs::write(current.join("60_story_cleanup.md"), "test").unwrap();
@@ -2180,7 +2180,7 @@ stage = "coder"
assert_eq!(remaining[0].story_id, "61_story_other");
assert!(
root.join(".story_kit/work/5_done/60_story_cleanup.md")
root.join(".storkit/work/5_done/60_story_cleanup.md")
.exists()
);
}

View File

@@ -56,7 +56,7 @@ impl AgentPool {
let default_qa = config.default_qa_mode();
// Story is in 2_current/ when a coder completes.
let story_path = project_root
.join(".story_kit/work/2_current")
.join(".storkit/work/2_current")
.join(format!("{story_id}.md"));
crate::io::story_metadata::resolve_qa_mode(&story_path, default_qa)
}
@@ -105,7 +105,7 @@ impl AgentPool {
if let Err(e) = super::super::lifecycle::move_story_to_qa(&project_root, story_id) {
slog_error!("[pipeline] Failed to move '{story_id}' to 3_qa/: {e}");
} else {
let qa_dir = project_root.join(".story_kit/work/3_qa");
let qa_dir = project_root.join(".storkit/work/3_qa");
let story_path = qa_dir.join(format!("{story_id}.md"));
if let Err(e) =
crate::io::story_metadata::write_review_hold(&story_path)
@@ -120,7 +120,7 @@ impl AgentPool {
} else {
// Increment retry count and check if blocked.
let story_path = project_root
.join(".story_kit/work/2_current")
.join(".storkit/work/2_current")
.join(format!("{story_id}.md"));
if should_block_story(&story_path, config.max_retries, story_id, "coder") {
// Story has exceeded retry limit — do not restart.
@@ -171,7 +171,7 @@ impl AgentPool {
if item_type == "spike" {
true // Spikes always need human review.
} else {
let qa_dir = project_root.join(".story_kit/work/3_qa");
let qa_dir = project_root.join(".storkit/work/3_qa");
let story_path = qa_dir.join(format!("{story_id}.md"));
let default_qa = config.default_qa_mode();
matches!(
@@ -183,7 +183,7 @@ impl AgentPool {
if needs_human_review {
// Hold in 3_qa/ for human review.
let qa_dir = project_root.join(".story_kit/work/3_qa");
let qa_dir = project_root.join(".storkit/work/3_qa");
let story_path = qa_dir.join(format!("{story_id}.md"));
if let Err(e) =
crate::io::story_metadata::write_review_hold(&story_path)
@@ -219,7 +219,7 @@ impl AgentPool {
}
} else {
let story_path = project_root
.join(".story_kit/work/3_qa")
.join(".storkit/work/3_qa")
.join(format!("{story_id}.md"));
if should_block_story(&story_path, config.max_retries, story_id, "qa-coverage") {
// Story has exceeded retry limit — do not restart.
@@ -243,7 +243,7 @@ impl AgentPool {
}
} else {
let story_path = project_root
.join(".story_kit/work/3_qa")
.join(".storkit/work/3_qa")
.join(format!("{story_id}.md"));
if should_block_story(&story_path, config.max_retries, story_id, "qa") {
// Story has exceeded retry limit — do not restart.
@@ -319,7 +319,7 @@ impl AgentPool {
);
} else {
let story_path = project_root
.join(".story_kit/work/4_merge")
.join(".storkit/work/4_merge")
.join(format!("{story_id}.md"));
if should_block_story(&story_path, config.max_retries, story_id, "mergemaster") {
// Story has exceeded retry limit — do not restart.
@@ -1125,7 +1125,7 @@ mod tests {
let root = tmp.path();
// Set up story in 2_current/ (no qa frontmatter → uses project default "server")
let current = root.join(".story_kit/work/2_current");
let current = root.join(".storkit/work/2_current");
fs::create_dir_all(&current).unwrap();
fs::write(current.join("50_story_test.md"), "test").unwrap();
@@ -1146,7 +1146,7 @@ mod tests {
// With default qa: server, story skips QA and goes straight to 4_merge/
assert!(
root.join(".story_kit/work/4_merge/50_story_test.md")
root.join(".storkit/work/4_merge/50_story_test.md")
.exists(),
"story should be in 4_merge/"
);
@@ -1163,7 +1163,7 @@ mod tests {
let root = tmp.path();
// Set up story in 2_current/ with qa: agent frontmatter
let current = root.join(".story_kit/work/2_current");
let current = root.join(".storkit/work/2_current");
fs::create_dir_all(&current).unwrap();
fs::write(
current.join("50_story_test.md"),
@@ -1188,7 +1188,7 @@ mod tests {
// With qa: agent, story should move to 3_qa/
assert!(
root.join(".story_kit/work/3_qa/50_story_test.md").exists(),
root.join(".storkit/work/3_qa/50_story_test.md").exists(),
"story should be in 3_qa/"
);
assert!(
@@ -1204,7 +1204,7 @@ mod tests {
let root = tmp.path();
// Set up story in 3_qa/
let qa_dir = root.join(".story_kit/work/3_qa");
let qa_dir = root.join(".storkit/work/3_qa");
fs::create_dir_all(&qa_dir).unwrap();
// qa: server so the story skips human review and goes straight to merge.
fs::write(
@@ -1230,7 +1230,7 @@ mod tests {
// Story should have moved to 4_merge/
assert!(
root.join(".story_kit/work/4_merge/51_story_test.md")
root.join(".storkit/work/4_merge/51_story_test.md")
.exists(),
"story should be in 4_merge/"
);
@@ -1246,7 +1246,7 @@ mod tests {
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let current = root.join(".story_kit/work/2_current");
let current = root.join(".storkit/work/2_current");
fs::create_dir_all(&current).unwrap();
fs::write(current.join("52_story_test.md"), "test").unwrap();
@@ -1280,18 +1280,18 @@ mod tests {
let root = tmp.path();
// Set up story in 2_current/
let current = root.join(".story_kit/work/2_current");
let current = root.join(".storkit/work/2_current");
fs::create_dir_all(&current).unwrap();
fs::write(current.join("173_story_test.md"), "test").unwrap();
// Ensure 3_qa/ exists for the move target
fs::create_dir_all(root.join(".story_kit/work/3_qa")).unwrap();
fs::create_dir_all(root.join(".storkit/work/3_qa")).unwrap();
// Ensure 1_backlog/ exists (start_agent calls move_story_to_current)
fs::create_dir_all(root.join(".story_kit/work/1_backlog")).unwrap();
fs::create_dir_all(root.join(".storkit/work/1_backlog")).unwrap();
// Write a project.toml with a qa agent so start_agent can resolve it.
fs::create_dir_all(root.join(".story_kit")).unwrap();
fs::create_dir_all(root.join(".storkit")).unwrap();
fs::write(
root.join(".story_kit/project.toml"),
root.join(".storkit/project.toml"),
r#"
default_qa = "agent"
@@ -1426,7 +1426,7 @@ stage = "qa"
.unwrap();
// Create the story file in 4_merge/ so we can test archival
let merge_dir = repo.join(".story_kit/work/4_merge");
let merge_dir = repo.join(".storkit/work/4_merge");
fs::create_dir_all(&merge_dir).unwrap();
let story_file = merge_dir.join("23_test.md");
fs::write(&story_file, "---\nname: Test\n---\n").unwrap();
@@ -1454,7 +1454,7 @@ stage = "qa"
"report should be coherent: {report:?}"
);
if report.story_archived {
let done = repo.join(".story_kit/work/5_done/23_test.md");
let done = repo.join(".storkit/work/5_done/23_test.md");
assert!(done.exists(), "done file should exist");
}
}
@@ -1639,7 +1639,7 @@ stage = "qa"
.unwrap();
// Create story file in 4_merge.
let merge_dir = repo.join(".story_kit/work/4_merge");
let merge_dir = repo.join(".storkit/work/4_merge");
fs::create_dir_all(&merge_dir).unwrap();
fs::write(merge_dir.join("42_story_foo.md"), "---\nname: Test\n---\n").unwrap();
Command::new("git")
@@ -1689,7 +1689,7 @@ stage = "qa"
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let sk = root.join(".story_kit");
let sk = root.join(".storkit");
let qa_dir = sk.join("work/3_qa");
fs::create_dir_all(&qa_dir).unwrap();

View File

@@ -20,7 +20,7 @@ pub struct TokenUsageRecord {
/// Append a token usage record to the persistent JSONL file.
///
/// Each line is a self-contained JSON object, making appends atomic and
/// reads simple. The file lives at `.story_kit/token_usage.jsonl`.
/// reads simple. The file lives at `.storkit/token_usage.jsonl`.
pub fn append_record(project_root: &Path, record: &TokenUsageRecord) -> Result<(), String> {
let path = token_usage_path(project_root);
if let Some(parent) = path.parent() {
@@ -87,7 +87,7 @@ pub fn build_record(
}
fn token_usage_path(project_root: &Path) -> std::path::PathBuf {
project_root.join(".story_kit").join("token_usage.jsonl")
project_root.join(".storkit").join("token_usage.jsonl")
}
#[cfg(test)]
@@ -147,7 +147,7 @@ mod tests {
fn malformed_lines_are_skipped() {
let dir = TempDir::new().unwrap();
let root = dir.path();
let path = root.join(".story_kit").join("token_usage.jsonl");
let path = root.join(".storkit").join("token_usage.jsonl");
fs::create_dir_all(path.parent().unwrap()).unwrap();
fs::write(&path, "not json\n{\"bad\":true}\n").unwrap();