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

@@ -84,7 +84,7 @@ struct PersistedHistory {
}
/// Path to the persisted conversation history file relative to project root.
const HISTORY_FILE: &str = ".story_kit/matrix_history.json";
const HISTORY_FILE: &str = ".storkit/matrix_history.json";
/// Load conversation history from disk, returning an empty map on any error.
pub fn load_history(project_root: &std::path::Path) -> HashMap<OwnedRoomId, RoomConversation> {
@@ -214,7 +214,7 @@ pub async fn run_bot(
perm_rx: Arc<TokioMutex<mpsc::UnboundedReceiver<PermissionForward>>>,
agents: Arc<AgentPool>,
) -> Result<(), String> {
let store_path = project_root.join(".story_kit").join("matrix_store");
let store_path = project_root.join(".storkit").join("matrix_store");
let client = Client::builder()
.homeserver_url(&config.homeserver)
.sqlite_store(&store_path, None)
@@ -223,7 +223,7 @@ pub async fn run_bot(
.map_err(|e| format!("Failed to build Matrix client: {e}"))?;
// Persist device ID so E2EE crypto state survives restarts.
let device_id_path = project_root.join(".story_kit").join("matrix_device_id");
let device_id_path = project_root.join(".storkit").join("matrix_device_id");
let saved_device_id: Option<String> = std::fs::read_to_string(&device_id_path)
.ok()
.map(|s| s.trim().to_string())
@@ -1701,7 +1701,7 @@ mod tests {
#[test]
fn save_and_load_history_round_trip() {
let dir = tempfile::tempdir().unwrap();
let story_kit_dir = dir.path().join(".story_kit");
let story_kit_dir = dir.path().join(".storkit");
std::fs::create_dir_all(&story_kit_dir).unwrap();
let room_id: OwnedRoomId = "!persist:example.com".parse().unwrap();
@@ -1742,7 +1742,7 @@ mod tests {
#[test]
fn load_history_returns_empty_on_corrupt_file() {
let dir = tempfile::tempdir().unwrap();
let story_kit_dir = dir.path().join(".story_kit");
let story_kit_dir = dir.path().join(".storkit");
std::fs::create_dir_all(&story_kit_dir).unwrap();
std::fs::write(dir.path().join(HISTORY_FILE), "not valid json").unwrap();
let loaded = load_history(dir.path());

View File

@@ -62,7 +62,7 @@ pub(super) fn handle_move(ctx: &CommandContext) -> Option<String> {
'outer: for stage_dir in SEARCH_DIRS {
let dir = ctx
.project_root
.join(".story_kit")
.join(".storkit")
.join("work")
.join(stage_dir);
if !dir.exists() {
@@ -143,7 +143,7 @@ mod tests {
}
fn write_story_file(root: &std::path::Path, stage: &str, filename: &str, content: &str) {
let dir = root.join(".story_kit/work").join(stage);
let dir = root.join(".storkit/work").join(stage);
std::fs::create_dir_all(&dir).unwrap();
std::fs::write(dir.join(filename), content).unwrap();
}
@@ -246,7 +246,7 @@ mod tests {
// Verify the file was actually moved.
let new_path = tmp
.path()
.join(".story_kit/work/2_current/42_story_some_feature.md");
.join(".storkit/work/2_current/42_story_some_feature.md");
assert!(new_path.exists(), "story file should be in 2_current/");
}

View File

@@ -108,7 +108,7 @@ fn find_story_name(root: &std::path::Path, num_str: &str) -> Option<String> {
"6_archived",
];
for stage in &stages {
let dir = root.join(".story_kit").join("work").join(stage);
let dir = root.join(".storkit").join("work").join(stage);
if !dir.exists() {
continue;
}

View File

@@ -34,7 +34,7 @@ pub(super) fn handle_show(ctx: &CommandContext) -> Option<String> {
for stage in &stages {
let dir = ctx
.project_root
.join(".story_kit")
.join(".storkit")
.join("work")
.join(stage);
if !dir.exists() {
@@ -92,7 +92,7 @@ mod tests {
}
fn write_story_file(root: &std::path::Path, stage: &str, filename: &str, content: &str) {
let dir = root.join(".story_kit/work").join(stage);
let dir = root.join(".storkit/work").join(stage);
std::fs::create_dir_all(&dir).unwrap();
std::fs::write(dir.join(filename), content).unwrap();
}

View File

@@ -38,7 +38,7 @@ fn read_stage_items(
stage_dir: &str,
) -> Vec<(String, Option<String>)> {
let dir = project_root
.join(".story_kit")
.join(".storkit")
.join("work")
.join(stage_dir);
if !dir.exists() {
@@ -228,7 +228,7 @@ mod tests {
use tempfile::TempDir;
let tmp = TempDir::new().unwrap();
let stage_dir = tmp.path().join(".story_kit/work/2_current");
let stage_dir = tmp.path().join(".storkit/work/2_current");
std::fs::create_dir_all(&stage_dir).unwrap();
// Write a story file with a front-matter name
@@ -257,7 +257,7 @@ mod tests {
use tempfile::TempDir;
let tmp = TempDir::new().unwrap();
let stage_dir = tmp.path().join(".story_kit/work/2_current");
let stage_dir = tmp.path().join(".storkit/work/2_current");
std::fs::create_dir_all(&stage_dir).unwrap();
let story_path = stage_dir.join("293_story_register_all_bot_commands.md");
@@ -295,7 +295,7 @@ mod tests {
use tempfile::TempDir;
let tmp = TempDir::new().unwrap();
let stage_dir = tmp.path().join(".story_kit/work/2_current");
let stage_dir = tmp.path().join(".storkit/work/2_current");
std::fs::create_dir_all(&stage_dir).unwrap();
let story_path = stage_dir.join("293_story_register_all_bot_commands.md");
@@ -318,7 +318,7 @@ mod tests {
use tempfile::TempDir;
let tmp = TempDir::new().unwrap();
let stage_dir = tmp.path().join(".story_kit/work/2_current");
let stage_dir = tmp.path().join(".storkit/work/2_current");
std::fs::create_dir_all(&stage_dir).unwrap();
let story_path = stage_dir.join("293_story_register_all_bot_commands.md");

View File

@@ -9,7 +9,7 @@ fn default_permission_timeout_secs() -> u64 {
120
}
/// Configuration for the Matrix bot, read from `.story_kit/bot.toml`.
/// Configuration for the Matrix bot, read from `.storkit/bot.toml`.
#[derive(Deserialize, Clone, Debug)]
pub struct BotConfig {
/// Matrix homeserver URL, e.g. `https://matrix.example.com`
@@ -107,12 +107,12 @@ fn default_transport() -> String {
}
impl BotConfig {
/// Load bot configuration from `.story_kit/bot.toml`.
/// Load bot configuration from `.storkit/bot.toml`.
///
/// Returns `None` if the file does not exist, fails to parse, has
/// `enabled = false`, or specifies no room IDs.
pub fn load(project_root: &Path) -> Option<Self> {
let path = project_root.join(".story_kit").join("bot.toml");
let path = project_root.join(".storkit").join("bot.toml");
if !path.exists() {
return None;
}
@@ -201,7 +201,7 @@ impl BotConfig {
/// array, and writes the result back. Errors are logged but not propagated
/// so a persistence failure never interrupts the bot's message handling.
pub fn save_ambient_rooms(project_root: &Path, room_ids: &[String]) {
let path = project_root.join(".story_kit").join("bot.toml");
let path = project_root.join(".storkit").join("bot.toml");
let content = match std::fs::read_to_string(&path) {
Ok(c) => c,
Err(e) => {
@@ -250,7 +250,7 @@ mod tests {
#[test]
fn load_returns_none_when_disabled() {
let tmp = tempfile::tempdir().unwrap();
let sk = tmp.path().join(".story_kit");
let sk = tmp.path().join(".storkit");
fs::create_dir_all(&sk).unwrap();
fs::write(
sk.join("bot.toml"),
@@ -270,7 +270,7 @@ enabled = false
#[test]
fn load_returns_config_when_enabled_with_room_ids() {
let tmp = tempfile::tempdir().unwrap();
let sk = tmp.path().join(".story_kit");
let sk = tmp.path().join(".storkit");
fs::create_dir_all(&sk).unwrap();
fs::write(
sk.join("bot.toml"),
@@ -298,7 +298,7 @@ enabled = true
#[test]
fn load_merges_deprecated_room_id_into_room_ids() {
let tmp = tempfile::tempdir().unwrap();
let sk = tmp.path().join(".story_kit");
let sk = tmp.path().join(".storkit");
fs::create_dir_all(&sk).unwrap();
// Old-style single room_id key — should still work.
fs::write(
@@ -319,7 +319,7 @@ enabled = true
#[test]
fn load_returns_none_when_no_room_ids() {
let tmp = tempfile::tempdir().unwrap();
let sk = tmp.path().join(".story_kit");
let sk = tmp.path().join(".storkit");
fs::create_dir_all(&sk).unwrap();
fs::write(
sk.join("bot.toml"),
@@ -338,7 +338,7 @@ enabled = true
#[test]
fn load_returns_none_when_toml_invalid() {
let tmp = tempfile::tempdir().unwrap();
let sk = tmp.path().join(".story_kit");
let sk = tmp.path().join(".storkit");
fs::create_dir_all(&sk).unwrap();
fs::write(sk.join("bot.toml"), "not valid toml {{{").unwrap();
let result = BotConfig::load(tmp.path());
@@ -348,7 +348,7 @@ enabled = true
#[test]
fn load_respects_optional_model() {
let tmp = tempfile::tempdir().unwrap();
let sk = tmp.path().join(".story_kit");
let sk = tmp.path().join(".storkit");
fs::create_dir_all(&sk).unwrap();
fs::write(
sk.join("bot.toml"),
@@ -369,7 +369,7 @@ model = "claude-sonnet-4-6"
#[test]
fn load_uses_default_history_size() {
let tmp = tempfile::tempdir().unwrap();
let sk = tmp.path().join(".story_kit");
let sk = tmp.path().join(".storkit");
fs::create_dir_all(&sk).unwrap();
fs::write(
sk.join("bot.toml"),
@@ -389,7 +389,7 @@ enabled = true
#[test]
fn load_respects_custom_history_size() {
let tmp = tempfile::tempdir().unwrap();
let sk = tmp.path().join(".story_kit");
let sk = tmp.path().join(".storkit");
fs::create_dir_all(&sk).unwrap();
fs::write(
sk.join("bot.toml"),
@@ -410,7 +410,7 @@ history_size = 50
#[test]
fn load_reads_display_name() {
let tmp = tempfile::tempdir().unwrap();
let sk = tmp.path().join(".story_kit");
let sk = tmp.path().join(".storkit");
fs::create_dir_all(&sk).unwrap();
fs::write(
sk.join("bot.toml"),
@@ -431,7 +431,7 @@ display_name = "Timmy"
#[test]
fn load_display_name_defaults_to_none_when_absent() {
let tmp = tempfile::tempdir().unwrap();
let sk = tmp.path().join(".story_kit");
let sk = tmp.path().join(".storkit");
fs::create_dir_all(&sk).unwrap();
fs::write(
sk.join("bot.toml"),
@@ -451,7 +451,7 @@ enabled = true
#[test]
fn load_uses_default_permission_timeout() {
let tmp = tempfile::tempdir().unwrap();
let sk = tmp.path().join(".story_kit");
let sk = tmp.path().join(".storkit");
fs::create_dir_all(&sk).unwrap();
fs::write(
sk.join("bot.toml"),
@@ -471,7 +471,7 @@ enabled = true
#[test]
fn load_respects_custom_permission_timeout() {
let tmp = tempfile::tempdir().unwrap();
let sk = tmp.path().join(".story_kit");
let sk = tmp.path().join(".storkit");
fs::create_dir_all(&sk).unwrap();
fs::write(
sk.join("bot.toml"),
@@ -495,7 +495,7 @@ permission_timeout_secs = 60
// must parse successfully — the field is simply ignored now that
// verification is always enforced unconditionally.
let tmp = tempfile::tempdir().unwrap();
let sk = tmp.path().join(".story_kit");
let sk = tmp.path().join(".storkit");
fs::create_dir_all(&sk).unwrap();
fs::write(
sk.join("bot.toml"),
@@ -520,7 +520,7 @@ require_verified_devices = true
#[test]
fn load_reads_ambient_rooms() {
let tmp = tempfile::tempdir().unwrap();
let sk = tmp.path().join(".story_kit");
let sk = tmp.path().join(".storkit");
fs::create_dir_all(&sk).unwrap();
fs::write(
sk.join("bot.toml"),
@@ -541,7 +541,7 @@ ambient_rooms = ["!abc:example.com"]
#[test]
fn load_ambient_rooms_defaults_to_empty_when_absent() {
let tmp = tempfile::tempdir().unwrap();
let sk = tmp.path().join(".story_kit");
let sk = tmp.path().join(".storkit");
fs::create_dir_all(&sk).unwrap();
fs::write(
sk.join("bot.toml"),
@@ -561,7 +561,7 @@ enabled = true
#[test]
fn save_ambient_rooms_persists_to_bot_toml() {
let tmp = tempfile::tempdir().unwrap();
let sk = tmp.path().join(".story_kit");
let sk = tmp.path().join(".storkit");
fs::create_dir_all(&sk).unwrap();
fs::write(
sk.join("bot.toml"),
@@ -583,7 +583,7 @@ enabled = true
#[test]
fn save_ambient_rooms_clears_when_empty() {
let tmp = tempfile::tempdir().unwrap();
let sk = tmp.path().join(".story_kit");
let sk = tmp.path().join(".storkit");
fs::create_dir_all(&sk).unwrap();
fs::write(
sk.join("bot.toml"),
@@ -606,7 +606,7 @@ ambient_rooms = ["!abc:example.com"]
#[test]
fn load_transport_defaults_to_matrix() {
let tmp = tempfile::tempdir().unwrap();
let sk = tmp.path().join(".story_kit");
let sk = tmp.path().join(".storkit");
fs::create_dir_all(&sk).unwrap();
fs::write(
sk.join("bot.toml"),
@@ -626,7 +626,7 @@ enabled = true
#[test]
fn load_transport_reads_custom_value() {
let tmp = tempfile::tempdir().unwrap();
let sk = tmp.path().join(".story_kit");
let sk = tmp.path().join(".storkit");
fs::create_dir_all(&sk).unwrap();
fs::write(
sk.join("bot.toml"),
@@ -662,7 +662,7 @@ whatsapp_verify_token = "my-verify"
#[test]
fn load_whatsapp_returns_none_when_missing_phone_number_id() {
let tmp = tempfile::tempdir().unwrap();
let sk = tmp.path().join(".story_kit");
let sk = tmp.path().join(".storkit");
fs::create_dir_all(&sk).unwrap();
fs::write(
sk.join("bot.toml"),
@@ -683,7 +683,7 @@ whatsapp_verify_token = "my-verify"
#[test]
fn load_whatsapp_returns_none_when_missing_access_token() {
let tmp = tempfile::tempdir().unwrap();
let sk = tmp.path().join(".story_kit");
let sk = tmp.path().join(".storkit");
fs::create_dir_all(&sk).unwrap();
fs::write(
sk.join("bot.toml"),
@@ -704,7 +704,7 @@ whatsapp_verify_token = "my-verify"
#[test]
fn load_whatsapp_returns_none_when_missing_verify_token() {
let tmp = tempfile::tempdir().unwrap();
let sk = tmp.path().join(".story_kit");
let sk = tmp.path().join(".storkit");
fs::create_dir_all(&sk).unwrap();
fs::write(
sk.join("bot.toml"),
@@ -727,7 +727,7 @@ whatsapp_access_token = "EAAtoken"
#[test]
fn load_slack_transport_reads_config() {
let tmp = tempfile::tempdir().unwrap();
let sk = tmp.path().join(".story_kit");
let sk = tmp.path().join(".storkit");
fs::create_dir_all(&sk).unwrap();
fs::write(
sk.join("bot.toml"),
@@ -753,7 +753,7 @@ slack_channel_ids = ["C01ABCDEF"]
#[test]
fn load_slack_returns_none_when_missing_bot_token() {
let tmp = tempfile::tempdir().unwrap();
let sk = tmp.path().join(".story_kit");
let sk = tmp.path().join(".storkit");
fs::create_dir_all(&sk).unwrap();
fs::write(
sk.join("bot.toml"),
@@ -774,7 +774,7 @@ slack_channel_ids = ["C01ABCDEF"]
#[test]
fn load_slack_returns_none_when_missing_signing_secret() {
let tmp = tempfile::tempdir().unwrap();
let sk = tmp.path().join(".story_kit");
let sk = tmp.path().join(".storkit");
fs::create_dir_all(&sk).unwrap();
fs::write(
sk.join("bot.toml"),
@@ -795,7 +795,7 @@ slack_channel_ids = ["C01ABCDEF"]
#[test]
fn load_slack_returns_none_when_missing_channel_ids() {
let tmp = tempfile::tempdir().unwrap();
let sk = tmp.path().join(".story_kit");
let sk = tmp.path().join(".storkit");
fs::create_dir_all(&sk).unwrap();
fs::write(
sk.join("bot.toml"),

View File

@@ -71,7 +71,7 @@ pub async fn handle_delete(
// Find the story file across all pipeline stages.
let mut found: Option<(std::path::PathBuf, &str, String)> = None; // (path, stage, story_id)
'outer: for stage in STAGES {
let dir = project_root.join(".story_kit").join("work").join(stage);
let dir = project_root.join(".storkit").join("work").join(stage);
if !dir.exists() {
continue;
}
@@ -152,7 +152,7 @@ pub async fn handle_delete(
// Commit the deletion to git.
let commit_msg = format!("story-kit: delete {story_id}");
let work_rel = std::path::PathBuf::from(".story_kit").join("work");
let work_rel = std::path::PathBuf::from(".storkit").join("work");
let _ = std::process::Command::new("git")
.args(["add", "-A"])
.arg(&work_rel)
@@ -296,7 +296,7 @@ mod tests {
let project_root = tmp.path();
// Create the pipeline directories.
for stage in &["1_backlog", "2_current", "3_qa", "4_merge", "5_done", "6_archived"] {
std::fs::create_dir_all(project_root.join(".story_kit").join("work").join(stage))
std::fs::create_dir_all(project_root.join(".storkit").join("work").join(stage))
.unwrap();
}
let agents = std::sync::Arc::new(crate::agents::AgentPool::new_test(3000));
@@ -329,7 +329,7 @@ mod tests {
.output()
.unwrap();
let backlog_dir = project_root.join(".story_kit").join("work").join("1_backlog");
let backlog_dir = project_root.join(".storkit").join("work").join("1_backlog");
std::fs::create_dir_all(&backlog_dir).unwrap();
let story_path = backlog_dir.join("42_story_some_feature.md");
std::fs::write(

View File

@@ -1,6 +1,6 @@
//! Matrix bot integration for Story Kit.
//!
//! When a `.story_kit/bot.toml` file is present with `enabled = true`, the
//! When a `.storkit/bot.toml` file is present with `enabled = true`, the
//! server spawns a Matrix bot that:
//!
//! 1. Connects to the configured homeserver and joins the configured room.
@@ -37,7 +37,7 @@ use tokio::sync::{Mutex as TokioMutex, broadcast, mpsc};
/// Attempt to start the Matrix bot.
///
/// Reads the bot configuration from `.story_kit/bot.toml`. If the file is
/// Reads the bot configuration from `.storkit/bot.toml`. If the file is
/// absent or `enabled = false`, this function returns immediately without
/// spawning anything — the server continues normally.
///

View File

@@ -52,7 +52,7 @@ pub fn extract_story_number(item_id: &str) -> Option<&str> {
/// Returns `None` if the file doesn't exist or has no parseable name.
pub fn read_story_name(project_root: &Path, stage: &str, item_id: &str) -> Option<String> {
let path = project_root
.join(".story_kit")
.join(".storkit")
.join("work")
.join(stage)
.join(format!("{item_id}.md"));
@@ -243,7 +243,7 @@ mod tests {
let tmp = tempfile::tempdir().unwrap();
let stage_dir = tmp
.path()
.join(".story_kit")
.join(".storkit")
.join("work")
.join("2_current");
std::fs::create_dir_all(&stage_dir).unwrap();
@@ -269,7 +269,7 @@ mod tests {
let tmp = tempfile::tempdir().unwrap();
let stage_dir = tmp
.path()
.join(".story_kit")
.join(".storkit")
.join("work")
.join("2_current");
std::fs::create_dir_all(&stage_dir).unwrap();

View File

@@ -90,7 +90,7 @@ pub async fn handle_start(
// Find the story file across all pipeline stages.
let mut found: Option<(std::path::PathBuf, String)> = None; // (path, story_id)
'outer: for stage in STAGES {
let dir = project_root.join(".story_kit").join("work").join(stage);
let dir = project_root.join(".storkit").join("work").join(stage);
if !dir.exists() {
continue;
}
@@ -301,7 +301,7 @@ mod tests {
let tmp = tempfile::tempdir().unwrap();
let project_root = tmp.path();
for stage in &["1_backlog", "2_current", "3_qa", "4_merge", "5_done", "6_archived"] {
std::fs::create_dir_all(project_root.join(".story_kit").join("work").join(stage))
std::fs::create_dir_all(project_root.join(".storkit").join("work").join(stage))
.unwrap();
}
let agents = std::sync::Arc::new(crate::agents::AgentPool::new_test(3000));