huskies: rename project from storkit to huskies

Rename all references from storkit to huskies across the codebase:
- .storkit/ directory → .huskies/
- Binary name, Cargo package name, Docker image references
- Server code, frontend code, config files, scripts
- Fix script/test to build frontend before cargo clippy/test
  so merge worktrees have frontend/dist available for RustEmbed

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Timmy
2026-04-03 16:12:52 +01:00
parent a7035b6ba7
commit 2d8ccb3eb6
572 changed files with 1340 additions and 1220 deletions
+22 -22
View File
@@ -22,19 +22,19 @@ use std::path::Path;
/// Return the filesystem path (relative to `project_root`) for a step's output.
///
/// Returns `None` for `Scaffold` since that step has no single output file — it
/// creates the full `.storkit/` directory structure and is handled by
/// `storkit init` before the server starts.
/// creates the full `.huskies/` directory structure and is handled by
/// `huskies init` before the server starts.
pub(crate) fn step_output_path(project_root: &Path, step: WizardStep) -> Option<std::path::PathBuf> {
match step {
WizardStep::Context => Some(
project_root
.join(".storkit")
.join(".huskies")
.join("specs")
.join("00_CONTEXT.md"),
),
WizardStep::Stack => Some(
project_root
.join(".storkit")
.join(".huskies")
.join("specs")
.join("tech")
.join("STACK.md"),
@@ -99,7 +99,7 @@ fn step_slug(step: WizardStep) -> String {
pub(super) fn tool_wizard_status(ctx: &AppContext) -> Result<String, String> {
let root = ctx.state.get_project_root()?;
let state =
WizardState::load(&root).ok_or("No wizard active. Run `storkit init` to begin setup.")?;
WizardState::load(&root).ok_or("No wizard active. Run `huskies init` to begin setup.")?;
Ok(format_wizard_state(&state))
}
@@ -161,7 +161,7 @@ pub(crate) fn is_bare_project(project_root: &Path) -> bool {
.filter_map(|e| e.ok())
.map(|e| e.file_name().to_string_lossy().to_string())
.collect();
// A bare project only has storkit scaffolding and no real code
// A bare project only has huskies scaffolding and no real code
names.iter().all(|n| {
n.starts_with('.')
|| n == "CLAUDE.md"
@@ -182,13 +182,13 @@ pub(crate) fn generation_hint(step: WizardStep, project_root: &Path) -> String {
if bare {
"This is a bare project with no existing code. Ask the user what they want \
to build — the project's purpose, goals, target users, and key features. \
Then generate `.storkit/specs/00_CONTEXT.md` from their answers covering:\n\
Then generate `.huskies/specs/00_CONTEXT.md` from their answers covering:\n\
- High-level goal of the project\n\
- Core features\n\
- Domain concepts and entities\n\
- Glossary of abbreviations and technical terms".to_string()
} else {
"Read the project source tree and generate a `.storkit/specs/00_CONTEXT.md` describing:\n\
"Read the project source tree and generate a `.huskies/specs/00_CONTEXT.md` describing:\n\
- High-level goal of the project\n\
- Core features\n\
- Domain concepts and entities\n\
@@ -198,14 +198,14 @@ pub(crate) fn generation_hint(step: WizardStep, project_root: &Path) -> String {
WizardStep::Stack => {
if bare {
"This is a bare project with no existing code. Ask the user what language, \
frameworks, and tools they plan to use. Then generate `.storkit/specs/tech/STACK.md` \
frameworks, and tools they plan to use. Then generate `.huskies/specs/tech/STACK.md` \
from their answers covering:\n\
- Language, frameworks, and runtimes\n\
- Coding standards and linting rules\n\
- Quality gates (commands that must pass before merging)\n\
- Approved libraries and their purpose".to_string()
} else {
"Read the project source tree and generate a `.storkit/specs/tech/STACK.md` describing:\n\
"Read the project source tree and generate a `.huskies/specs/tech/STACK.md` describing:\n\
- Language, frameworks, and runtimes\n\
- Coding standards and linting rules\n\
- Quality gates (commands that must pass before merging)\n\
@@ -262,7 +262,7 @@ pub(crate) fn generation_hint(step: WizardStep, project_root: &Path) -> String {
"Generate a `script/test_coverage` shell script (#!/usr/bin/env bash, set -euo pipefail) that generates a test coverage report (e.g. `cargo llvm-cov nextest` or `npm run coverage`).".to_string()
}
}
WizardStep::Scaffold => "Scaffold step is handled automatically by `storkit init`.".to_string(),
WizardStep::Scaffold => "Scaffold step is handled automatically by `huskies init`.".to_string(),
}
}
@@ -391,7 +391,7 @@ mod tests {
fn setup(dir: &TempDir) -> AppContext {
let root = dir.path().to_path_buf();
std::fs::create_dir_all(root.join(".storkit")).unwrap();
std::fs::create_dir_all(root.join(".huskies")).unwrap();
WizardState::init_if_missing(&root);
AppContext::new_test(root)
}
@@ -408,7 +408,7 @@ mod tests {
#[test]
fn wizard_status_no_wizard_returns_error() {
let dir = TempDir::new().unwrap();
std::fs::create_dir_all(dir.path().join(".storkit")).unwrap();
std::fs::create_dir_all(dir.path().join(".huskies")).unwrap();
let ctx = AppContext::new_test(dir.path().to_path_buf());
assert!(tool_wizard_status(&ctx).is_err());
}
@@ -453,7 +453,7 @@ mod tests {
// File should now exist.
let context_path = dir
.path()
.join(".storkit")
.join(".huskies")
.join("specs")
.join("00_CONTEXT.md");
assert!(context_path.exists());
@@ -472,7 +472,7 @@ mod tests {
let dir = TempDir::new().unwrap();
let ctx = setup(&dir);
// Pre-create the specs directory and file.
let specs_dir = dir.path().join(".storkit").join("specs");
let specs_dir = dir.path().join(".huskies").join("specs");
std::fs::create_dir_all(&specs_dir).unwrap();
let context_path = specs_dir.join("00_CONTEXT.md");
std::fs::write(&context_path, "original content").unwrap();
@@ -550,7 +550,7 @@ mod tests {
#[test]
fn is_bare_project_detects_scaffold_only_dir() {
let dir = TempDir::new().unwrap();
std::fs::create_dir_all(dir.path().join(".storkit")).unwrap();
std::fs::create_dir_all(dir.path().join(".huskies")).unwrap();
std::fs::write(dir.path().join("CLAUDE.md"), "# Claude").unwrap();
std::fs::write(dir.path().join("README.md"), "# Readme").unwrap();
std::fs::create_dir_all(dir.path().join("script")).unwrap();
@@ -560,7 +560,7 @@ mod tests {
#[test]
fn is_bare_project_false_when_source_files_exist() {
let dir = TempDir::new().unwrap();
std::fs::create_dir_all(dir.path().join(".storkit")).unwrap();
std::fs::create_dir_all(dir.path().join(".huskies")).unwrap();
std::fs::write(dir.path().join("Cargo.toml"), "[package]").unwrap();
assert!(!is_bare_project(dir.path()));
}
@@ -576,7 +576,7 @@ mod tests {
fn generation_hint_bare_context_asks_user() {
let dir = TempDir::new().unwrap();
// Bare project — only scaffolding
std::fs::create_dir_all(dir.path().join(".storkit")).unwrap();
std::fs::create_dir_all(dir.path().join(".huskies")).unwrap();
let hint = generation_hint(WizardStep::Context, dir.path());
assert!(hint.contains("bare project"));
assert!(hint.contains("Ask the user"));
@@ -585,7 +585,7 @@ mod tests {
#[test]
fn generation_hint_bare_stack_asks_user() {
let dir = TempDir::new().unwrap();
std::fs::create_dir_all(dir.path().join(".storkit")).unwrap();
std::fs::create_dir_all(dir.path().join(".huskies")).unwrap();
let hint = generation_hint(WizardStep::Stack, dir.path());
assert!(hint.contains("bare project"));
assert!(hint.contains("Ask the user"));
@@ -594,7 +594,7 @@ mod tests {
#[test]
fn generation_hint_bare_test_script_references_stack() {
let dir = TempDir::new().unwrap();
std::fs::create_dir_all(dir.path().join(".storkit")).unwrap();
std::fs::create_dir_all(dir.path().join(".huskies")).unwrap();
let hint = generation_hint(WizardStep::TestScript, dir.path());
assert!(hint.contains("bare project"));
assert!(hint.contains("STACK.md"));
@@ -603,7 +603,7 @@ mod tests {
#[test]
fn generation_hint_bare_release_script_references_stack() {
let dir = TempDir::new().unwrap();
std::fs::create_dir_all(dir.path().join(".storkit")).unwrap();
std::fs::create_dir_all(dir.path().join(".huskies")).unwrap();
let hint = generation_hint(WizardStep::ReleaseScript, dir.path());
assert!(hint.contains("bare project"));
assert!(hint.contains("STACK.md"));
@@ -612,7 +612,7 @@ mod tests {
#[test]
fn generation_hint_bare_test_coverage_references_stack() {
let dir = TempDir::new().unwrap();
std::fs::create_dir_all(dir.path().join(".storkit")).unwrap();
std::fs::create_dir_all(dir.path().join(".huskies")).unwrap();
let hint = generation_hint(WizardStep::TestCoverage, dir.path());
assert!(hint.contains("bare project"));
assert!(hint.contains("STACK.md"));